diff --git a/services/platform/cert-manager/applications/scaleway/chart.vendor.yaml b/services/platform/cert-manager/applications/scaleway/chart.vendor.yaml index ac88fb5..8230f3c 100644 --- a/services/platform/cert-manager/applications/scaleway/chart.vendor.yaml +++ b/services/platform/cert-manager/applications/scaleway/chart.vendor.yaml @@ -28,6 +28,52 @@ spec: gatewayAPI: enabled: true + # Chart ships none of these by default (resources: {} everywhere) — + # confirmed live 2026-08-11: with every platform chart requestless, + # the scheduler has nothing to balance nodes on and Cluster + # Autoscaler never sees a reason to use the pool's 3rd node, so a + # fresh scaleway-homelab boot piles ~30 pods onto one 2-node's worth + # of real RAM and OOMs. + # + # Sized from `kubectl top pods -n cert-manager` on the live cluster + # (2026-08-11), not chart-doc guesses — a first pass anchored on + # generic recommendations left the controller request at half its + # observed usage. cainjector gets the most headroom: it watches every + # CRD/webhook/APIService in the cluster to inject CA bundles, so its + # memory scales with total CRD count and spikes hardest during the + # initial sync right after cert-manager's own CRDs land. + resources: + requests: + cpu: 10m + memory: 96Mi + limits: + cpu: 200m + memory: 256Mi + webhook: + resources: + requests: + cpu: 10m + memory: 32Mi + limits: + cpu: 100m + memory: 64Mi + cainjector: + resources: + requests: + cpu: 10m + memory: 96Mi + limits: + cpu: 200m + memory: 320Mi + startupapicheck: + resources: + requests: + cpu: 10m + memory: 32Mi + limits: + cpu: 100m + memory: 64Mi + destination: server: https://kubernetes.default.svc namespace: cert-manager diff --git a/services/platform/cert-manager/applications/scaleway/webhook.vendor.yaml b/services/platform/cert-manager/applications/scaleway/webhook.vendor.yaml index dc015c4..29569a5 100644 --- a/services/platform/cert-manager/applications/scaleway/webhook.vendor.yaml +++ b/services/platform/cert-manager/applications/scaleway/webhook.vendor.yaml @@ -24,6 +24,18 @@ spec: secret: externalSecretName: scaleway-dns-credentials + # See cert-manager/applications/scaleway/chart.vendor.yaml's comment + # on the same fix — this chart also ships resources: {} by default. + # Sized from `kubectl top pods` (2026-08-11): a first pass guessed + # 16Mi here against an actual observed ~45Mi, nearly 3x under. + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 100m + memory: 128Mi + destination: server: https://kubernetes.default.svc namespace: cert-manager diff --git a/services/platform/external-dns/applications/scaleway/chart.vendor.yaml b/services/platform/external-dns/applications/scaleway/chart.vendor.yaml index 74ba829..d156ca6 100644 --- a/services/platform/external-dns/applications/scaleway/chart.vendor.yaml +++ b/services/platform/external-dns/applications/scaleway/chart.vendor.yaml @@ -45,6 +45,18 @@ spec: registry: txt txtOwnerId: scaleway + # See cert-manager/applications/scaleway/chart.vendor.yaml's comment + # on the same fix — this chart also ships resources: {} by default, + # and this pod is one that was confirmed live 2026-08-11 getting + # node-pressure Evicted during a fresh cluster boot. + resources: + requests: + cpu: 10m + memory: 32Mi + limits: + cpu: 50m + memory: 64Mi + destination: server: https://kubernetes.default.svc namespace: external-dns diff --git a/services/platform/external-secrets/applications/scaleway/chart.vendor.yaml b/services/platform/external-secrets/applications/scaleway/chart.vendor.yaml index e1db44c..24914e3 100644 --- a/services/platform/external-secrets/applications/scaleway/chart.vendor.yaml +++ b/services/platform/external-secrets/applications/scaleway/chart.vendor.yaml @@ -12,6 +12,40 @@ spec: repoURL: https://external-secrets.io chart: external-secrets targetRevision: 2.6.0 + helm: + values: | + # Chart ships resources: {} by default for every component. See + # cert-manager/applications/scaleway/chart.vendor.yaml's comment on + # the same fix — without this, the scheduler can't balance the + # cluster's 2 nodes and Cluster Autoscaler never gets a reason to + # use the pool's 3rd node. + # + # Sized from `kubectl top pods -n external-secrets` on the live + # cluster (2026-08-11), not chart-doc guesses — a first pass left + # every one of these requests below observed usage. + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 100m + memory: 128Mi + webhook: + resources: + requests: + cpu: 10m + memory: 48Mi + limits: + cpu: 50m + memory: 96Mi + certController: + resources: + requests: + cpu: 10m + memory: 64Mi + limits: + cpu: 50m + memory: 128Mi destination: server: https://kubernetes.default.svc diff --git a/services/platform/monitoring/applications/scaleway/chart.vendor.yaml b/services/platform/monitoring/applications/scaleway/chart.vendor.yaml index 846ba1d..23cf848 100644 --- a/services/platform/monitoring/applications/scaleway/chart.vendor.yaml +++ b/services/platform/monitoring/applications/scaleway/chart.vendor.yaml @@ -148,7 +148,21 @@ spec: requests: storage: 5Gi + # DaemonSet pods are pinned to one specific node each (nodeAffinity + # on that node's own name) — unlike a Deployment pod, they can't + # just get scheduled on the other node if this one is full, and + # Cluster Autoscaler adding a 3rd node doesn't rescue them either, + # since the pod that needs scheduling is bound to a node that + # already exists. Confirmed live 2026-08-11: node-exporter sat + # Pending for minutes on a node running at ~99% requested memory, + # because at default priority (0) it couldn't preempt anything to + # make room for itself. Every other DaemonSet on this cluster + # (cilium, csi-node, konnectivity-agent, kube-proxy — all + # Scaleway-managed) already runs system-node-critical/ + # system-cluster-critical, so node-exporter reuses the same + # built-in tier rather than inventing a dedicated one. prometheus-node-exporter: + priorityClassName: system-node-critical resources: requests: cpu: 20m diff --git a/services/platform/openbao/applications/scaleway/chart.vendor.yaml b/services/platform/openbao/applications/scaleway/chart.vendor.yaml index afdc1f5..71900d2 100644 --- a/services/platform/openbao/applications/scaleway/chart.vendor.yaml +++ b/services/platform/openbao/applications/scaleway/chart.vendor.yaml @@ -47,10 +47,46 @@ spec: kms_key_id = "367e11de-75f4-4df0-a038-b6cf06ae2ead" } + # Chart ships resources: {} by default. See + # cert-manager/applications/scaleway/chart.vendor.yaml's comment on + # the same fix. OpenBao backs every other app's secrets in this + # cluster (including its own snapshotAgent below), so it gets the + # most headroom of anything here — raft compaction and unseal both + # spike above steady-state usage. Request sized from `kubectl top + # pods -n openbao` (2026-08-11, observed 49-62m/113Mi); limit kept + # well above that for the compaction/unseal spikes above. + resources: + requests: + cpu: 50m + memory: 160Mi + limits: + cpu: 500m + memory: 512Mi + + injector: + resources: + requests: + cpu: 10m + memory: 32Mi + limits: + cpu: 100m + memory: 64Mi + snapshotAgent: enabled: true schedule: "0 * * * *" # Every hours, at 0min. - s3CredentialsSecret: "scaleway-s3-credentials" + s3CredentialsSecret: "scaleway-s3-credentials" + # Runs as its own CronJob (not a sidecar in the server pod) — a + # short-lived s3cmd export, so it gets a low request but a limit + # well above it: same "bursty tool, generous limit" reasoning as + # monitoring/applications/scaleway/chart.vendor.yaml's grafana/prometheus comment. + resources: + requests: + cpu: 25m + memory: 32Mi + limits: + cpu: 250m + memory: 256Mi config: s3Host: "s3.fr-par.scw.cloud" s3Bucket: "backup-dev-id" diff --git a/services/platform/velero/applications/scaleway/chart.vendor.yaml b/services/platform/velero/applications/scaleway/chart.vendor.yaml index b936c8d..2c233b1 100644 --- a/services/platform/velero/applications/scaleway/chart.vendor.yaml +++ b/services/platform/velero/applications/scaleway/chart.vendor.yaml @@ -97,6 +97,22 @@ spec: includedResources: - secrets + # Chart ships resources: {} by default (its own commented-out example + # suggests 500m/128Mi request, 1000m/512Mi limit — scaled down here + # since this instance's backup scope is a handful of Secrets, not + # volumes). See cert-manager/applications/scaleway/chart.vendor.yaml's + # comment on the same fix. Request sized from `kubectl top pods -n + # velero` (2026-08-11, observed ~81Mi at idle) — limit stays well + # above that: backup runs (listing/serializing API objects) spike + # above the idle footprint the rest of the time. + resources: + requests: + cpu: 10m + memory: 112Mi + limits: + cpu: 500m + memory: 384Mi + destination: server: https://kubernetes.default.svc namespace: velero diff --git a/services/platform/wireguard/config/templates/deployment.yaml b/services/platform/wireguard/config/templates/deployment.yaml index 2d11daf..717cf4d 100644 --- a/services/platform/wireguard/config/templates/deployment.yaml +++ b/services/platform/wireguard/config/templates/deployment.yaml @@ -45,6 +45,7 @@ spec: printf "\n# %s\n[Peer]\nPublicKey = %s\nAllowedIPs = %s\n" "$name" "$pubkey" "$allowedips" >> /config/wg_confs/wg0.conf done chmod 600 /config/wg_confs/wg0.conf + resources: {{ .Values.resources.renderConf | toYaml | nindent 12 }} volumeMounts: - name: conf-template mountPath: /template @@ -63,6 +64,7 @@ spec: securityContext: capabilities: add: ["NET_ADMIN"] + resources: {{ .Values.resources.wireguard | toYaml | nindent 12 }} env: - name: PUID value: "1000" @@ -97,6 +99,7 @@ spec: set -eu apk add --no-cache socat exec socat TCP-LISTEN:{{ $proxyTarget.port }},fork,reuseaddr TCP:{{ $proxyTarget.target }} + resources: {{ $.Values.resources.proxy | toYaml | nindent 12 }} {{- end }} # Raw TCP passthrough to Envoy Gateway's own real Service — SNI/Host # travel untouched inside the TLS ClientHello, so Envoy does its @@ -124,6 +127,7 @@ spec: socat TCP-LISTEN:443,fork,reuseaddr TCP:${TARGET}:443 & socat TCP-LISTEN:80,fork,reuseaddr TCP:${TARGET}:80 & wait + resources: {{ .Values.resources.proxyGateway | toYaml | nindent 12 }} # Split DNS: answers *.scalepack.fr with this pod's own tunnel # address (server.address, stripped of its CIDR suffix) and # forwards everything else upstream. Peers get this pushed via @@ -144,6 +148,7 @@ spec: --address=/{{ .Values.dnsZone }}/{{ (splitList "/" .Values.server.address) | first }} \ --server=1.1.1.1 --server=8.8.8.8 \ --port=53 + resources: {{ .Values.resources.dns | toYaml | nindent 12 }} volumes: - name: conf-template configMap: diff --git a/services/platform/wireguard/config/values.yaml b/services/platform/wireguard/config/values.yaml index 718fc90..2606979 100644 --- a/services/platform/wireguard/config/values.yaml +++ b/services/platform/wireguard/config/values.yaml @@ -91,3 +91,57 @@ server: # the header comment above; add an entry back if something genuinely needs # a dedicated non-Gateway path. proxyTargets: {} + +# This chart was the one exception that already had explicit per-container +# resources missing entirely (not even a chart default: we own this +# template). Confirmed live 2026-08-11 alongside every other requestless +# platform chart — see cert-manager/applications/scaleway/chart.vendor.yaml's +# comment for the full incident. Every container here is a thin proxy/init +# step, so these all stay small — except where noted below. +# +# dns and proxyGateway both got OOMKilled at their original 32Mi limit +# during a live relaunch (2026-08-11): every container here runs `apk +# add --no-cache ` fresh at startup (nothing's baked into the base +# alpine image), and that package-fetch/install step spikes well above +# what the actual running process needs afterwards — confirmed live for +# proxyGateway specifically, observed at 31Mi against a 32Mi limit right +# after startup. proxyGateway also gets its own tier instead of sharing +# "proxy": it runs on alpine/kubectl (bundles the kubectl binary), a +# heavier base image than the plain alpine the generic per-target proxy +# sidecars use. +resources: + renderConf: + requests: + cpu: 10m + memory: 16Mi + limits: + cpu: 100m + memory: 64Mi + wireguard: + requests: + cpu: 10m + memory: 16Mi + limits: + cpu: 100m + memory: 32Mi + proxy: + requests: + cpu: 5m + memory: 8Mi + limits: + cpu: 50m + memory: 64Mi + proxyGateway: + requests: + cpu: 10m + memory: 32Mi + limits: + cpu: 100m + memory: 96Mi + dns: + requests: + cpu: 5m + memory: 16Mi + limits: + cpu: 50m + memory: 128Mi