Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
88 lines
6.4 KiB
Markdown
88 lines
6.4 KiB
Markdown
# platform/
|
|
|
|
Cluster-wide **platform services**, Flux-managed (**R-PLAT-01**, **R-GITOPS-01/02/03**). Reconciled
|
|
by the `platform` Flux Kustomization defined in [`clusters/base/platform.yaml`](../clusters/base/platform.yaml),
|
|
**before** `apps/`.
|
|
|
|
Governing spec: [`docs/05-gitops-and-delivery.md`](../../home-network-k3s/docs/05-gitops-and-delivery.md),
|
|
[`docs/01-architecture-overview.md`](../../home-network-k3s/docs/01-architecture-overview.md).
|
|
|
|
> **Phase 0 scaffolding only.** Every component here is a structurally-correct **stub** — a Flux
|
|
> HelmRelease and/or Kustomization with a values placeholder, a README citing the governing ADR/spec,
|
|
> and TODOs for the phase that fills it in. **No cluster exists**; nothing reconciles yet. Do not add
|
|
> working config, secrets, or provisioning under Phase 0 (spec `AGENTS.md` §1/§5/§6, `roadmap/phases.md`).
|
|
|
|
## Reconciliation flow (how a change lands)
|
|
|
|
```
|
|
git (source of truth)
|
|
│ operator PR → CI (lint · schema · Kyverno L0 · Chainsaw) → merge to tracked branch
|
|
▼
|
|
Flux GitRepository (clusters/base/flux-system.yaml)
|
|
▼
|
|
Flux Kustomization "platform" → ./platform (this dir) ── substituteFrom cluster-vars ──┐
|
|
│ prune=true (drift correction, R-GITOPS-03) · wait=true │ R-ENV-02
|
|
▼ │
|
|
Flux Kustomization "apps" → ./apps (dependsOn platform) ─ substituteFrom cluster-vars ──┘
|
|
```
|
|
|
|
Git is authoritative; the cluster conforms to git and drift is auto-corrected (R-GITOPS-01/03).
|
|
Manual `kubectl apply` of platform state is prohibited (spec `AGENTS.md` §5).
|
|
|
|
## The dev ↔ prod overlay model (R-ENV-02)
|
|
|
|
Platform manifests are authored **once**. Every value that legitimately differs between environments
|
|
is a `${TOKEN}` resolved from the `cluster-vars` ConfigMap via Flux `postBuild.substituteFrom`. The
|
|
`clusters/dev` and `clusters/prod` overlays differ **only** by the values they patch into
|
|
`cluster-vars` (issuer, replica counts, storage sizes, retention). See
|
|
[`clusters/README.md`](../clusters/README.md). Base manifests are **never forked per environment**.
|
|
|
|
## Components (one directory each)
|
|
|
|
| Dir | Component | Governing ADR / spec | Serves |
|
|
|---|---|---|---|
|
|
| `cilium/` | CNI + kube-proxy replacement + Gateway API + Egress Gateway + Hubble | [ADR-0002](../../home-network-k3s/decisions/adr-0002-cni-cilium.md), docs/03 | R-NET-* |
|
|
| `longhorn/` | Replicated block storage; 3-replica default StorageClass + bulk tier | [ADR-0003](../../home-network-k3s/decisions/adr-0003-storage-longhorn.md), docs/04 | R-STATE-* |
|
|
| `cert-manager/` | TLS via Let's Encrypt DNS-01 (Cloudflare); staging + prod ClusterIssuers | [ADR-0006](../../home-network-k3s/decisions/adr-0006-tls-cert-manager-letsencrypt.md), docs/08 | R-TLS-* |
|
|
| `externaldns/` | Automatic DNS records for public services (Cloudflare) | docs/09 | R-DNS-* |
|
|
| `gateway/` | Gateway API GatewayClass + shared HTTPS Gateway + wildcard cert | [ADR-0002](../../home-network-k3s/decisions/adr-0002-cni-cilium.md)/[ADR-0006](../../home-network-k3s/decisions/adr-0006-tls-cert-manager-letsencrypt.md), docs/09 | R-DNS-01, R-TLS-01 |
|
|
| `monitoring/` | kube-prometheus-stack + Loki + Grafana Alloy + Alertmanager | docs/10 | R-OBS-* |
|
|
| `velero/` | Off-cluster backup/DR of volumes + resource state | [ADR-0003](../../home-network-k3s/decisions/adr-0003-storage-longhorn.md), docs/04 | R-STATE-03 |
|
|
| `kubevirt/` | KubeVirt + CDI (IaaS: application VMs on the same K8s surface) | [ADR-0005](../../home-network-k3s/decisions/adr-0005-vm-workloads-kubevirt.md), docs/06 | R-PLAT-03 |
|
|
| `image-automation/` | Flux image-update-automation (hands-off image tag advance) | [ADR-0009](../../home-network-k3s/decisions/adr-0009-automated-image-updates.md), docs/11 | R-UPD-02 |
|
|
| `keycloak/` | Platform IdP (OIDC + SAML), config-as-code, PostgreSQL on Longhorn | [ADR-0014](../../home-network-k3s/decisions/adr-0014-idp-keycloak.md), docs/15 | R-IDP-* |
|
|
| `oauth2-proxy/` | Forward-auth at the Gateway for non-OIDC apps → Keycloak | [ADR-0014](../../home-network-k3s/decisions/adr-0014-idp-keycloak.md), docs/15 | R-IDP-* |
|
|
| `kyverno/` | **L0 policy-as-code gate — OWNED BY THE POLICY ENGINEER (WS-TEST).** | [ADR-0011](../../home-network-k3s/decisions/adr-0011-test-tooling-kyverno-chainsaw.md), docs/14 | R-TEST-* |
|
|
|
|
## ⚠️ INTEGRATION TODO(PM): wire kyverno into the platform kustomization
|
|
|
|
`platform/kyverno/` is authored by a **different agent** (the policy engineer, WS-TEST). This
|
|
workstream did **not** create any files under `platform/kyverno/` and must not.
|
|
|
|
[`platform/kustomization.yaml`](kustomization.yaml) intentionally **omits `- kyverno`**. Once the
|
|
policy engineer's files land, the **PM** must add `- kyverno` to that list (recommended first, so
|
|
policies are present before other components reconcile). The line is present as a commented TODO in
|
|
the kustomization.
|
|
|
|
## Secrets
|
|
|
|
Every secret referenced below (Cloudflare API token, Velero backup-target creds, Keycloak admin/DB,
|
|
oauth2-proxy cookie/client secrets) is referenced **by name only** and will be committed
|
|
**SOPS-encrypted** (WS-SEC, [ADR-0007](../../home-network-k3s/decisions/adr-0007-secrets-sops-age.md)).
|
|
**No plaintext secret appears anywhere in this tree.**
|
|
|
|
## Cross-workstream contracts surfaced by these stubs
|
|
|
|
- **cilium (WS-NET ↔ WS-INFRA):** Cilium's *initial* CNI install is done by Ansible at cluster
|
|
bootstrap (docs/02, Phase 1). The HelmRelease here manages Cilium *config* thereafter; its Helm
|
|
values MUST match the Ansible bootstrap values (kubeProxyReplacement, k8sServiceHost/Port, API
|
|
server host) or reconciliation will fight the bootstrap. Contract owner: WS-NET + WS-INFRA.
|
|
- **gateway + cert-manager + externaldns (WS-NET + WS-SEC):** the shared Gateway listener, the
|
|
wildcard `*.home.keithjackson.dev` cert, and the ExternalDNS source all reference each other; they
|
|
form the "Issuer + Gateway TLS" interface in `roadmap/workstreams.md`.
|
|
- **image-automation (WS-UPDATE):** this dir holds only the *cluster-wide* ImageUpdateAutomation +
|
|
git write-back. Per-service `ImageRepository`/`ImagePolicy` are rendered from each
|
|
ServiceDefinition's `update` block (WS-GITOPS/WS-UPDATE), living with `apps/`.
|
|
- **keycloak/oauth2-proxy (WS-SEC):** the SSO/auth contract (`auth` block → Keycloak client /
|
|
oauth2-proxy protection) is owned by WS-SEC; these are placeholders pending that contract.
|