From cbc2301b30a0aa68d744e4cae86f746385347714 Mon Sep 17 00:00:00 2001 From: Keith Jackson Date: Sun, 30 Aug 2026 15:13:12 -0500 Subject: [PATCH] docs: reconcile docs/comments with post-upgrade cluster state Text-only cleanup after the upgrade campaign. Updates stale version strings, prose, and comments to the verified current facts; no Kubernetes behavior or version pins changed except the kubectl toolchain bump (below). Verified facts applied: k3s v1.36.4+k3s1, Debian 13 trixie, Cilium 1.20.1 / Gateway API v1.6.1, Longhorn 1.12.1, node RAM 24 GiB, dedicated virtio2 SSD etcd disk per node, Velero chart 12.x / v1.18, Grafana 13.2.0. - Version strings across infra/ and platform/ READMEs + comments - kubectl toolchain 1.31.4 -> 1.36.4 (devcontainer/ci/conformance versions.env; 1.31 vs a 1.36 cluster exceeded the +-1 skew) - Retired-single-apps-Kustomization refs -> apps-wave-0/1/2 + apps-vms with per-wave SOPS decryption (flux/clusters docs + bootstrap.sh) - COMPLETED/historical banners on the three executed plan docs - Resolved TODO(WS-SEC) markers -> Renovate-maintained ranges - Appended dated DECISIONS-LOG entry (2026-08-30) superseding the 2026-08-26 LIVE STATE line Left as revalidation items (not blind-edited): external-snapshotter v8.2.0 vs 1.36, Cilium ext_authz/forward-auth relevance under 1.20.1, conformance ImageVolume feature-gate assertions under 1.36. Co-Authored-By: Claude Opus 4.8 --- DECISIONS-LOG.md | 24 +++++++++++++++++++ bootstrap/flux/README.md | 16 ++++++++----- bootstrap/flux/bootstrap.sh | 9 ++++--- catalog/README.md | 2 +- catalog/render.py | 2 +- ci/versions.env | 2 +- clusters/README.md | 5 ++-- conformance/versions.env | 2 +- docs/plans/cluster-upgrade-plan.md | 7 ++++++ docs/plans/ssd-etcd-execution-runbook.md | 7 ++++++ docs/plans/ssd-etcd-isolation.md | 7 ++++++ infra/PHASE1-STATUS.md | 10 ++++---- infra/README.md | 2 +- infra/ansible/roles/cilium/defaults/main.yml | 5 ++-- .../roles/k3s_server/defaults/main.yml | 2 +- infra/devcontainer/versions.env | 4 ++-- infra/tofu/README.md | 7 +++--- platform/cert-manager/helmrelease.yaml | 2 +- platform/cilium/values.yaml | 4 ++-- platform/cnpg/helmrelease.yaml | 2 +- platform/external-snapshotter/README.md | 7 +++--- .../external-snapshotter/kustomization.yaml | 7 +++--- platform/longhorn/README.md | 2 +- .../monitoring/kube-prometheus-stack.yaml | 4 ++-- platform/velero/README.md | 2 +- 25 files changed, 100 insertions(+), 43 deletions(-) diff --git a/DECISIONS-LOG.md b/DECISIONS-LOG.md index eba32db..fee2c3e 100644 --- a/DECISIONS-LOG.md +++ b/DECISIONS-LOG.md @@ -1150,3 +1150,27 @@ gitignored (agent worktrees were tripping the lint stage's untracked-file scan). Plex uses `/config` → Plex writes the ephemeral layer, is unclaimed, loses config on restart (seerr↔plex connectivity is actually fine — 200 on `/identity`). FIX PENDING operator go (resets Plex, needs re-claim): mount PVC at `/config` + wire `PLEX_CLAIM`. + +--- + +## 2026-08-30 — Upgrade campaign landed: cluster now k3s v1.36.4 / Debian 13 / Cilium 1.20.1 / Longhorn 1.12.1 + +The platform-wide upgrade campaign completed and is live. Verified current state of the dev cluster: + +- **k3s v1.36.4+k3s1** (was v1.31.5+k3s1), 3-server embedded-etcd HA. +- **Debian 13 (trixie)** node OS (was Debian 12 bookworm). +- **Cilium 1.20.1** (was 1.16.5); **Gateway API v1.6.1** (was v1.2.x). +- **Longhorn 1.12.1** (was 1.7.3). +- cert-manager >=1.21; Velero chart 12.x / Velero v1.18; kube-prometheus-stack 88 (operator + v0.93.1, Grafana 13.2.0); kube-vip v1.2.3. +- Node RAM **24 GiB / 24576 MB** (tofu default; earlier docs said 16 GiB). +- Each node now carries a **dedicated virtio2 SSD etcd disk** (`/dev/vdc`, `local-zfs`) isolating + etcd WAL fsync from HDD Longhorn I/O — see `docs/plans/ssd-etcd-isolation.md`. + +**The "LIVE STATE VERIFIED 2026-08-26" line above (k3s v1.31.5) is SUPERSEDED by this entry.** +That older line is retained as historical record — this append is the current source of truth. +Documentation and comments across the repo were reconciled to these facts in the same change; +toolchain kubectl bumped 1.31.4 → 1.36.4 (the 1.31 pin exceeded the ±1 version skew against a 1.36 +cluster). Revalidation items deliberately left open: external-snapshotter v8.2.0 pin vs 1.36, the +Cilium ext_authz/forward-auth workaround relevance under 1.20.1, and the conformance ImageVolume +feature-gate assertions under 1.36. diff --git a/bootstrap/flux/README.md b/bootstrap/flux/README.md index d9f7e45..90465ce 100644 --- a/bootstrap/flux/README.md +++ b/bootstrap/flux/README.md @@ -13,14 +13,16 @@ Spec: [ADR-0004 (Flux)](../../../home-network-k3s/decisions/adr-0004-gitops-flux |---|---| | `bootstrap.sh` | **The single bootstrap entrypoint** the Infra worker's final Ansible play calls. `flux install` → verify `sops-age` Secret → `kubectl apply -k clusters/dev`. | | `patches/platform-sops-decryption.yaml` | Strategic-merge patch enabling `decryption.provider: sops` + `secretRef: sops-age` on the `platform` Kustomization (realises the base TODO). | -| `patches/apps-sops-decryption.yaml` | Same, for the `apps` Kustomization. | +| `patches/apps-sops-decryption.yaml` | Same, for the app-wave Kustomizations. There is **no single `apps` Kustomization** any more — the apps tier is now `apps-wave-0/1/2` + `apps-vms`, and SOPS decryption is layered on **per wave** (each wave Kustomization is patched by name in `clusters/dev`). | | `patches/flux-system-source-url.yaml` | Overrides the `flux-system` GitRepository `url` placeholder with the real bootstrap source (template — fill at bootstrap). | ## Why `flux install` + apply, not `flux bootstrap git` (Phase 1) The reconciliation graph is **already authored** in `clusters/base` (read-only to this worker): -`flux-system.yaml` is the `flux-system` **GitRepository**; `platform.yaml`/`apps.yaml` are the Flux -**Kustomizations**; `clusters/dev` is the overlay that patches `cluster-vars` (R-ENV-02). +`flux-system.yaml` is the `flux-system` **GitRepository**; `platform.yaml`, `platform-config.yaml` +and the app-wave Kustomizations (`apps-wave-0/1/2.yaml` + `apps-vms.yaml` — the single `apps.yaml` +was retired) are the Flux **Kustomizations**; `clusters/dev` is the overlay that patches +`cluster-vars` (R-ENV-02) and layers SOPS decryption onto each Kustomization by name. `flux bootstrap git` **generates and owns its own** `gotk-sync` GitRepository + Kustomization named `flux-system` and commits them into the repo — which would **duplicate/conflict** with the authored @@ -41,8 +43,9 @@ tofu apply → cloud-init → Ansible (k3s + Cilium) [Infra worker, T-1 3. bootstrap/flux/bootstrap.sh # flux install → verify sops-age → apply -k clusters/dev │ ▼ -Flux reconciles: GitRepository(flux-system) → Kustomization(platform) → Kustomization(apps), -with SOPS decryption enabled (patches/) and cluster-vars overlay (R-ENV-02). +Flux reconciles: GitRepository(flux-system) → Kustomization(platform) → Kustomization(platform-config) +→ Kustomization(apps-wave-0 → apps-wave-1 → apps-wave-2) + Kustomization(apps-vms), +with per-Kustomization SOPS decryption enabled (patches/) and cluster-vars overlay (R-ENV-02). ``` ## Interface note — for the Infra worker (T-1.3 Ansible) @@ -72,7 +75,8 @@ patches: - path: ../../bootstrap/flux/patches/apps-sops-decryption.yaml # SOPS on apps ``` -Alternatively the base TODOs in `clusters/base/{platform,apps}.yaml` and the `url` in +Alternatively the base TODOs in `clusters/base/platform.yaml` and each app-wave Kustomization +(`apps-wave-0/1/2.yaml`, `apps-vms.yaml`) and the `url` in `clusters/base/flux-system.yaml` can be filled in directly (same effect) — the clusters owner's call. Either way the `sops-age` `secretRef` name and `flux-system` source name are kept in lockstep with the authored base. diff --git a/bootstrap/flux/bootstrap.sh b/bootstrap/flux/bootstrap.sh index a7a9f57..893b19c 100755 --- a/bootstrap/flux/bootstrap.sh +++ b/bootstrap/flux/bootstrap.sh @@ -25,7 +25,9 @@ # We do NOT use `flux bootstrap git` in Phase 1 because that command commits # and OWNS its own gotk-sync GitRepository+Kustomization named `flux-system`. # Our entrypoints are ALREADY authored in clusters/base (flux-system.yaml = -# the GitRepository; platform.yaml/apps.yaml = the Kustomizations). Letting +# the GitRepository; platform.yaml + platform-config.yaml + the app-wave +# Kustomizations apps-wave-0/1/2.yaml + apps-vms.yaml = the Kustomizations; +# the single apps.yaml was retired). Letting # bootstrap regenerate them would DUPLICATE/conflict. `flux install` + # applying the authored clusters/dev overlay is the reconciling path. # 2. sops-age Secret — the operator installs the age PRIVATE key out-of-band BEFORE reconcile so @@ -33,8 +35,9 @@ # only VERIFIES it exists; it never handles key material. # 3. `kubectl apply -k clusters/dev` — materialises the authored reconciliation graph: # GitRepository `flux-system` (source) -> Kustomization `platform` -> -# Kustomization `apps` (dependsOn platform), with cluster-vars overlay -# (R-ENV-02) and SOPS decryption enabled via the patches in ./patches/. +# `platform-config` -> the app-wave Kustomizations `apps-wave-0/1/2` +# (chained dependsOn) + `apps-vms`, with cluster-vars overlay +# (R-ENV-02) and per-Kustomization SOPS decryption enabled via ./patches/. # # PREREQUISITES the operator/PM resolves before this runs (see ../README.md "Handoff"): # - clusters/base/flux-system.yaml url placeholder is overridden — wire ./patches/flux-system- diff --git a/catalog/README.md b/catalog/README.md index e28b689..4b5912a 100644 --- a/catalog/README.md +++ b/catalog/README.md @@ -10,7 +10,7 @@ policy, egress, TLS, DNS, monitoring, and update policy from it (see [`docs/13-service-catalog.md`](../../home-network-k3s/docs/13-service-catalog.md) (14-service table + SSO/egress/dependency intent). -## Current examples (Phase 0) +## Current examples | File | docs/13 row | exposure | egress | auth | Notes | |---|---|---|---|---|---| | `pihole.yaml` | 6 | internal | internet | forward-auth | admin UI behind oauth2-proxy; config on Longhorn (DR-critical); also platform DNS | diff --git a/catalog/render.py b/catalog/render.py index 67f3947..e6e81d3 100644 --- a/catalog/render.py +++ b/catalog/render.py @@ -464,7 +464,7 @@ def r_gateway_ingress_policy(s: dict): north-south). This CiliumNetworkPolicy is the ADDITIVE, least-privilege allow that opens ONLY the north-south path (docs/09 "Ingress opens north-south only — it does not relax east-west default-deny"): ingress from Cilium's reserved `ingress` identity (the Gateway/ - Ingress Envoy proxy, `reserved:ingress`, numeric identity 8 in Cilium 1.16.5) to ONLY the + Ingress Envoy proxy, `reserved:ingress`, numeric identity 8 in Cilium 1.20.1) to ONLY the exposed service port(s). Everything else stays denied; undeclared ports stay denied. Verified empirically against the cluster: with default-deny in place, Hubble shows the diff --git a/ci/versions.env b/ci/versions.env index e235451..c61155f 100644 --- a/ci/versions.env +++ b/ci/versions.env @@ -18,7 +18,7 @@ CHAINSAW_VERSION="0.2.12" # Lint / manifest tooling YAMLLINT_VERSION="1.35.1" -KUBECTL_VERSION="1.31.4" +KUBECTL_VERSION="1.36.4" YQ_VERSION="4.44.6" # ServiceDefinition JSON-Schema validation (schemas/validate.sh). Pip-installed; diff --git a/clusters/README.md b/clusters/README.md index b72633f..62ca127 100644 --- a/clusters/README.md +++ b/clusters/README.md @@ -29,8 +29,9 @@ clusters/ ## How the overlay model satisfies R-ENV-02 -The base authors the reconciliation graph **once**. `platform.yaml` and `apps.yaml` (Flux -`Kustomization`s) both declare `postBuild.substituteFrom` the `cluster-vars` ConfigMap. Platform and +The base authors the reconciliation graph **once**. `platform.yaml` and the app-wave Kustomizations +(`apps-wave-0/1/2.yaml` — the single `apps.yaml` was retired; `apps-vms.yaml` deliberately omits it, +see below) declare `postBuild.substituteFrom` the `cluster-vars` ConfigMap. Platform and app manifests use `${TOKEN}` placeholders for every value that legitimately differs between environments (issuer, replica counts, storage sizes, retention, node placement). diff --git a/conformance/versions.env b/conformance/versions.env index 31dad42..7e900ae 100644 --- a/conformance/versions.env +++ b/conformance/versions.env @@ -9,7 +9,7 @@ CHAINSAW_VERSION="v0.2.12" CHAINSAW_IMAGE="ghcr.io/kyverno/chainsaw:v0.2.12" # kubectl — used by run.sh for cluster reachability preflight and by probe scripts. -KUBECTL_VERSION="v1.31.4" +KUBECTL_VERSION="v1.36.4" # Kyverno CLI — L0 static/policy gate (owned by T-0.5, referenced here for a single # pinned toolchain view). Not invoked by run.sh yet. diff --git a/docs/plans/cluster-upgrade-plan.md b/docs/plans/cluster-upgrade-plan.md index 2be61f9..94669e1 100644 --- a/docs/plans/cluster-upgrade-plan.md +++ b/docs/plans/cluster-upgrade-plan.md @@ -1,5 +1,12 @@ # Cluster upgrade plan — k3s 1.31.5 → 1.36.x + node OS (dev cluster) +> ## ✅ COMPLETED / historical — executed 2026-08-30, see git log +> +> **This plan has been carried out.** The dev cluster now runs **k3s v1.36.4+k3s1** on **Debian 13 +> (trixie)** with Cilium 1.20.1 and Longhorn 1.12.1. The steps, gates, and rollbacks below are +> retained as the record of how the upgrade was performed — do NOT re-execute them against the live +> cluster. Current state is tracked in `infra/PHASE1-STATUS.md` and the 2026-08-30 DECISIONS-LOG entry. + **Scope:** the `home-network-k3s-impl` **dev** cluster (`k3s-dev-1/2/3` @ 192.168.1.50-52), 3× HA embedded-etcd servers behind a kube-vip VIP, Debian 12 bookworm. Upgrade Kubernetes/k3s from **v1.31.5+k3s1 → v1.36.x+k3s1** (five minors) and the node OS (Debian 12 → 13), with an diff --git a/docs/plans/ssd-etcd-execution-runbook.md b/docs/plans/ssd-etcd-execution-runbook.md index 212ad3d..84238b2 100644 --- a/docs/plans/ssd-etcd-execution-runbook.md +++ b/docs/plans/ssd-etcd-execution-runbook.md @@ -1,5 +1,12 @@ # Phase 2 execution runbook — SSD-backed etcd migration (interactive/manual) +> ## ✅ COMPLETED / historical — executed 2026-08-30, see git log +> +> **This runbook has been executed.** Every k3s node's etcd now lives on its dedicated SSD `virtio2` +> disk. The command sequence below is retained as the record of how the migration was performed — do +> NOT re-run it against the live cluster. Current state is tracked in `infra/PHASE1-STATUS.md` and the +> 2026-08-30 DECISIONS-LOG entry. + Companion to `ssd-etcd-isolation.md`. This is the **exact command sequence** to migrate each k3s node's etcd onto its dedicated SSD `virtio2` disk. It must be run where live-infra mutations are permitted — an **interactive `claude` session** (default permission mode, which diff --git a/docs/plans/ssd-etcd-isolation.md b/docs/plans/ssd-etcd-isolation.md index cfeef0b..6aa8e04 100644 --- a/docs/plans/ssd-etcd-isolation.md +++ b/docs/plans/ssd-etcd-isolation.md @@ -1,5 +1,12 @@ # SSD-backed etcd isolation for the k3s dev cluster +> ## ✅ COMPLETED / historical — executed 2026-08-30, see git log +> +> **This proposal was approved and carried out.** Each node now has a dedicated `virtio2` SSD etcd +> disk (`/dev/vdc`, `local-zfs`) hosting the etcd data dir. The **Status: PROPOSAL** line below and +> the sizing/RAM figures are the original investigation record — retained for the reasoning, not as a +> live to-do. Current state is tracked in `infra/PHASE1-STATUS.md` and the 2026-08-30 DECISIONS-LOG entry. + **Status:** PROPOSAL — awaiting user approval. No changes have been made. **Author:** investigation agent (read-only), 2026-08-29 **Problem:** Longhorn replica-rebuild I/O storms on the HDD-backed VM disks starve diff --git a/infra/PHASE1-STATUS.md b/infra/PHASE1-STATUS.md index 1acb930..1a98ffc 100644 --- a/infra/PHASE1-STATUS.md +++ b/infra/PHASE1-STATUS.md @@ -1,6 +1,6 @@ # Dev cluster — current state & reconnect guide -**Last verified: 2026-08-26.** Phase 1 is **complete and long since exited**; the cluster has been +**Last verified: 2026-08-30.** Phase 1 is **complete and long since exited**; the cluster has been running the full platform (phases 2–6) for some time. This doc is how a session — human or agent — reconnects to it and re-establishes the toolchain. @@ -15,12 +15,12 @@ reconnects to it and re-establishes the toolchain. | | | |---|---| | Substrate | Proxmox VE host, node `proxmox`, disks on the `Storage` ZFS datastore, bridge `vmbr0` | -| Nodes | `k3s-dev-1/2/3` at `192.168.1.50 / .51 / .52` — 6 vCPU, 16 GiB, Debian 12 (bookworm) | -| k3s | **v1.31.5+k3s1**, 3 servers, embedded etcd (HA); no flannel / kube-proxy / Traefik | -| CNI | Cilium 1.16.5 (kube-proxy replacement, L2 announcements, egress gateway) | +| Nodes | `k3s-dev-1/2/3` at `192.168.1.50 / .51 / .52` — 6 vCPU, 24 GiB, Debian 13 (trixie) | +| k3s | **v1.36.4+k3s1**, 3 servers, embedded etcd (HA); no flannel / kube-proxy / Traefik | +| CNI | Cilium 1.20.1 (kube-proxy replacement, L2 announcements, egress gateway) | | kube-API | kube-vip VIP **`192.168.1.49:6443`**, tls-san'd on the serving cert | | Ingress VIP | **`192.168.1.53`** (shared Gateway). Pool `192.168.1.53–.60` for LB VIPs; UniFi holds `.54` | -| Storage | Longhorn 1.7.3 — classes `longhorn` (default), `longhorn-static`, `longhorn-vm` (RWX/Block, migratable), `longhorn-scratch`. `bulk` (NFS CSI) is a **non-provisioning stub** pending OQ-2 | +| Storage | Longhorn 1.12.1 — classes `longhorn` (default), `longhorn-static`, `longhorn-vm` (RWX/Block, migratable), `longhorn-scratch`. `bulk` (NFS CSI) is a **non-provisioning stub** pending OQ-2 | | Nested virt | `cpu_type = host` → real KVM in-guest; KubeVirt + CDI run on it | Everything above is provisioned by IaC: [`tofu/`](tofu/) creates the VMs, diff --git a/infra/README.md b/infra/README.md index 0e729bc..80d2e23 100644 --- a/infra/README.md +++ b/infra/README.md @@ -20,7 +20,7 @@ Proxmox LAN and are reached across a pfSense NAT: | | | |---|---| -| Nodes | `k3s-dev-1/2/3` at `192.168.1.50/.51/.52` — 6 vCPU, 16 GiB, Debian 12, k3s v1.31.5 | +| Nodes | `k3s-dev-1/2/3` at `192.168.1.50/.51/.52` — 6 vCPU, 24 GiB, Debian 13, k3s v1.36.4 | | kube-API | kube-vip VIP `192.168.1.49:6443`, reached from the workstation via NAT `192.168.2.50:6443` | | Node SSH | pfSense NAT `192.168.2.102:2250/2251/2252` → node `:22` (Ansible only) | | Ingress VIP | `192.168.1.53` (Cilium L2, shared Gateway); `.53–.60` reserved for LB VIPs | diff --git a/infra/ansible/roles/cilium/defaults/main.yml b/infra/ansible/roles/cilium/defaults/main.yml index 1ddc8f3..02a7d1d 100644 --- a/infra/ansible/roles/cilium/defaults/main.yml +++ b/infra/ansible/roles/cilium/defaults/main.yml @@ -4,14 +4,15 @@ # HelmRelease adopts config afterward. The parity-critical values # (kubeProxyReplacement, k8sServiceHost/Port) are templated from k3s_api_host. -# Pin inside the platform/cilium HelmRelease window (>=1.16.0 <1.17.0). +# Exact pin — MUST equal the platform/cilium HelmRelease chart.spec.version (1.20.1, an +# exact pin, not a range). Renovate bumps both together. cilium_version: "1.20.1" cilium_chart_repo_name: "cilium" cilium_chart_repo_url: "https://helm.cilium.io/" cilium_namespace: "kube-system" # Gateway API CRDs (standard channel) must exist BEFORE Cilium with gatewayAPI.enabled. -# Cilium 1.16 targets Gateway API v1.2.x. +# Cilium 1.20.1 targets Gateway API v1.6.1. gateway_api_version: "v1.6.1" gateway_api_crd_urls: - "https://github.com/kubernetes-sigs/gateway-api/releases/download/{{ gateway_api_version }}/standard-install.yaml" diff --git a/infra/ansible/roles/k3s_server/defaults/main.yml b/infra/ansible/roles/k3s_server/defaults/main.yml index dd3036d..462280c 100644 --- a/infra/ansible/roles/k3s_server/defaults/main.yml +++ b/infra/ansible/roles/k3s_server/defaults/main.yml @@ -1,7 +1,7 @@ --- # k3s_server role defaults (ADR-0001). -# Best-effort version pin (kept near the ci/versions kubectl 1.31.x line). Bump +# Best-effort version pin (kept near the ci/versions kubectl 1.36.x line). Bump # deliberately — a version change is a code change. Empty string => latest stable. k3s_version: "v1.36.4+k3s1" diff --git a/infra/devcontainer/versions.env b/infra/devcontainer/versions.env index c63efa8..9eef922 100644 --- a/infra/devcontainer/versions.env +++ b/infra/devcontainer/versions.env @@ -11,8 +11,8 @@ OPENTOFU_VERSION=1.9.0 AGE_VERSION=1.2.1 SOPS_VERSION=3.9.4 FLUX_VERSION=2.4.0 -# Aligned with ci/versions.env (KUBECTL=1.31.4) and the k3s 1.31.5 cluster. -KUBECTL_VERSION=1.31.4 +# Aligned with ci/versions.env (KUBECTL=1.36.4) and the k3s 1.36.4 cluster. +KUBECTL_VERSION=1.36.4 HELM_VERSION=3.16.0 # --- Conformance test toolchain (match ci/versions.env) ---------------------- diff --git a/infra/tofu/README.md b/infra/tofu/README.md index 3d2c20c..30ffbd8 100644 --- a/infra/tofu/README.md +++ b/infra/tofu/README.md @@ -5,7 +5,7 @@ Provisions the "Create" lifecycle stage (docs/02): 3 cloud-init'd VMs on the (Migrated from the old memory-constrained libvirt host; provider is now `bpg/proxmox`.) **APPLIED AND LIVE.** These three VMs are the running dev cluster — `k3s-dev-1/2/3`, k3s -v1.31.5, carrying the whole platform. Treat any `tofu apply/destroy` here as an operation on +v1.36.4, carrying the whole platform. Treat any `tofu apply/destroy` here as an operation on production-for-dev, and note the state file caveat below. Serves **R-ENV-01/02**, **R-PLAT-01**, ADR-0001 (k3s substrate). @@ -19,9 +19,10 @@ Serves **R-ENV-01/02**, **R-PLAT-01**, ADR-0001 (k3s substrate). | Image/snippet datastore | `local` (dir; content = iso + **snippets**) | | Bridge | `vmbr0` (no VLAN) | | Nodes | `k3s-dev-1/2/3` at `192.168.1.50/.51/.52`, gw `192.168.1.1`, DNS `192.168.1.18` | -| Per node | 6 vCPU, 16 GiB RAM, **cpu type `host`** (nested virt for KubeVirt — real KVM confirmed in-guest) | -| OS disk | **64 GiB**, virtio0 (`/dev/vda`, boot), imported from the Debian 12 cloud image | +| Per node | 6 vCPU, 24 GiB RAM, **cpu type `host`** (nested virt for KubeVirt — real KVM confirmed in-guest) | +| OS disk | **64 GiB**, virtio0 (`/dev/vda`, boot), imported from the Debian 13 cloud image | | Data disk | **128 GiB**, virtio1 (`/dev/vdb`) → `/var/lib/longhorn` (mounted by cloud-init; Longhorn reports ~125 GiB usable per node) | +| etcd disk | **16 GiB SSD**, virtio2 (`/dev/vdc`) on the `local-zfs` SSD datastore → etcd data dir (`/var/lib/rancher/k3s/server/db`); isolates etcd WAL fsync from the HDD Longhorn I/O (docs/plans/ssd-etcd-isolation.md) | | Cloud-init | native `initialization` (static IP + DNS) + user-data **snippet** for the baseline | | Reserved | `192.168.1.53–.60` for Cilium L2 ingress VIPs (surfaced in outputs). In use: `.53` shared Gateway, `.54` UniFi | diff --git a/platform/cert-manager/helmrelease.yaml b/platform/cert-manager/helmrelease.yaml index 0855afc..bafe554 100644 --- a/platform/cert-manager/helmrelease.yaml +++ b/platform/cert-manager/helmrelease.yaml @@ -10,7 +10,7 @@ spec: chart: spec: chart: cert-manager - version: ">=1.21.0 <1.22.0" # TODO(WS-SEC): pin at bring-up; Renovate maintains + version: ">=1.21.0 <1.22.0" # Renovate-maintained range (bring-up is past; team uses ranges, not exact pins) sourceRef: kind: HelmRepository name: jetstack diff --git a/platform/cilium/values.yaml b/platform/cilium/values.yaml index b6f03e4..ba0c469 100644 --- a/platform/cilium/values.yaml +++ b/platform/cilium/values.yaml @@ -6,9 +6,9 @@ # # SOURCE OF TRUTH (all [parity] fields MUST equal these): # infra/ansible/roles/cilium/templates/cilium-values.yaml.j2 -# infra/ansible/roles/cilium/defaults/main.yml (cilium_version: 1.16.5, k3s_api_host/port) +# infra/ansible/roles/cilium/defaults/main.yml (cilium_version: 1.20.1, k3s_api_host/port) # -# chart version (helmrelease.yaml chart.spec.version): 1.16.5 # [parity] = cilium_version +# chart version (helmrelease.yaml chart.spec.version): 1.20.1 # [parity] = cilium_version # [parity] k3s kube-proxy disabled → Cilium replaces it (ADR-0001/0002) kubeProxyReplacement: true diff --git a/platform/cnpg/helmrelease.yaml b/platform/cnpg/helmrelease.yaml index ec1f17e..1c39767 100644 --- a/platform/cnpg/helmrelease.yaml +++ b/platform/cnpg/helmrelease.yaml @@ -13,7 +13,7 @@ spec: chart: spec: chart: cloudnative-pg - version: ">=0.22.0 <1.0.0" # TODO(WS-SEC): pin at bring-up; Renovate maintains + version: ">=0.22.0 <1.0.0" # Renovate-maintained range (bring-up is past; team uses ranges, not exact pins) sourceRef: kind: HelmRepository name: cloudnative-pg diff --git a/platform/external-snapshotter/README.md b/platform/external-snapshotter/README.md index b972c7b..1819543 100644 --- a/platform/external-snapshotter/README.md +++ b/platform/external-snapshotter/README.md @@ -26,6 +26,7 @@ Neither k3s nor the Longhorn chart ships this. It is a prerequisite for: ## Version Pinned to **v8.2.0** (Renovate-maintained). The v8.x line aligned to Kubernetes 1.31 at -v8.1.0; this cluster is k3s v1.31.5. The snapshot-controller image is re-pinned to the same -tag via the kustomization `images` transformer (the upstream setup manifest lags on the image -tag). +v8.1.0; this cluster is now k3s v1.36.4, so the pin should be **re-checked for 1.36** (a newer +external-snapshotter line may be the version-matched choice) — do not treat v8.2.0 as verified +against 1.36 yet. The snapshot-controller image is re-pinned to the same tag via the kustomization +`images` transformer (the upstream setup manifest lags on the image tag). diff --git a/platform/external-snapshotter/kustomization.yaml b/platform/external-snapshotter/kustomization.yaml index 12050b0..a11b9f5 100644 --- a/platform/external-snapshotter/kustomization.yaml +++ b/platform/external-snapshotter/kustomization.yaml @@ -18,9 +18,10 @@ # CRDs (the Longhorn VolumeSnapshotClass, item 2) live in platform-config so the CRDs exist first. # # VERSION (Renovate-maintained): external-snapshotter v8.2.0. -# * The v8.x line updated its Kubernetes deps to 1.31 at v8.1.0 (this cluster is k3s v1.31.5), -# so v8.2.x is the conservative, version-matched choice — newer than the 1.31 alignment, -# older than the v8.4/v8.5 churn. +# * The v8.x line updated its Kubernetes deps to 1.31 at v8.1.0. This cluster is now k3s v1.36.4, +# so the v8.2.0 pin is NO LONGER verified against the running Kubernetes version — RE-CHECK it +# for 1.36 (a newer external-snapshotter line may be the version-matched choice). Pin left as-is +# pending that revalidation. # * snapshot.storage.k8s.io CRDs are served at v1 (GA) — driver.longhorn.io speaks v1, so # Longhorn CSI snapshots + CDI snapshot-clone work against these CRDs. # * The upstream setup manifest pins the controller image to an older v8.0.x tag; the `images` diff --git a/platform/longhorn/README.md b/platform/longhorn/README.md index e2550e1..e7afd8d 100644 --- a/platform/longhorn/README.md +++ b/platform/longhorn/README.md @@ -63,7 +63,7 @@ media on the replicated tier, or app DBs on the bulk tier.** - **OQ-2 (human):** decide the `bulk`-tier backing (NAS/NFS host + share, vs dedicated large disk). Until answered, the `bulk` class is a non-functional placeholder (`server`/`share` = REPLACE-ME). Blocks `bulk` finalize; does **not** block the core platform (docs/04). -- **Version pin (WS-STORAGE):** `>=1.7.0 <1.8.0` is a range; pin exactly at bring-up, Renovate +- **Version pin (WS-STORAGE):** `>=1.12.0 <1.13.0` is a range; pin exactly at bring-up, Renovate maintains. - **Phase 4 (WS-STORAGE):** off-cluster backup target via `defaultSettings.backupTarget` + SOPS-encrypted credential secret, wired alongside `platform/velero/` (R-STATE-03). diff --git a/platform/monitoring/kube-prometheus-stack.yaml b/platform/monitoring/kube-prometheus-stack.yaml index a83bcb6..4aea9c0 100644 --- a/platform/monitoring/kube-prometheus-stack.yaml +++ b/platform/monitoring/kube-prometheus-stack.yaml @@ -172,9 +172,9 @@ spec: resources: requests: cpu: 50m - memory: 256Mi # Grafana 12.x (kps 88) baseline is well above Grafana 11.x (kps 65) + memory: 256Mi # Grafana 13.x (image 13.2.0, kps 88) baseline is well above Grafana 11.x (kps 65) limits: - memory: 512Mi # 256Mi OOMKilled (exit 137) Grafana 12.x during apiserver/unified-storage + memory: 512Mi # 256Mi OOMKilled (exit 137) Grafana 13.x during apiserver/unified-storage # startup — the silent SIGKILL that made the whole 65->88 Helm upgrade # time out (the new Grafana pod never went Ready). 512Mi holds. # --- Keycloak native-OIDC SSO (ADR-0014, deliverable #4 SSO proof) --- diff --git a/platform/velero/README.md b/platform/velero/README.md index 2b62a16..431d347 100644 --- a/platform/velero/README.md +++ b/platform/velero/README.md @@ -9,7 +9,7 @@ ## What this is (LIVE) -Flux `HelmRelease` (Velero chart 8.x / Velero 1.15.x) wired to the on-Proxmox **MinIO** S3 target: +Flux `HelmRelease` (Velero chart 12.x / Velero 1.18.x) wired to the on-Proxmox **MinIO** S3 target: - **Endpoint:** `http://192.168.1.9:9000` (plain HTTP, **path-style**, region `us-east-1` placeholder) - **BucketStorageLocation `default`:** provider `aws`, bucket `velero`, `s3ForcePathStyle=true`.