Argo CD / Generated systems and controlled recovery / Lesson 15
Diff normalization and bounded ignored fields
Distinguish legitimate controller-managed variation from hidden desired-state drift.
On this page
Lesson goals
- Explain why representation, admission, and external controllers can create differences.
- Separate ignoreDifferences comparison behavior from supported sync behavior.
A visible difference needs an owner and meaning
Desired and live representations can differ because of defaulting, normalization, admission mutation, quantity formatting, list ordering, another controller, or an actual unauthorized change. Parcel’s replica count may be controlled by an autoscaler under a deliberate contract, while an image change remains release-sensitive. Do not ignore a field until its owner and expected variation are understood. A broad rule can make Synced look reassuring while masking a material change. Preserve a redacted before-and-after example and explain the specific reason equality should not be required for that field.
Ignore only the intended identity and path
Application-level ignoreDifferences can target resource group, kind, name, namespace, and supported field selectors. System-level customization has a wider effect and deserves broader review. JSON Pointer escaping and list selection need accuracy; a malformed selector may fail to match or select more than intended. Avoid wildcard rules that suppress all spec differences to reduce noise. Document the external owner and an independent observation of the ignored behavior. Ignoring replicas for an autoscaler is not the same as ignoring arbitrary rollout fields or credentials.
Read a comparison-only rule carefully
The fragment below selects one synthetic Deployment’s replica field for comparison customization. It is not applied and does not include RespectIgnoreDifferences. In the release-3.1 documented behavior, comparison ignoring does not by itself guarantee that the same field is excluded during sync. That separate sync option has its own semantics and limitations. Review whether the resource already exists and how the desired manifest is applied. A reviewer should not infer a write-ownership promise merely from a clean diff.
spec:
ignoreDifferences:
- group: apps
kind: Deployment
name: parcel
namespace: parcel-lab
jsonPointers:
- /spec/replicas
The partial Application is never configured. It illustrates comparison scope only and does not assert live autoscaler ownership, sync exclusion, or a real field-management result.
Ensure unrelated drift remains visible
The complete local model removes only a top-level synthetic replicas key before comparing two flat records. It first ignores the intended count difference, then detects an image change. This is not JSON Pointer evaluation, Argo CD normalization, Kubernetes managedFields, or a server-side diff. It demonstrates a useful negative-case test: a narrow exception must not suppress a release-sensitive difference. Real customization needs representative complete resource fixtures and authorized platform validation where its exact behavior matters.
def compared(record):
return {k: v for k, v in record.items() if k != "replicas"}
desired = {"replicas": 2, "image": "parcel-lab-r5"}
live = {"replicas": 4, "image": "parcel-lab-r5"}
print(compared(desired) == compared(live))
live["image"] = "parcel-lab-r6"
print(compared(desired) == compared(live))
True
False
Only flat dictionaries are compared. The program cannot validate the YAML rule or reproduce Kubernetes or Argo CD diff behavior.
Keep exceptions owned and revisitable
An ignored field can become unsafe when a controller is removed, an API changes, or ownership moves. Assign an owner and review conditions rather than accumulating permanent unexplained rules. Compare observed field behavior separately and retain meaningful alerts for unexpected values. If the issue is nondeterministic generation or a bad template, fix that source instead of suppressing every output difference. A clean comparison is useful only when its exclusions are part of an honest contract that still exposes important drift and does not overstate runtime health.
Common errors and fixes
All spec fields are ignored to make an Application Synced.
- Why it happens
- Noise reduction removes the core desired-state comparison contract.
- How to fix it
- Identify each legitimate external owner and scope any justified exception narrowly.
- Prevent it next time
- Test that image, identity, and other critical drift remain visible.
ignoreDifferences is assumed to prevent every write to the field.
- Why it happens
- Comparison policy was confused with sync application behavior.
- How to fix it
- Review the supported RespectIgnoreDifferences semantics independently.
- Prevent it next time
- State comparison and write-ownership guarantees separately.
An old exception remains after its external controller is removed.
- Why it happens
- The ignored-field lifecycle has no owner or review trigger.
- How to fix it
- Reevaluate ownership and restore appropriate comparison.
- Prevent it next time
- Track why each exception exists and when it should be retired.
Check your understanding
1. Replicas are ignored for a declared autoscaler. Should an image change also disappear?
Show worked solution
No. The exception should preserve unrelated release-sensitive differences. The local negative case demonstrates that requirement only for a flat model; actual resource fixtures and supported selectors must establish the real scope.
2. Why can an Application be Synced while a field still changes during sync?
Show worked solution
The comparison rule and apply behavior are separate. A field ignored for equality may still be present in the desired document applied under default behavior. Review the specific supported sync option and resource state before promising exclusion from writes.
Key takeaways
- Every ignored field needs an explicit owner and reason.
- Comparison exceptions and sync-write behavior are distinct.