diff --git a/helm-overrides/gke-toolshed-prd-usc1/external-secrets/custom-values.yaml b/helm-overrides/gke-toolshed-prd-usc1/external-secrets/custom-values.yaml new file mode 100644 index 0000000..bd9f0cc --- /dev/null +++ b/helm-overrides/gke-toolshed-prd-usc1/external-secrets/custom-values.yaml @@ -0,0 +1,42 @@ +external-secrets: + # Same as the homelab's, which carries nothing cluster-specific: the + # controller is configured entirely by the ClusterSecretStore and + # ExternalSecret objects in devops-infra-argo-config-gcp, not by values. + # + # This is the piece every credential in the cluster hangs off — Harbor, + # Jenkins, Grafana and the pipeline all read their secrets from Vault + # through it, so it comes up before any of them. + # + # Two things must exist in Vault before the first ExternalSecret can sync, + # and neither is declarative: the KV v2 engine at secret/, and the + # Kubernetes auth method with a role bound to this controller's service + # account. Until then ExternalSecrets stay in a retry loop rather than + # failing outright. + # + # installCRDs defaults to true — kept, as on a fresh cluster there are no + # existing SecretStore/ExternalSecret CRs whose schema it could clobber. + # + # All three components default to unbounded resources; trimmed here for + # the same reason as everything else in this repo. + resources: + requests: + cpu: 25m + memory: 32Mi + limits: + memory: 128Mi + + webhook: + resources: + requests: + cpu: 25m + memory: 32Mi + limits: + memory: 64Mi + + certController: + resources: + requests: + cpu: 25m + memory: 32Mi + limits: + memory: 64Mi diff --git a/helm-overrides/gke-toolshed-prd-usc1/grafana/custom-values.yaml b/helm-overrides/gke-toolshed-prd-usc1/grafana/custom-values.yaml new file mode 100644 index 0000000..7f1e51a --- /dev/null +++ b/helm-overrides/gke-toolshed-prd-usc1/grafana/custom-values.yaml @@ -0,0 +1,272 @@ +grafana: + # From Vault via ExternalSecret (devops-infra-argo-config/secretstores/ + # grafana-admin-credentials.yaml), same pattern as gitea/harbor/jenkins + # admin credentials elsewhere in this project — never a plaintext + # adminPassword in this file. + admin: + existingSecret: grafana-admin-credentials + userKey: username + passwordKey: password + + persistence: + # 1Gi, not the chart's 10Gi default: this holds dashboards, folders and + # Grafana's own sqlite state, not metric data — VictoriaMetrics keeps + # that. Unlike the homelab's local-path, standard-rwo can be expanded + # later if that ever proves tight. + enabled: true + storageClassName: standard-rwo + size: 1Gi + + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 384Mi + + # Provisioned at boot, not clicked through in the UI — the same reason + # every other credential/config in this project is committed rather + # than set by hand: it survives a pod restart and a fresh install gets + # it automatically. VictoriaMetrics speaks Prometheus's own query API, + # so `type: prometheus` here is correct even though the URL is VM's — + # see this repo's victoria-metrics-single chart for why. + datasources: + datasources.yaml: + apiVersion: 1 + datasources: + - name: VictoriaMetrics + # Fixed uid, not left to auto-generate — the provisioned + # dashboard below references this datasource by uid, and an + # auto-generated one would only exist after Grafana's first + # boot, too late for a dashboard provisioned in the same boot. + uid: victoriametrics + type: prometheus + access: proxy + url: http://victoria-metrics-single-server.monitoring.svc.cluster.local:8428 + isDefault: true + + # Dashboard provisioning. Provisioned rather than built by hand in the + # UI for the same reason the datasource above is: it survives a pod + # restart (this deployment has no persistent Grafana database beyond + # the 1Gi PVC, and even with one, a fresh install should not start + # with an empty dashboard list) and a `git diff` shows what changed. + dashboardProviders: + dashboardproviders.yaml: + apiVersion: 1 + providers: + - name: default + orgId: 1 + folder: "" + type: file + disableDeletion: false + editable: true + options: + path: /var/lib/grafana/dashboards/default + + # "Homelab Overview" — total Envoy/Contour RPS, per-namespace CPU and + # memory (the $namespace template variable filters every relevant + # panel), cluster-wide utilization against actual node capacity, and a + # total-resources row (cores/memory/pods/disk). Envoy and node-exporter + # metrics both required their own vmagent scrape job — see + # helm-overrides/.../vmagent/custom-values.yaml for why neither was + # reachable through the chart's own defaults in this cluster. + # + # Every panel except "Disk free" was run against the live deployment + # (vmui, over Tailscale) before being written in here — RPS, per- + # namespace CPU/memory, machine_cpu_cores/machine_memory_bytes all + # returned real data. "Disk free" depends on the node-exporter scrape + # job added alongside this same change, which had not been live yet to + # verify against — worth checking once this actually deploys, same as + # everything else in this repo that gets a `helm template` check but + # cannot get a live one before the first sync. + dashboards: + default: + homelab: + json: | + { + "title": "Homelab Overview", + "uid": "homelab-overview", + "schemaVersion": 39, + "editable": true, + "timezone": "browser", + "time": { "from": "now-1h", "to": "now" }, + "refresh": "30s", + "templating": { + "list": [ + { + "name": "namespace", + "type": "query", + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "query": "label_values(container_memory_working_set_bytes{container!=\"\", container!=\"POD\"}, namespace)", + "refresh": 2, + "multi": true, + "includeAll": true, + "current": { "selected": true, "text": "All", "value": "$__all" } + } + ] + }, + "panels": [ + { "type": "row", "title": "Ingress (Envoy / Contour)", "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, "id": 100 }, + + { + "type": "stat", "title": "Total RPS", "id": 1, + "gridPos": { "h": 6, "w": 6, "x": 0, "y": 1 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ "expr": "sum(rate(envoy_http_downstream_rq_total{namespace=\"projectcontour\"}[5m]))", "legendFormat": "rps" }], + "fieldConfig": { "defaults": { "unit": "reqps", "decimals": 2 }, "overrides": [] }, + "options": { "reduceOptions": { "calcs": ["lastNotNull"] }, "graphMode": "area" } + }, + { + "type": "stat", "title": "Active downstream connections", "id": 2, + "gridPos": { "h": 6, "w": 6, "x": 6, "y": 1 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ "expr": "sum(envoy_http_downstream_cx_active{namespace=\"projectcontour\"})", "legendFormat": "connections" }], + "fieldConfig": { "defaults": { "unit": "short" }, "overrides": [] } + }, + { + "type": "timeseries", "title": "Requests by response class", "id": 3, + "gridPos": { "h": 6, "w": 12, "x": 12, "y": 1 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ + "expr": "sum by (envoy_response_code_class) (rate(envoy_http_downstream_rq_xx{namespace=\"projectcontour\"}[5m]))", + "legendFormat": "{{envoy_response_code_class}}xx" + }], + "fieldConfig": { "defaults": { "unit": "reqps" }, "overrides": [] }, + "options": { "legend": { "displayMode": "list", "placement": "bottom" } } + }, + + { "type": "row", "title": "Service level (by namespace)", "gridPos": { "h": 1, "w": 24, "x": 0, "y": 7 }, "id": 101 }, + + { + "type": "timeseries", "title": "CPU usage by namespace", "id": 10, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ + "expr": "sum by (namespace) (rate(container_cpu_usage_seconds_total{namespace=~\"$namespace\", container!=\"\", container!=\"POD\"}[5m]))", + "legendFormat": "{{namespace}}" + }], + "fieldConfig": { "defaults": { "unit": "short", "custom": { "fillOpacity": 10, "stacking": { "mode": "normal" } } }, "overrides": [] }, + "options": { "legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max"] } } + }, + { + "type": "timeseries", "title": "Memory usage by namespace", "id": 11, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 8 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ + "expr": "sum by (namespace) (container_memory_working_set_bytes{namespace=~\"$namespace\", container!=\"\", container!=\"POD\"})", + "legendFormat": "{{namespace}}" + }], + "fieldConfig": { "defaults": { "unit": "bytes", "custom": { "fillOpacity": 10, "stacking": { "mode": "normal" } } }, "overrides": [] }, + "options": { "legend": { "displayMode": "table", "placement": "right", "calcs": ["mean", "max"] } } + }, + { + "type": "table", "title": "Current usage per namespace", "id": 12, + "gridPos": { "h": 8, "w": 24, "x": 0, "y": 16 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [ + { "expr": "sum by (namespace) (rate(container_cpu_usage_seconds_total{namespace=~\"$namespace\", container!=\"\", container!=\"POD\"}[5m]))", "format": "table", "instant": true, "refId": "A" }, + { "expr": "sum by (namespace) (container_memory_working_set_bytes{namespace=~\"$namespace\", container!=\"\", container!=\"POD\"})", "format": "table", "instant": true, "refId": "B" }, + { "expr": "count by (namespace) (count by (namespace, pod) (container_memory_working_set_bytes{namespace=~\"$namespace\", container!=\"\", container!=\"POD\"}))", "format": "table", "instant": true, "refId": "C" } + ], + "transformations": [ + { "id": "merge", "options": {} }, + { "id": "organize", "options": { + "excludeByName": { "Time": true, "Time 1": true, "Time 2": true, "Time 3": true }, + "renameByName": { "Value #A": "CPU (cores)", "Value #B": "Memory", "Value #C": "Pods" } + } } + ], + "fieldConfig": { "defaults": {}, "overrides": [ + { "matcher": { "id": "byName", "options": "Memory" }, "properties": [{ "id": "unit", "value": "bytes" }] }, + { "matcher": { "id": "byName", "options": "CPU (cores)" }, "properties": [{ "id": "unit", "value": "short" }, { "id": "decimals", "value": 3 }] } + ] } + }, + + { "type": "row", "title": "Cluster utilization", "gridPos": { "h": 1, "w": 24, "x": 0, "y": 24 }, "id": 102 }, + + { + "type": "gauge", "title": "CPU utilization", "id": 20, + "gridPos": { "h": 7, "w": 6, "x": 0, "y": 25 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ "expr": "100 * sum(rate(container_cpu_usage_seconds_total{container!=\"\", container!=\"POD\"}[5m])) / sum(machine_cpu_cores)" }], + "fieldConfig": { "defaults": { "unit": "percent", "min": 0, "max": 100, + "thresholds": { "mode": "absolute", "steps": [ + { "color": "green", "value": null }, { "color": "yellow", "value": 70 }, { "color": "red", "value": 90 } + ] } }, "overrides": [] } + }, + { + "type": "gauge", "title": "Memory utilization", "id": 21, + "gridPos": { "h": 7, "w": 6, "x": 6, "y": 25 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ "expr": "100 * sum(container_memory_working_set_bytes{container!=\"\", container!=\"POD\"}) / sum(machine_memory_bytes)" }], + "fieldConfig": { "defaults": { "unit": "percent", "min": 0, "max": 100, + "thresholds": { "mode": "absolute", "steps": [ + { "color": "green", "value": null }, { "color": "yellow", "value": 70 }, { "color": "red", "value": 90 } + ] } }, "overrides": [] } + }, + { + "type": "timeseries", "title": "Cluster CPU utilization over time", "id": 22, + "gridPos": { "h": 7, "w": 12, "x": 12, "y": 25 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [ + { "expr": "100 * sum(rate(container_cpu_usage_seconds_total{container!=\"\", container!=\"POD\"}[5m])) / sum(machine_cpu_cores)", "legendFormat": "CPU %" }, + { "expr": "100 * sum(container_memory_working_set_bytes{container!=\"\", container!=\"POD\"}) / sum(machine_memory_bytes)", "legendFormat": "Memory %" } + ], + "fieldConfig": { "defaults": { "unit": "percent", "min": 0 }, "overrides": [] } + }, + + { "type": "row", "title": "Total resources", "gridPos": { "h": 1, "w": 24, "x": 0, "y": 32 }, "id": 103 }, + + { + "type": "stat", "title": "Node CPU capacity", "id": 30, + "gridPos": { "h": 5, "w": 4, "x": 0, "y": 33 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ "expr": "max(machine_cpu_cores)" }], + "fieldConfig": { "defaults": { "unit": "short", "displayName": "cores" }, "overrides": [] } + }, + { + "type": "stat", "title": "Node memory capacity", "id": 31, + "gridPos": { "h": 5, "w": 4, "x": 4, "y": 33 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ "expr": "max(machine_memory_bytes)" }], + "fieldConfig": { "defaults": { "unit": "bytes" }, "overrides": [] } + }, + { + "type": "stat", "title": "CPU used (cluster)", "id": 32, + "gridPos": { "h": 5, "w": 4, "x": 8, "y": 33 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ "expr": "sum(rate(container_cpu_usage_seconds_total{container!=\"\", container!=\"POD\"}[5m]))" }], + "fieldConfig": { "defaults": { "unit": "short", "displayName": "cores", "decimals": 2 }, "overrides": [] } + }, + { + "type": "stat", "title": "Memory used (cluster)", "id": 33, + "gridPos": { "h": 5, "w": 4, "x": 12, "y": 33 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ "expr": "sum(container_memory_working_set_bytes{container!=\"\", container!=\"POD\"})" }], + "fieldConfig": { "defaults": { "unit": "bytes" }, "overrides": [] } + }, + { + "type": "stat", "title": "Running pods", "id": 34, + "gridPos": { "h": 5, "w": 4, "x": 16, "y": 33 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ "expr": "count(count by (namespace, pod) (container_memory_working_set_bytes{container!=\"\", container!=\"POD\"}))" }], + "fieldConfig": { "defaults": { "unit": "short" }, "overrides": [] } + }, + { + "type": "stat", "title": "Disk free (root)", "id": 35, + "gridPos": { "h": 5, "w": 4, "x": 20, "y": 33 }, + "datasource": { "type": "prometheus", "uid": "victoriametrics" }, + "targets": [{ "expr": "node_filesystem_avail_bytes{mountpoint=\"/\"}" }], + "fieldConfig": { "defaults": { "unit": "bytes", + "thresholds": { "mode": "absolute", "steps": [ + { "color": "red", "value": null }, { "color": "yellow", "value": 5000000000 }, { "color": "green", "value": 15000000000 } + ] } }, "overrides": [] } + } + ] + } + + ingress: + enabled: true + ingressClassName: contour + path: / + hosts: + - grafana.35.238.248.203.nip.io diff --git a/helm-overrides/gke-toolshed-prd-usc1/harbor/custom-values.yaml b/helm-overrides/gke-toolshed-prd-usc1/harbor/custom-values.yaml new file mode 100644 index 0000000..6f452c5 --- /dev/null +++ b/helm-overrides/gke-toolshed-prd-usc1/harbor/custom-values.yaml @@ -0,0 +1,132 @@ +harbor: + # GKE counterpart of helm-overrides/k8s-admin-prd-ase1/harbor, same chart + # (1.19.1), with one fundamental difference: this Harbor is served over + # real TLS, and it has to be. + # + # The homelab runs Harbor on plain HTTP and works around containerd's + # refusal to pull from an insecure registry by hand-editing + # /etc/containerd/certs.d//hosts.toml on the node. GKE nodes are + # managed and replaced, so that edit cannot survive. Instead the node pool + # is told, at creation, to trust a private CA for exactly this hostname, + # fetching it from Secret Manager (see toolshed-gke-infra's gke-cluster + # module). cert-manager signs Harbor's certificate from that same CA. + # + # Let's Encrypt is not an option: nip.io is not on the public suffix list, + # so every *.nip.io certificate on the internet shares one rate limit. + # A private CA is fine for image pulls, which is what matters, but + # browsers will warn on the Harbor UI. That is expected, not a fault. + expose: + type: ingress + tls: + enabled: true + # secret, not the chart's "auto": auto generates its own self-signed + # certificate, which the nodes have no reason to trust. This one is + # signed by the CA they were told to trust. + certSource: secret + secret: + secretName: harbor-tls + ingress: + hosts: + core: "harbor.35.238.248.203.nip.io" + className: contour + annotations: + # cert-manager's ingress-shim watches for this and creates the + # Certificate itself, writing the result into the secret named + # above. Nothing here ever touches a Certificate resource directly. + # The issuer is defined in devops-infra-argo-config-gcp's + # extra-manifests/registry-ca-clusterissuer.yaml. + cert-manager.io/cluster-issuer: registry-ca-issuer + + # https, matching the ingress above. Harbor hands this URL to docker + # clients in its own API responses, so a mismatch here breaks pushes in + # ways that look like registry errors rather than configuration. + externalURL: "https://harbor.35.238.248.203.nip.io" + + # From Vault through External Secrets — see + # secretstores/harbor-admin-credentials.yaml and Vault path + # secret/harbor/admin. + existingSecretAdminPassword: harbor-admin-credentials + existingSecretAdminPasswordKey: HARBOR_ADMIN_PASSWORD + + # The one genuinely optional component. Harbor's database and redis are + # its own required internal state, not add-ons. + trivy: + enabled: false + + persistence: + enabled: true + # Keeps the PVCs if the release is ever uninstalled: these hold the + # actual images. + resourcePolicy: "keep" + persistentVolumeClaim: + registry: + storageClass: standard-rwo + size: 5Gi + jobservice: + jobLog: + storageClass: standard-rwo + size: 1Gi + database: + storageClass: standard-rwo + size: 1Gi + redis: + storageClass: standard-rwo + size: 1Gi + + portal: + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 256Mi + + core: + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + memory: 512Mi + + jobservice: + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 256Mi + + registry: + registry: + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + memory: 256Mi + controller: + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + memory: 128Mi + + database: + internal: + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + memory: 512Mi + + redis: + internal: + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + memory: 128Mi diff --git a/helm-overrides/gke-toolshed-prd-usc1/jenkins/custom-values.yaml b/helm-overrides/gke-toolshed-prd-usc1/jenkins/custom-values.yaml new file mode 100644 index 0000000..60519a2 --- /dev/null +++ b/helm-overrides/gke-toolshed-prd-usc1/jenkins/custom-values.yaml @@ -0,0 +1,78 @@ +jenkins: + # GKE counterpart of helm-overrides/k8s-admin-prd-ase1/jenkins, same chart + # (5.8.58). Dynamic Kubernetes build agents, so idle cost is the + # controller alone. + # + # Every plugin pin below is carried over deliberately, not copied + # blindly — each one fixes a failure that is not obvious from its symptom. + # See the homelab file for the full history. + + controller: + image: + # The chart's own default plugin list requires core >= 2.504.3, while + # its default image tag is 2.504.2. An upstream inconsistency in the + # chart, not our configuration: bumping core is the fix, since the + # plugins involved (kubernetes above all) are what dynamic agents + # depend on. + tag: "2.504.3-jdk21" + + # Helm replaces lists wholesale rather than merging, so this is the + # chart's full default list with one version corrected, plus two + # additions — not a hand-picked subset. + installPlugins: + # Pinned as a pair. kubernetes needs kubernetes-client-api >= + # 7.3.1-256.v788a_0b_787114; left unpinned it resolves to an older + # version at image-build time and every agent launch dies with + # NoSuchMethodError while constructing the client. The pods start + # fine, so it presents as builds hanging forever at "Still waiting to + # schedule task" rather than as a plugin problem. + - kubernetes:4437.v3a_18554d3f32 + - kubernetes-client-api:7.3.1-256.v788a_0b_787114 + - workflow-aggregator:608.v67378e9d3db_1 + - git:5.7.0 + # kubernetes/git/credentials need this version, though the chart's + # own default list pins an older one. Same class of upstream + # inconsistency as the image tag. + - configuration-as-code:2006.v001a_2ca_6b_574 + # Not in the chart's default list at all — provides readYaml, which + # the shared library's loadConfig stage uses to parse each repo's + # config.yaml. + - pipeline-utility-steps:3.810.va_7672d206740 + + resources: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 500m + memory: 1Gi + + admin: + # From Vault through External Secrets, never a plaintext password + # here. Requires secretstores/jenkins-admin-credentials.yaml to have + # synced, which in turn requires the Vault path secret/jenkins/admin. + existingSecret: jenkins-admin-credentials + userKey: jenkins-admin-user + passwordKey: jenkins-admin-password + + ingress: + enabled: true + hostName: "jenkins.35.238.248.203.nip.io" + ingressClassName: contour + # The homelab also enables secondaryingress, purely to serve its + # Tailscale hostname — this chart's primary ingress supports only one + # host. There is one hostname here, so it stays off. + + agent: + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + + persistence: + enabled: true + storageClass: standard-rwo + size: 5Gi diff --git a/helm-overrides/gke-toolshed-prd-usc1/node-exporter/custom-values.yaml b/helm-overrides/gke-toolshed-prd-usc1/node-exporter/custom-values.yaml new file mode 100644 index 0000000..296d711 --- /dev/null +++ b/helm-overrides/gke-toolshed-prd-usc1/node-exporter/custom-values.yaml @@ -0,0 +1,17 @@ +prometheus-node-exporter: + # Unchanged from the homelab's — nothing here is cluster-specific. One + # DaemonSet pod per node on hostNetwork; three pods here rather than one. + # + # Host-level metrics are independent of which TSDB stores them, which is + # why this is its own release rather than a subchart of anything. + resources: + requests: + cpu: 20m + memory: 32Mi + limits: + memory: 64Mi + + # The chart's Service carries prometheus.io/scrape by default. vmagent + # also targets these pods directly by container port, because that + # annotation-based path found nothing in the homelab — see the vmagent + # values for the detail. diff --git a/helm-overrides/gke-toolshed-prd-usc1/postgresql/custom-values.yaml b/helm-overrides/gke-toolshed-prd-usc1/postgresql/custom-values.yaml new file mode 100644 index 0000000..3f2a6f4 --- /dev/null +++ b/helm-overrides/gke-toolshed-prd-usc1/postgresql/custom-values.yaml @@ -0,0 +1,45 @@ +# PostgreSQL for toolshed's control plane, on GKE. +# +# Its own namespace rather than toolshed's, so it is addressed over cluster +# DNS like any other platform component and outlives its first consumer: +# +# postgresql.postgres.svc.cluster.local:5432 +# +# Hand-written chart, not Bitnami's: that registry has been unstable, and +# PostgreSQL ships no official chart. +# +# Credentials come from Vault through External Secrets — see +# secretstores/toolshed-postgres-credentials.yaml. The Secret must exist +# before this pod starts; without it the pod sits in +# CreateContainerConfigError, which does not explain itself. + +fullnameOverride: postgresql + +image: + repository: postgres + tag: "16-alpine" + pullPolicy: IfNotPresent + +existingSecret: postgresql-credentials +database: toolshed + +persistence: + enabled: true + storageClass: standard-rwo + size: 5Gi + +config: + # Kept at the homelab's deliberately small values even though this + # cluster has room to spare: for a handful of control-plane tables it + # makes no measurable difference, and matching the homelab keeps one + # fewer variable between the two deployments. Raise it if a real query + # workload ever shows up here. + sharedBuffers: 32MB + maxConnections: "50" + +resources: + requests: + cpu: 50m + memory: 64Mi + limits: + memory: 256Mi diff --git a/helm-overrides/gke-toolshed-prd-usc1/redis/custom-values.yaml b/helm-overrides/gke-toolshed-prd-usc1/redis/custom-values.yaml new file mode 100644 index 0000000..aa24fc0 --- /dev/null +++ b/helm-overrides/gke-toolshed-prd-usc1/redis/custom-values.yaml @@ -0,0 +1,45 @@ +# Redis backing toolshed's managed cache add-on, on GKE. +# +# Its own namespace, same reasoning as postgresql: +# +# redis.redis.svc.cluster.local:6379 +# +# Hand-written chart, not Bitnami's, for the same reason as postgresql. +# +# Read the chart's own values.yaml before changing anything about +# authentication. The absence of requirepass is deliberate and +# security-relevant, not an oversight: access is defined by an ACL file +# seeded from Vault through External Secrets +# (secretstores/toolshed-redis-credentials.yaml). The Secret must exist +# before this pod starts, or the init container cannot seed that file. + +fullnameOverride: redis + +image: + repository: redis + tag: "7-alpine" + pullPolicy: IfNotPresent + +existingSecret: redis-credentials + +persistence: + enabled: true + storageClass: standard-rwo + # Holds the ACL file and nothing else worth keeping, since snapshotting + # is off. 1Gi is already far more than needed. + size: 1Gi + +config: + # Kept at the homelab's value. It was chosen there to fit an 8GB node + # under pressure, and while this cluster has room, a bigger cache buys + # nothing for a handful of small internal tools. + maxmemory: 48mb + maxmemoryPolicy: allkeys-lru + save: "" + +resources: + requests: + cpu: 25m + memory: 32Mi + limits: + memory: 96Mi diff --git a/helm-overrides/gke-toolshed-prd-usc1/victoria-metrics-single/custom-values.yaml b/helm-overrides/gke-toolshed-prd-usc1/victoria-metrics-single/custom-values.yaml new file mode 100644 index 0000000..1329505 --- /dev/null +++ b/helm-overrides/gke-toolshed-prd-usc1/victoria-metrics-single/custom-values.yaml @@ -0,0 +1,31 @@ +victoria-metrics-single: + server: + # 7 days rather than the chart's month: this cluster exists to prove a + # pipeline, and every extra day is disk against the project's 250GB SSD + # quota, which every standard-rwo volume in the cluster shares. + retentionPeriod: "7d" + + persistentVolume: + storageClassName: standard-rwo + # VictoriaMetrics' compression is why it replaced Prometheus here; + # this cluster's metric volume at 7 days fits well inside 3Gi. Unlike + # the homelab's local-path, this class can be expanded later. + size: 3Gi + + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 512Mi + + # vmui, VictoriaMetrics' built-in query UI, on the same pod and port — + # ad-hoc PromQL only, no saved dashboards; Grafana is the real UI. Free + # to expose, since it is not a separate component. + ingress: + enabled: true + ingressClassName: contour + hosts: + - name: vm.35.238.248.203.nip.io + path: ["/"] + port: http diff --git a/helm-overrides/gke-toolshed-prd-usc1/vmagent/custom-values.yaml b/helm-overrides/gke-toolshed-prd-usc1/vmagent/custom-values.yaml new file mode 100644 index 0000000..b7daedf --- /dev/null +++ b/helm-overrides/gke-toolshed-prd-usc1/vmagent/custom-values.yaml @@ -0,0 +1,70 @@ +victoria-metrics-agent: + # Unchanged from the homelab's, deliberately: everything here is + # addressed by cluster-internal Service DNS and namespace, none of which + # differs on GKE. + # + # The write path is what wires the two components together; the chart + # names do not imply it on their own. + remoteWrite: + - url: http://victoria-metrics-single-server.monitoring.svc.cluster.local:8428/api/v1/write + + # config.scrape_configs stays at the chart's default, which already + # covers kubelet's cAdvisor endpoint and the prometheus.io/scrape + # annotation convention. extraScrapeConfigs is concatenated onto it + # rather than replacing it. + # + # Both jobs below exist because annotation-based discovery did not reach + # these targets in the homelab. Contour's Envoy carries no scrape + # annotation at all, and node-exporter's annotation sits on its Service, + # where the endpointslice discovery path found nothing. Targeting each by + # its fixed container port sidesteps both problems and is no less + # correct. Worth re-checking on this cluster rather than assuming the + # same gaps: if the defaults do find them here, these jobs are harmless + # duplicates, not errors. + extraScrapeConfigs: + - job_name: contour-envoy + kubernetes_sd_configs: + - role: pod + namespaces: + names: ["projectcontour"] + relabel_configs: + # 8002 is the official Contour chart's fixed metrics port for + # Envoy. /stats/prometheus is Envoy's own admin endpoint, not + # anything Contour-specific. + - action: keep + source_labels: [__meta_kubernetes_pod_container_port_number] + regex: "8002" + - target_label: __metrics_path__ + replacement: /stats/prometheus + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_pod_name] + target_label: pod + - source_labels: [__meta_kubernetes_namespace] + target_label: namespace + - source_labels: [__meta_kubernetes_pod_node_name] + target_label: node + - job_name: node-exporter + kubernetes_sd_configs: + - role: pod + namespaces: + names: ["monitoring"] + relabel_configs: + - action: keep + source_labels: [__meta_kubernetes_pod_container_port_number] + regex: "9100" + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_pod_name] + target_label: pod + - source_labels: [__meta_kubernetes_namespace] + target_label: namespace + - source_labels: [__meta_kubernetes_pod_node_name] + target_label: node + + resources: + requests: + cpu: 25m + memory: 64Mi + limits: + memory: 192Mi