Skip to content

GitOps plane — Argo CD v3.4.8 bootstrap and app layout

Purpose

The deployment plane for everything that runs inside the cluster. The ownership boundary (ADR-0003 split, made operational): Ansible = node bootstrap only; Argo CD = everything in-cluster after node bootstrap. There is deliberately no CI kubectl apply pipeline — Git is the deployment path.

Install and version pin

  • Argo CD v3.4.8, non-HA plain install, pinned by commit-tagged URL (argoproj/argo-cd v3.4.8 manifest, upstream SHA-256 recorded in docs/gitops.md of the infrastructure repo) and vendored bit-identical in kubernetes/gitops/bootstrap/argocd-install-v3.4.8/ (namespace file, server.insecure="true" params, install.yaml).
  • Installed by human from wetopi-ops01 during apply runbook Phase G (2026-08-30), with two recorded apply-time deviations: the org disables deploy keys (repo credential is therefore a read-only HTTPS token in repository Secret argocd/repo-infra-https), and the applicationsets.argoproj.io CRD exceeds kubectl's client-side annotation cap and is applied server-side (split manifest).
  • Edge-terminated TLS: server.insecure: "true" — the Argo CD server serves plain HTTP; TLS for argo.wetopi.net terminates at the edge Gateway (edge.md).
  • No HA at bootstrap (single replicas); HA layout is OPEN. Upgrades replace the pinned directory — never a moving stable URL.

Project and app layout

One AppProject, platform (kubernetes/gitops/app.project.yaml):

  • sourceRepos: the private infrastructure repo over HTTPS (token in argocd/repo-infra-https) + quay.io/jetstack/charts (public OCI Helm registry for cert-manager; nothing outside that exact path is admitted).
  • destinations: in-cluster only, namespace: '*' — AppProject destinations support globs but not negation, so the argocd-namespace self-management exclusion is procedural (the Argo control plane is installed only from the pinned manifests by human apply; Applications are reviewed before apply; mechanical enforcement = admission control, which does not exist at bootstrap — OPEN). ResourceQuota/LimitRange kinds are blacklisted.
  • clusterResourceWhitelist: */* (cluster-scoped resources needed at bootstrap).

The layout is a minimal viable app-of-apps:

flowchart TB
    subgraph GIT["GitHub (private)"]
        R["wetopi-platform/infrastructure<br/>kubernetes/ (desired state)"]
    end
    subgraph CL["cluster (ops01 kubectl for bootstrap only)"]
        RC["AppProject platform"]
        ROOT["Application root<br/>path kubernetes/platform/"]
        ROOT --> CM["Application cert-manager<br/>→ Helm chart + F3 manifests"]
        ROOT --> DS["Application docs-site<br/>→ 6 workload manifests"]
        ROOT --> VT["Application vault<br/>→ Infisical manifests (ns vault)"]
        OE["Application argo-edge (not anchored)<br/>→ kube-system edge-argo manifests"]
        CL2["Application cilium (not anchored)<br/>→ Helm 1.20.1 + edge-node-config"]
    end
    R -->|"HTTPS + repo Secret argocd/repo-infra-https"| RC
    RC --> ROOT
    RC -. "bootstrap apply (ops01)" .-> OE & CL2
  • Anchored in Git (child Application manifests live in the root app's synced path kubernetes/platform/, so they survive cluster state loss via root prune+selfHeal): root, cert-manager, docs-site, vault. Anchored children carry the resources-finalizer.argocd.argoproj.io finalizer — deleting an anchoring merge cascades foreground (children's workloads are deleted before the Application CR disappears), so a revert never orphans live state.
  • Not yet anchored (operator-bootstrap path, include-only self-management contract each): argo-edge, cilium.
  • Live app inventory (2026-08-31): 5 applications — root, argo-edge, cert-manager, docs-site, vault. vault is Degraded: its two operator-provisioned Secrets (postgres/infra credentials) predate S0 inputs and must exist on-cluster before first sync — expected, tracked by OBJ-VAULT-001. Per-service facts live in services/.

The broader App-of-Apps vs ApplicationSet vs per-domain split remains OPEN (master architecture plan §9.4); this layout is built to stay evolvable.

Invariants

  • The only deployment path is Git → Argo CD; ad-hoc kubectl from ops01 is for recovery/surgery and must be reconciled back into Git.
  • Child Applications never self-manage Application objects (include-only sources; anchored ones are applied only by the root app).
  • Secrets never live in Git: operator-provisioned Secrets (argo-basic-auth, docs-site-basic-auth, the vault credentials, the repo token) exist only on-cluster — Argo with default sync options neither prunes nor replaces them.
  • argocd-namespace exclusion stays procedural until admission control lands.
  • Pinned version: upgrades are reviewed replacements of the pin directory.

Dependencies

  • Depends on: the cluster + API VIP (rke2-cluster.md), the edge plane for the public WebUI path (edge.md).
  • Depends on this: every in-cluster add-on and service (cert-manager → edge TLS; docs-site, vault, argo-edge, cilium).

Verified state (2026-08-31, live from ops01)

Argo CD v3.4.8 7/7 pods Running/Ready; 5 Applications in project platform as listed above; argocd/repo-infra-https present. Dated observation — re-read argocd app list before relying on it.

Live inventory (verified 2026-09-06, BookStack mirror — T1.6)

  • v3.4.8 non-HA (sin Postgres — Redis only); WebUI argo.wetopi.net.
  • App-of-apps: app gitops → platform-gitops@main (apps/*.yaml) con recurse: true.
  • 11 apps: argocd, bookstack, cert-manager, docs-site, docs-runtime, gitops, hindsight, litellm, litellm-postgres, observability, vault — todas Synced+Healthy.
  • include-glob CONTRACT (Ley 4): añadir/quitar ficheros del include EN EL MISMO PR.
  • Repo Secrets: repo-<name>-https (auto-discovery por label, con url/username/password/project).
  • Chicken-and-egg: AppProject.sourceRepos debe aplicarse LIVE antes del root Application que lo adopta.
  • Ley de flip: la route/objeto que muere sale de Git EN el flip, nunca antes (incidente 09-01: 404 6h).

Repo: platform-gitops.