Argo CD can be configured to ignore specific differences between the desired state in Git and the live state in the cluster, allowing you to manage certain resource attributes dynamically without triggering sync failures.
Let’s see this in action. Imagine you have a Kubernetes Deployment managed by Argo CD, and you want to ignore changes to the spec.template.metadata.annotations field because an external controller (like cert-manager) is adding annotations to your Pods.
Here’s a simplified deployment.yaml in your Git repository:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
# This is where cert-manager might add annotations
annotations:
some-managed-annotation: "value"
spec:
containers:
- name: main
image: nginx:latest
When Argo CD syncs this, and cert-manager (or another controller) adds an annotation like cert-manager.io/cluster-issuer: "letsencrypt-prod" to the Pod template’s metadata, Argo CD will see this as a difference and report a sync error if automatic sync is enabled, or simply show a diff if manual sync is used.
To prevent this, you can tell Argo CD to ignore this specific field. You do this by modifying the Application manifest itself, adding an ignoreDifferences section.
Here’s how your Application manifest would look:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app-application
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-username/your-repo.git
targetRevision: HEAD
path: path/to/your/app
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
ignoreDifferences:
- group: apps
kind: Deployment
name: my-app
jsonPointers:
- "/spec/template/metadata/annotations"
Let’s break down the ignoreDifferences section:
group: The API group of the resource. For Deployments, this isapps.kind: The resource type,Deployment.name: The specific name of the resource to apply this rule to,my-app. If you omitname, the rule applies to all resources of thatkindandgroup.jsonPointers: A list of JSON Pointers indicating the fields to ignore./spec/template/metadata/annotationspoints directly to the annotations map within the Pod template.
How it works mechanically:
When Argo CD compares the live state of my-app in the default namespace with the desired state from Git, it will parse the ignoreDifferences rules. For any resource matching group: apps, kind: Deployment, and name: my-app, it will specifically exclude the fields specified by the jsonPointers from its diff calculation. If the only difference between Git and live is within an ignored field, Argo CD will consider the resource "synced" and healthy, even if the values don’t match.
You can ignore more than just annotations. For example, if you have a Service with a dynamically assigned clusterIP that you don’t want to track, you could add:
ignoreDifferences:
- group: "" # Core API group
kind: Service
name: my-service
jsonPointers:
- "/spec/clusterIP"
Or, to ignore all status fields across all resources:
ignoreDifferences:
- jsonPointers:
- "/status"
# group, kind, name omitted to apply globally
The jsonPointers are crucial. They follow the RFC 6901 standard for JSON Pointers. A leading / signifies the root of the document, and subsequent / characters denote nested fields. You can also use * as a wildcard for array elements or map keys if you want to ignore a pattern rather than a specific path, though this is less common for specific resource attributes.
The most surprising thing about ignoreDifferences is how granularly you can apply it. It’s not just about ignoring entire fields; you can ignore specific keys within a map or specific elements within an array if you know the exact JSON Pointer path. This allows for very precise control over what Argo CD considers drift. For instance, if you only wanted to ignore a specific annotation key, say cert-manager.io/cluster-issuer, you’d need to target the parent annotations map with the JSON Pointer /spec/template/metadata/annotations and then rely on the fact that cert-manager is the only external agent modifying it. If other agents also modified annotations, you might need a more sophisticated approach or accept that any annotation change will be ignored.
Understanding the exact JSON Pointer to the field you want to ignore is key. You can get this by examining the output of kubectl get <resource> <resource-name> -o json and tracing the path to the differing field.
Once you’ve applied ignoreDifferences, Argo CD will no longer flag these specific discrepancies, and your application will show as synchronized if all other tracked fields match.
The next challenge you’ll likely encounter is managing secrets that are injected into your cluster by external systems, and deciding whether or not to ignore their differences.