GitOps makes Git the source of truth for what runs in the cluster: you commit manifests, and a controller inside the cluster keeps the live state matching the repository. No one runs `kubectl apply` from a laptop, every change is a reviewed commit, and a cluster that loses a node reconciles itself straight back to the repo. That last point matters more here than it would elsewhere. This platform drains and replaces worker nodes as routine maintenance: pods move, machines come and go, so "the cluster should converge back to a known-good state on its own" is not a disaster-recovery hypothetical. It is the everyday shape of the system. A controller reconciling to Git is what makes constant churn boring. Argo CD is the controller this page uses, but the pattern is standard and not locked to any one tool. The other delivery pages feed into this one: whatever you write in [Helm](/docs/hetzner/apalla/workloads/delivery/deploy-with-helm) or [Kustomize](/docs/hetzner/apalla/workloads/delivery/deploy-with-kustomize) becomes the thing Git holds and the controller reconciles. ## The reconcile loop ```mermaid flowchart LR Dev([You]) -->|commit + merge| Repo[(Git repo)] Repo -->|controller watches| Ctrl{Argo CD} Ctrl -->|render + apply| Live[Live cluster state] Live -.->|drift detected| Ctrl Ctrl -.->|selfHeal reverts| Live ``` The solid path is a deploy: a merge lands in Git, the controller notices, renders the manifests, and applies them. The dashed path is the interesting half. The controller keeps comparing live state against the repo, and when they diverge (someone ran `kubectl edit`, or a replaced node came back without a workload) it pulls the cluster back to what Git says. There is no separate "restore" step. Reconcile is the restore. ## The Application resource An `Application` points Argo CD at a path in a repo and a destination in the cluster: ```yaml title="application.yaml" apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: web namespace: argocd spec: project: default source: repoURL: https://github.com/your-org/apps path: web/overlays/prod targetRevision: main destination: server: https://kubernetes.default.svc namespace: team-web syncPolicy: automated: prune: true # delete objects removed from Git selfHeal: true # revert manual changes back to Git ``` The `source` can be plain YAML, a Helm chart, or a Kustomize overlay; Argo CD renders all three. For the fuller install, access, OIDC login, and repository credentials, see [Set up Argo CD](/docs/hetzner/apalla/clusters/gitops/set-up-argo-cd). ## What automated sync gives you Two flags on `syncPolicy.automated` do the reconciling: - **`prune`** deletes objects you removed from Git, so the cluster does not accumulate orphans. - **`selfHeal`** reverts a manual `kubectl edit` back to what Git says, so the repo stays the truth. Turn both on and the outcome is a single rule you can reason about: a merge deploys, a revert rolls back, and a hand-made change is undone. ## Many clusters with ApplicationSets For a fleet, an `ApplicationSet` generates one `Application` per cluster, or per environment, from a single template, each with its own values. That is how an agency delivers a shared platform across dozens of client clusters without hand-writing an `Application` for each. ## Keep secrets out of Git and split the repos Plaintext secrets never belong in a repo the controller reads. Commit an encrypted form or a reference instead, and let the tooling resolve it in-cluster. The [ConfigMaps and Secrets](/docs/hetzner/apalla/workloads/delivery/config-maps-and-secrets) page covers Sealed Secrets and External Secrets end to end. The repo layout tends to mirror the `ApplicationSet` split above: the platform team owns the repo holding the templates and the list of clusters, and each application team owns the repo an `Application` `source` points at. Argo CD only ever reads what it is pointed at, so a client team merging their own app can never reach the definition that governs the whole fleet. Because it is all standard Git and Kubernetes manifests, there is no lock-in: Argo CD, Flux, or any GitOps tool reads the same repository, and you can move between them.