Argo CD — GitOps on both planes
Argo CD is the only mechanism that changes cluster state in this lab. If it is not in git, it does not run; if Argo did not sync it, it is drift to be explained. There are two independent installs, one per plane, and confusing them is the classic beginner error here.
Part A — How it is set up
Tooling plane (Mac mini)
- Where: namespace
argocdon the tooling cluster; front doorargo.rhels.com. - Login: Dex fronting OpenLDAP (“Log in via OpenLDAP” —
identity.md). The local admin exists as break-glass;
its initial secret is recorded in Vault
(
secret/lab/argocd/mini-initial-admin). - Layout: root-app pattern from
rhels/local-k8s-gitops(argocd/applications/root.yaml+ one Application file per app inargocd/applications/). Most apps sync paths insidelocal-k8s-gitopsitself; theagentops-*apps syncrhels/lab-agentopsmodules (LDAP, group-sync, observability, MCP server, snow-sim, CMDB). - Sync model: automated with prune + self-heal on the platform
apps. Repository credentials for the private repos are delivered
from Vault (
secret/lab/argocd/repositories-*paths).
Workload cluster (CRC / OpenShift GitOps)
- Where: OpenShift GitOps operator 1.21 (Argo CD 3.4.7) in the
openshift-gitopsnamespace; front door is the OpenShift route under the cluster’s own route domain. - Login: “Log in via OpenShift” — OpenShift OAuth with LDAP behind it. Local login is disabled for the platform tenants (OAuth-only since 2026-10-24); recovery is via the cluster, not a password.
- Layout: bootstrap root application in
rhels/local-k8s-gitops(clusters/crc/openshift-gitops/bootstrap/), then per-area apps (observability, logging, vault-access, security, the agentops platform fromrhels/lab-agentopsgitops-crc/). Apps live in AppProjects (crc-gitops,crc-agentops, …) whose destination whitelists are the real permission boundary — a new namespace or kind needs a commented, deliberate project change. - Controller-access shims: apps that create namespaces or
cluster-scoped objects carry an
argocd-controller-adminbinding at sync-wave −1 (the pattern the login-tests app established); without it the controller is forbidden from creating the app’s own service accounts.
Shared rules
- Sync waves order platform pieces (foundation at −1, tenants after).
- A failed PostSync hook means the sync did not finish — check hook Jobs before believing “Synced” (the LDAP seed is the standing example, identity.md).
Part B — How to use it
- Check an app: open the plane’s UI, find the app, read
Sync/Health and the last sync operation — or
kubectl -n argocd get application <app>/kubectl -n openshift-gitops get application <app>and read.status. Runbook 8 is the checklist. - Make a change: edit git, push, watch the app go OutOfSync → Synced/Healthy at the new revision. That revision SHA is the evidence a change landed — quote it, not “it should be fine”.
- Refresh vs sync: a hard refresh re-reads git (use it when Argo seems to be looking at a stale revision); a sync applies. Automated apps normally need neither — reaching for the button first is a smell; find out why automation did not do it.
- Roll back: runbook 10 — Argo’s history view redeploys a prior revision, but the durable fix is a git revert; a UI rollback without the revert is undone by the next sync.
- Add an app: runbook 5 (demo apps) or copy the nearest existing Application file (platform apps). New destination namespace or resource kind ⇒ extend the AppProject whitelist in the same commit, with a comment naming why.
- Read pod logs through Argo: the resource tree → pod → Logs is the quickest path when you do not have cluster shell access (runbook 3 has the kubectl equivalent).