# The other half of "CI does not deploy". # # CI's last act is a commit that changes image.*.digest in deploy/chart/values.yaml. # ArgoCD notices that commit and syncs. There is no kubeconfig in CI, no `helm upgrade` in # a pipeline step, and no human running kubectl. If you want to know what is running in the # cluster, you read git — that is the whole property, and a single `kubectl apply` from a # laptop is what destroys it (selfHeal below exists to undo exactly that). apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: svcforge namespace: argocd finalizers: # Without this, deleting the Application orphans every resource it created. - resources-finalizer.argocd.argoproj.io spec: project: default source: repoURL: https://gitea.oci-oci.duckdns.org/gitea_admin/svcforge.git targetRevision: master path: deploy/chart helm: releaseName: svcforge # No valueFiles override and no `parameters:` block. values.yaml in the repo is the # single source of truth — a parameter here would be a second place the deployed # digest could come from, invisible in the chart's own diff. destination: server: https://kubernetes.default.svc namespace: svcforge syncPolicy: automated: # Delete resources removed from the chart. Safe because the chart owns only svcforge # itself; tenant releases are created by the worker's helm calls and are not part of # this Application, so prune cannot reach them. prune: true # Revert manual edits. A hotfix applied by hand is a lie the next sync tells on. selfHeal: true syncOptions: - CreateNamespace=true # The migrate Job is a helm pre-install/pre-upgrade hook. ArgoCD maps helm hooks onto # its own PreSync phase, so migrations still run before any new pod starts, and a # non-zero exit fails the sync instead of rolling out pods onto an unmigrated schema. - ApplyOutOfSyncOnly=true retry: # 0, not 3, and for the same reason migrate-job.yaml sets backoffLimit: 0. # # An ArgoCD retry re-runs the WHOLE sync including the PreSync phase, and the migrate # Job is a helm pre-install/pre-upgrade hook that ArgoCD maps onto PreSync. So # `limit: 3` quietly reinstated the retry-a-failed-DDL behaviour that backoffLimit: 0 # exists to forbid — three attempts at the same failed migration, one readable error # turned into three, against a schema that may now be half-applied. # # There is no recovery path here that a retry helps with. Recovery from a failed # migration is a REVERT COMMIT: fix the SQL forward, push, and let ArgoCD sync the # new revision. Rolling back the app image does not roll back DDL that already # committed. limit: 0 backoff: duration: 20s factor: 2 maxDuration: 3m # The migrate Job is a hook, so ArgoCD deletes and recreates it every sync; its # generated fields would otherwise show as permanent drift and the app would never # report Synced. ignoreDifferences: - group: batch kind: Job jsonPointers: - /spec/template/metadata/labels