Flux is designed to be eventually consistent, meaning it will eventually reach the desired state, but it doesn’t guarantee immediate reconciliation. This is often a good thing, preventing rapid state flapping. However, there are times when you need to force Flux to re-evaluate and apply a resource’s state right now.

Let’s see this in action. Imagine you’ve just applied a Deployment manifest to your cluster, but for some reason, Flux isn’t picking it up or applying it as expected. You want to trigger that reconciliation immediately.

Here’s a minimal Deployment manifest:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

You’ve applied this to your cluster, perhaps via kubectl apply -f deployment.yaml, and you’re monitoring flux get kustomizations or flux get helmreleases (depending on how you’re managing this resource through Flux) and you see it’s not updating or applying the deployment as you expect.

The core mechanism Flux uses for managing resources is through its controllers, primarily kustomize-controller and helm-controller. When a Kustomization or HelmRelease custom resource is updated (e.g., a new commit is pushed to a Git repository that Flux is watching), Flux will typically detect this change and schedule a reconciliation. However, network glitches, controller restarts, or complex dependency chains can sometimes delay this.

The most direct way to force a reconciliation for a Kustomization resource is by patching the Kustomization object itself. This tells the kustomize-controller to immediately re-evaluate its source and apply any pending changes.

kubectl patch kustomization <your-kustomization-name> \
  --namespace <your-kustomization-namespace> \
  --type merge \
  --patch '{"spec": {"force": true}}'

Replace <your-kustomization-name> with the actual name of your Kustomization resource (e.g., flux-system) and <your-kustomization-namespace> with its namespace (often flux-system). The force: true field is a signal to the kustomize-controller to ignore its reconciliation interval and perform an immediate sync. The controller will then fetch the latest source, apply the Kustomization, and update the relevant Kubernetes resources.

If you are managing resources via a HelmRelease instead of a Kustomization, the mechanism is similar. You can patch the HelmRelease to trigger a Helm upgrade, which will force Helm to re-evaluate the desired state and apply it.

kubectl patch helmrelease <your-helmrelease-name> \
  --namespace <your-helmrelease-namespace> \
  --type merge \
  --patch '{"spec": {"suspend": false, "reconcile": {}}}'

Here, <your-helmrelease-name> and <your-helmrelease-namespace> should be substituted with your specific HelmRelease details. Setting suspend: false ensures the release is not paused, and the empty reconcile: {} effectively acts as a trigger for an immediate reconciliation. The helm-controller interprets this as a request to perform an immediate helm upgrade --install operation.

You can also achieve a similar effect by modifying the Kustomization or HelmRelease spec in a way that Flux is guaranteed to detect as a change, even if it’s a no-op change in terms of the actual deployed resources. For instance, adding or modifying a label on the Kustomization object will typically trigger a reconciliation.

kubectl label kustomization <your-kustomization-name> \
  --namespace <your-kustomization-namespace> \
  flux-reconcile-trigger=$(date +%s)

This command adds a new label to the Kustomization resource with a timestamp. Flux’s controllers watch for changes to these custom resources, and any modification, including adding a label, will cause them to re-evaluate and trigger a reconciliation. The timestamp ensures the label is always unique, forcing a change detection.

Another common, albeit less direct, method involves restarting the relevant Flux controller pod. For example, if you suspect kustomize-controller is stuck:

kubectl delete pod -n flux-system -l app.kubernetes.io/name=kustomize-controller

When the pod restarts, it will re-register itself and typically initiate a reconciliation cycle for all the resources it manages, including any that were previously stalled. This is a more heavy-handed approach and should be used with caution, as it can briefly disrupt other reconciliations managed by that controller.

Finally, if you’re using Flux’s GitOps integration and suspect a problem with Flux’s ability to fetch from your Git repository, you can force a re-sync of the source itself. This is done by patching the GitRepository custom resource Flux uses to track your code.

kubectl patch gitrepository <your-gitrepository-name> \
  --namespace <your-gitrepository-namespace> \
  --type merge \
  --patch '{"spec": {"force": true}}'

This tells the source-controller (which kustomize-controller and helm-controller depend on) to perform an immediate fetch from the configured Git repository, even if its internal checks suggest no changes have occurred. This can be useful if the Git server had a temporary issue or if there’s a discrepancy that Flux’s normal polling mechanism missed.

After forcing a reconciliation, you’ll often find yourself needing to verify the actual state of your deployed Kubernetes resources. The next common issue you might encounter is a ImageUpdateAutomation failing to trigger an update when a new container image tag is available in your registry.

Want structured learning?

Take the full Flux course →