I added a Horizontal Pod Autoscaler to a Flux-managed Deployment and watched the replica count bounce between what the HPA wanted and what Git said. Every 5 minutes, Flux would reconcile, see that spec.replicas had drifted from the Git state, and reset it. The HPA would immediately scale it back. Repeat forever.
This is a fundamental tension in GitOps: Flux’s job is to make the cluster match Git. The HPA’s job is to set the replica count based on metrics. They both write to the same field, and they disagree.
The problem Link to heading
Say your Deployment in Git has replicas: 3, and the HPA scales it to 7 based on CPU load. From Flux’s perspective, the cluster has drifted — spec.replicas is 7 but Git says 3. So Flux “fixes” it back to 3. The HPA sees CPU is still high, scales to 7 again. Next reconciliation, Flux resets it. You get a sawtooth pattern in your replica count that never stabilizes.
The obvious first step is to remove the replicas field from the Deployment manifest:
# Before
spec:
replicas: 3
template:
...
# After — let HPA own it
spec:
template:
...
This helps — Flux won’t set a specific replica count if the field isn’t in the manifest. But it’s not always enough. If Flux applies the manifest and the server-side default fills in replicas: 1, you’re back to the same problem. And if you have overlay patches (like Kustomize patches for production) that set replicas, those need to be cleaned up too.
The fix: ignoreDifferences Link to heading
Flux Kustomization resources support an ignoreDifferences field that tells Flux to skip specific fields during drift detection. For the HPA case:
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
# ... other fields ...
ignoreDifferences:
- target:
kind: Deployment
namespace: my-app
jsonPatches:
- op: remove
path: /spec/replicas
This tells Flux: “when comparing the desired state from Git with the live state in the cluster, pretend /spec/replicas doesn’t exist on Deployments in the my-app namespace.” Flux still manages every other field in the Deployment — image tags, resource requests, env vars, probe configuration — but it leaves spec.replicas alone.
How it works under the hood Link to heading
When Flux reconciles, it:
- Renders the manifests from Git (running Kustomize, substituting variables, etc.)
- Fetches the live state from the cluster
- Computes a diff between the two
- Applies the diff to the cluster
The ignoreDifferences directive intervenes at step 3. Before Flux computes the diff, it applies the JSON patches to the desired state (the rendered manifests from Git). The op: remove patch strips /spec/replicas from the desired state, so when Flux compares it against the live state, there’s nothing to diff on that field. Flux sees no drift and leaves it alone.
This is why you need op: remove and not something like op: replace — you’re not setting a value, you’re removing the field from Flux’s awareness entirely.
Scoping with target Link to heading
The target field controls which resources the patches apply to. You can scope it narrowly:
ignoreDifferences:
- target:
kind: Deployment
namespace: my-app
name: frontend # only this specific Deployment
jsonPatches:
- op: remove
path: /spec/replicas
Or broadly — applying to all Deployments in a namespace, which is what I used since both my CMS and frontend Deployments have HPAs:
ignoreDifferences:
- target:
kind: Deployment
namespace: my-app
jsonPatches:
- op: remove
path: /spec/replicas
The gotcha: remove replicas from your manifests too Link to heading
Even with ignoreDifferences, you should still remove replicas from your Deployment manifests and any Kustomize patches. If you leave replicas: 3 in the manifest, it will be applied on the first reconciliation (before the HPA has a chance to set its own value), potentially causing a brief scale-down every time Flux first applies a change to the Deployment.
The cleanest setup is:
- No
replicasfield in base Deployment - No
replicasin any overlay patches ignoreDifferenceswithop: removeon/spec/replicasin the Flux Kustomization- HPA
minReplicasset to your desired minimum
This way, the HPA is the single source of truth for replica count, and Flux is the single source of truth for everything else.