See also: learnings-helm-ci.md, learnings-progressive-delivery.md, learnings-operators.md
Numbered, append-only. Update the existing entry — never duplicate.
-
ignoreDifferencesrequiresRespectIgnoreDifferences=trueinsyncOptions. Without this option, ArgoCD still overwrites the live value during sync even though the diff is hidden in the UI. Symptom: live values keep resetting after each sync. -
Sync-waves on Application objects only enforce ordering during app-of-apps sync. They do NOT control when Applications sync their own contents. For guaranteed ordering between independent child Application syncs, use a multi-PR phased approach.
-
Sync-wave
"5"is the right default for CRD-dependent resources. Wave 0 installs the operator and CRDs; wave 5 gives time for CRDs to be Established before the dependent resources sync. Do NOT use"1"— too close to default and races with CRD installation.
-
Values key naming must be lowercase kebab-case when keys become Helm release names downstream. Avoid camelCase. Use
index .Values "key-name"for hyphenated keys in templates. -
GKE-targeted ArgoCD apps need a
values/providers/gcp.yaml. When an argo-apps entry targets a GKE cluster, always include the GCP provider values file alongside the app entry. Check existing entries for the pattern — omission causes silent platform-detection mismatches downstream.
-
SSA + API-server-injected fields cause sync loops on DaemonSets. The
deprecated.daemonset.template.generationannotation causes perpetual OutOfSync diffs withServerSideApply=true. Fix:ignoreDifferenceswithjsonPointers: [/metadata/annotations]scoped to the specific resource withname:andkind:.jqPathExpressionsdoes not work for this case in ArgoCD v2.12 — thejsonPointersform scoped by name should be the default pattern for any DaemonSet annotation drift. -
Operator webhook
failurePolicydrift. Operators (Istio, others) that dynamically patchfailurePolicyon ValidatingWebhookConfigurations at runtime will always cause ArgoCD drift. AddignoreDifferenceswithjsonPointersfor/webhooks/0/failurePolicy.
- ArgoCD does NOT pass
--kube-versiontohelm template..Capabilities.KubeVersion.GitVersionis empty in ArgoCD rendering, so charts that auto-detect platform (e.g. checking for the-gkesuffix) silently fail. Always set platform-specific values explicitly in provider files rather than relying on capability detection.
-
Create namespaces in the chart, not via
CreateNamespace=true. Platform/infra charts (policy engines, runtime security agents, cert managers, service meshes, gateway controllers, progressive-delivery controllers) must include atemplates/namespace.yamlthat renders the Namespace. This makes the namespace declarative, version-controlled (labels/annotations), and cleanly pruned on app deletion. Only legacy/simple services may still useCreateNamespace=true. New charts must always follow the chart-managed pattern. -
ApplyOutOfSyncOnly=truereduces noise and apply churn on large applications. Most repos should set it. Don't combine with aggressive self-heal on stateful workloads. -
ServerSideApply=trueis required for any chart that installs CRDs. CRDs are large and routinely exceed the 262KBmetadata.annotations/last-applied-configurationlimit with client-side apply. Charts without CRDs do not need it. -
CreateNamespace=trueconflicts with charts that include a Namespace template. Before adding tosyncOptions, check:grep -r "kind: Namespace" charts/<chart-name>/templates/
If found, omit
CreateNamespace=true.
- For tag-based rollouts, never use commit SHAs as
targetRevisionin production. Use named tags (e.g.stable-v1.2.3) plus a mutable promotion tag. ArgoCD tag-based sync is eventually consistent — recheck after 2–5 minutes before troubleshooting.