Orchestration

Auto-Update Deployments with Flux CD Image Automation

June 19, 2026 Kubezilla Team 6 min read

Introduction

In the fast-paced world of microservices and continuous delivery, keeping your Kubernetes deployments up-to-date with the latest container images can be a significant operational challenge. Manually updating image tags in YAML files, committing changes, and waiting for your GitOps controller to sync is not only tedious but also prone to human error. This overhead can slow down release cycles and prevent teams from truly embracing a continuous deployment mindset. Imagine a scenario where a critical security patch is released, or a performance improvement is ready, but its deployment is delayed because of manual intervention. This is where automated image updates become invaluable.

Enter Flux CD’s Image Automation controllers. Flux, a leading GitOps tool for Kubernetes, provides a powerful set of capabilities to automate the process of detecting new container image versions and updating your Kubernetes manifests directly in Git. Instead of constantly monitoring your container registry, you can configure Flux to do it for you, pushing the updated image tags back to your repository. This closes the loop on continuous delivery, allowing you to achieve true “GitOps at scale” where your repository remains the single source of truth, but updates happen autonomously based on configured policies.

This guide will walk you through setting up Flux CD’s Image Automation to automatically update your Kubernetes deployments with new container image versions. We’ll cover everything from installing Flux with image automation enabled, to configuring image repositories and update policies, and finally observing the magic of automated updates. By the end, you’ll have a robust system that keeps your applications evergreen, reduces operational burden, and accelerates your deployment pipeline, all while maintaining the integrity and auditability of your Git repository.

TL;DR: Flux CD Image Automation

Automate Kubernetes deployment image updates using Flux CD. Flux monitors container registries, detects new image versions, and pushes updated manifest tags back to your Git repository, ensuring your clusters always run the latest approved images without manual intervention.

  • Install Flux: flux install --components-extra=image-reflector-controller,image-automation-controller
  • Create Git Repository: flux create source git --url= --branch= --interval=1m
  • Define Image Repository:
    
    apiVersion: image.toolkit.fluxcd.io/v1beta1
    kind: ImageRepository
    metadata:
      name: my-app-image
    spec:
      image: ghcr.io/kubezilla/my-app
      interval: 1m
      secretRef:
        name: registry-creds # if private registry
    
  • Define Image Policy:
    
    apiVersion: image.toolkit.fluxcd.io/v1beta1
    kind: ImagePolicy
    metadata:
      name: my-app-policy
    spec:
      imageRepositoryRef:
        name: my-app-image
      policy:
        semver:
          range: '1.0.x' # or latest, or regex
    
  • Configure Image Update Automation:
    
    apiVersion: image.toolkit.fluxcd.io/v1beta1
    kind: ImageUpdateAutomation
    metadata:
      name: my-app-update
    spec:
      interval: 1m
      git:
        checkout:
          ref:
            branch: main
        commit:
          author:
            email: fluxcd@kubezilla.io
            name: fluxcd
          messageTemplate: "Automated image update for {{ .Resource.Name }}"
      update:
        strategy: Setters
        path: ./clusters/my-cluster
    
  • Mark Deployment for Automation: Add image.toolkit.fluxcd.io/tag.semver: '1.0.x' and image.toolkit.fluxcd.io/container: my-app annotations to your deployment.

Prerequisites

Before diving into Flux CD’s Image Automation, ensure you have the following:

  • Kubernetes Cluster: A running Kubernetes cluster (v1.20 or newer). You can use Minikube, Kind, or a cloud provider’s managed Kubernetes service.
  • kubectl: The Kubernetes command-line tool, configured to connect to your cluster. Refer to the official Kubernetes documentation for installation instructions.
  • flux CLI: The Flux CD command-line interface, installed and configured. Follow the Flux CD installation guide.
  • Git Repository: An empty or existing Git repository (GitHub, GitLab, Bitbucket, etc.) where your Kubernetes manifests will reside. Flux will push updates to this repository, so ensure the repository is accessible and you have write permissions.
  • Container Registry: A Docker-compatible container registry (Docker Hub, Google Container Registry, AWS ECR, GitHub Container Registry, etc.) where your application images are stored.
  • Basic GitOps Understanding: Familiarity with GitOps principles and how Flux CD works for syncing manifests from Git to Kubernetes.

Step-by-Step Guide

1. Install Flux CD with Image Automation Components

First, you need to install Flux CD on your Kubernetes cluster. Crucially, to enable image automation, you must include the `image-reflector-controller` and `image-automation-controller` components during installation. The `image-reflector-controller` scans container registries for new image tags, and the `image-automation-controller` updates your Git repository with these new tags based on your policies.

This command bootstraps Flux into your cluster, creating the necessary Custom Resource Definitions (CRDs), controllers, and service accounts. It also sets up a GitRepository source that points to your specified repository and a Kustomization to sync resources from that repository. Remember to replace `YOUR_GIT_PROVIDER`, `YOUR_GIT_USER`, `YOUR_GIT_REPO`, and `YOUR_GIT_BRANCH` with your actual details.


flux bootstrap github \
  --owner=YOUR_GIT_USER \
  --repository=YOUR_GIT_REPO \
  --branch=main \
  --path=./clusters/my-cluster \
  --personal \
  --components-extra=image-reflector-controller,image-automation-controller

Verify: After running the bootstrap command, Flux will install itself. You can verify that all Flux components, including the image automation ones, are running correctly.


kubectl get pods -n flux-system

Expected Output: You should see pods for source-controller, kustomize-controller, helm-controller, notification-controller, image-reflector-controller, and image-automation-controller in a Running state.


NAME                                       READY   STATUS    RESTARTS   AGE
helm-controller-7bf8696887-j7x9p           1/1     Running   0          2m
image-automation-controller-74b8898cb-25sdz 1/1     Running   0          2m
image-reflector-controller-786d7955c-wz6d7 1/1     Running   0          2m
kustomize-controller-6556c68d4d-r8t9v      1/1     Running   0          2m
notification-controller-58674d8985-t8z2s   1/1     Running   0          2m
source-controller-795f7c469c-shz9x         1/1     Running   0          2m

2. Prepare Your Git Repository and Deployment Manifest

Next, you need to set up your Git repository with the application manifests that Flux will manage. Create a directory structure similar to what you specified during the `flux bootstrap` (e.g., `clusters/my-cluster`). Inside this directory, place your deployment YAML. For image automation to work, you need to use a specific placeholder for the image tag and add annotations to your deployment.

The placeholder `#[image]` will be replaced by Flux’s image automation controller. This placeholder is part of the Kubezippers Setters syntax, which Flux supports. The annotations `image.toolkit.fluxcd.io/container: my-app` and `image.toolkit.fluxcd.io/tag.semver: ‘1.0.x’` tell the `image-automation-controller` which container to target within the deployment and what semantic version range to consider for updates.

Create a file named `my-app-deployment.yaml` inside `clusters/my-cluster` in your Git repository.


apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: default
  annotations:
    image.toolkit.fluxcd.io/container.my-app: 'my-app' # Associates this container with the image policy
    image.toolkit.fluxcd.io/tag.semver: '1.0.x' # Specifies the semantic version range to adhere to
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: ghcr.io/kubezilla/my-app:1.0.0 # {"$imagepolicy": "flux-system:my-app-policy"}
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: my-app
  namespace: default
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP

Commit and Push: Commit this file to your Git repository and push it to the remote. Flux will detect the changes due to the Kustomization created during bootstrap and deploy your application.


git add .
git commit -m "Add initial my-app deployment with image automation annotations"
git push origin main

Verify: Check if the deployment is created in your cluster.


kubectl get deployment my-app -n default

Expected Output:


NAME     READY   UP-TO-DATE   AVAILABLE   AGE
my-app   1/1     1            1           <some-time>

3. Define Image Repository and Image Policy

Now, let’s tell Flux where to find your container images and what versioning policy to apply. This involves creating two Flux custom resources: `ImageRepository` and `ImagePolicy`.

The `ImageRepository` resource specifies the container image to monitor in your registry. It’s crucial for Flux to know which repository to scan. If your registry is private, you’ll need to create a Kubernetes secret with credentials and reference it here. For more advanced networking configurations or secure communication, you might explore solutions like Cilium WireGuard Encryption for private registry access within your cluster.

The `ImagePolicy` resource defines the rules for selecting the latest image tag from the `ImageRepository`. You can use `semver` ranges (e.g., `1.0.x`, `>1.0.0 <2.0.0`), `latest` tag, or even `regex` to match specific patterns. This is a powerful feature for controlling what updates are automatically applied. Create `image-automation.yaml` in your Git repository (e.g., in `clusters/my-cluster` or a dedicated `flux-system` folder if you prefer).


apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageRepository
metadata:
  name: my-app-image
  namespace: flux-system
spec:
  image: ghcr.io/kubezilla/my-app # Replace with your image path
  interval: 1m # How often to scan the registry
  # If your registry is private, uncomment and configure secretRef:
  # secretRef:
  #   name: registry-creds # A Kubernetes secret with Docker config.json
---
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImagePolicy
metadata:
  name: my-app-policy
  namespace: flux-system
spec:
  imageRepositoryRef:
    name: my-app-image
  policy:
    semver:
      range: '1.0.x' # Update to any new patch version in the 1.0.x series
  # You could also use:
  # policy:
  #   latest:
  #     allowContainerTags: '^[a-f0-9]+$' # For Git SHA tags

Commit and Push: Commit and push this file to your Git repository.


git add .
git commit -m "Add ImageRepository and ImagePolicy for my-app"
git push origin main

Verify: Check if the ImageRepository and ImagePolicy resources are created and healthy.


kubectl get imagerepository my-app-image -n flux-system
kubectl get imagepolicy my-app-policy -n flux-system

Expected Output: The ImageRepository should show the scanned image and its latest tags. The ImagePolicy should reflect the selected latest image.


NAME           AGE   LAST SCAN             LAST SUCCESSFUL SCAN   REPOSITORY                  TAGS
my-app-image   1m    2023-10-27T10:00:00Z  2023-10-27T10:00:00Z   ghcr.io/kubezilla/my-app    [1.0.0 1.0.1 1.0.2]

NAME            AGE   LATEST IMAGE                 POLICY
my-app-policy   1m    ghcr.io/kubezilla/my-app:1.0.2 semver:1.0.x

4. Configure Image Update Automation

The `ImageUpdateAutomation` resource is the core component that brings everything together. It defines *how* and *where* Flux should commit new image tags back to your Git repository. This resource specifies the Git repository to update, the branch, the commit message template, and the strategy for applying updates (e.g., `Setters` for the annotations we used).

This is where the true GitOps loop closes. Flux detects a new image, updates the manifest in Git, and then its `KustomizeController` detects the Git change and applies it to the cluster. This allows for full auditability of all changes in your Git history.

Create `image-update-automation.yaml` in your Git repository (e.g., in `clusters/my-cluster` or `flux-system` folder).


apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
  name: flux-system
  namespace: flux-system
spec:
  interval: 1m # How often to check for updates and commit
  sourceRef:
    kind: GitRepository
    name: flux-system # Refers to the GitRepository created by flux bootstrap
  git:
    checkout:
      ref:
        branch: main # The branch to commit updates to
    commit:
      author:
        email: fluxcd@kubezilla.io
        name: fluxcd-automation
      messageTemplate: "Automated image update for {{ .Resource.Name }}: {{ .Image.Tag }}"
  update:
    strategy: Setters # Use the setters strategy for annotations
    path: ./clusters/my-cluster # The path in the Git repository to scan for updates

Commit and Push: Commit and push this file to your Git repository.


git add .
git commit -m "Add ImageUpdateAutomation resource"
git push origin main

Verify: Check if the ImageUpdateAutomation resource is created.


kubectl get imageupdateautomation flux-system -n flux-system

Expected Output:


NAME        READY   STATUS                                                                  AGE
flux-system True    Automation initialized for branch 'main' and path './clusters/my-cluster'   1m

5. Trigger an Automated Update

Now for the exciting part! To see the automation in action, you need to push a new version of your `my-app` image to your container registry that matches the `semver` policy (`1.0.x`). For example, if your current image is `1.0.0`, push `1.0.1` or `1.0.2`.

Let’s simulate this by building and pushing a new image. Replace `ghcr.io/kubezilla/my-app` with your actual image path.


# Build a new image (example for a simple Dockerfile)
# Dockerfile:
# FROM alpine:latest
# CMD ["echo", "Hello Kubezilla! Version 1.0.1"]
docker build -t ghcr.io/kubezilla/my-app:1.0.1 .

# Log in to your container registry (e.g., GitHub Container Registry)
echo YOUR_GHCR_TOKEN | docker login ghcr.io -u YOUR_GHCR_USERNAME --password-stdin

# Push the new image
docker push ghcr.io/kubezilla/my-app:1.0.1

Observe: After pushing the new image, Flux will:

  1. The `ImageRepository` will scan the registry (within its `interval`, e.g., 1 minute) and detect the new `1.0.1` tag.
  2. The `ImagePolicy` will evaluate the new tag against its `1.0.x` policy and determine `1.0.1` is the latest valid tag.
  3. The `ImageUpdateAutomation` will then check for changes. It will find that the `my-app-deployment.yaml` in your Git repository is using `1.0.0` while the `ImagePolicy` has selected `1.0.1`.
  4. It will update the `my-app-deployment.yaml` file in your Git repository, changing the image tag to `1.0.1`, and commit this change.
  5. Finally, Flux’s `KustomizeController` will detect the commit to your Git repository and apply the updated deployment manifest to your Kubernetes cluster.

This process might take a few minutes depending on the `interval` settings of your Flux resources.

Verify Git Commit: Check your Git repository’s history. You should see a new commit from `fluxcd-automation` with a message like “Automated image update for my-app: 1.0.1”.


git pull origin main # Pull the latest changes from your remote
git log -1

Expected Output:


commit <commit-sha> (HEAD -> main, origin/main)
Author: fluxcd-automation <fluxcd@kubezilla.io>
Date:   Fri Oct 27 10:15:00 2023 +0000

    Automated image update for my-app: 1.0.1

Verify Deployment Update: Check the image of your deployed application in Kubernetes.


kubectl describe deployment my-app -n default | grep "Image:"

Expected Output:


    Image:        ghcr.io/kubezilla/my-app:1.0.1

This confirms that Flux CD successfully detected the new image, updated your Git repository, and applied the change to your cluster – all automatically!

Production Considerations

Implementing Flux CD Image Automation in a production environment requires careful planning and adherence to best practices.

  • Security Credentials: For private container registries, ensure your `ImageRepository` `secretRef` points to a Kubernetes secret with appropriate `dockerconfigjson` credentials. These secrets should be managed securely, perhaps using a secret management solution like HashiCorp Vault or Kubernetes external secrets.
  • Semantic Versioning (SemVer) Discipline: Strictly adhere to Semantic Versioning for your container image tags. Flux’s `semver` policy relies heavily on this. Misconfigured or inconsistent tagging can lead to unexpected updates or no updates at all.
  • Granular Policies: Use `ImagePolicy` effectively. Avoid `latest` in production for critical applications unless you have robust testing pipelines. Prefer `semver` ranges (e.g., `1.0.x` for patch updates, `1.x.x` for minor updates) to control the blast radius of automatic changes. Consider different policies for different environments (e.g., `1.0.x` for `prod`, `1.x.x` for `staging`).
  • Testing Strategy: Automated image updates should always be coupled with an automated testing strategy. Deploy new images to a staging environment, run integration and end-to-end tests, and only then allow promotion to production. Flux doesn’t inherently handle promotion across environments, this is where you might chain `ImagePolicies` or use manual promotion gates.
  • Rollback Strategy: Have a clear rollback strategy. Since Flux commits changes to Git, rolling back is as simple as reverting the commit in Git. Flux will then detect the reverted commit and roll back the deployment in the cluster. Consider using Karpenter for efficient node scaling during rollbacks and updates.
  • Monitoring and Alerting: Monitor your Flux components and the `ImageUpdateAutomation` status. Set up alerts for failed image scans, policy violations, or update automation failures. Tools like Prometheus and Grafana, potentially leveraging eBPF Observability with Hubble, can provide deep insights into your cluster’s health and Flux operations.
  • Rate Limiting and Throttling: Be mindful of potential rate limits on your container registry. If you have many `ImageRepository` resources with short `interval`s, you might hit limits. Adjust intervals accordingly.
  • Git Branching Strategy: Decide on a branching strategy for your Git repository. For production, you might commit automated updates directly to `main` (if that’s your production branch) or to a dedicated `auto-updates` branch that is then merged after review/CI.
  • Auditability: Leverage Git’s audit trail. Every automated update is a commit, providing a clear history of changes, who made them (Flux), and when.
  • Network Policies: Ensure that your Flux controllers have the necessary network access to your container registry. If your cluster uses strict Kubernetes Network Policies, you will need to explicitly allow egress traffic from the `flux-system` namespace to your registry’s endpoints.
  • Service Mesh Integration: If you’re using a service mesh like Istio Ambient Mesh, ensure that your application deployments are correctly configured to work within the mesh after updates. Automated image updates should not interfere with sidecar injection or traffic routing rules.

Troubleshooting

Here are common issues you might encounter with Flux CD Image Automation and their solutions:

  1. Issue: Flux is not detecting new image tags in the registry.

    Solution:

    • Check the `ImageRepository` resource status: kubectl get imagerepository <name> -n flux-system -o yaml. Look for errors in `status.conditions`.
    • Verify the `spec.image` path is correct and accessible.
    • Ensure the `interval` on `ImageRepository` is set appropriately (e.g., `1m`).
    • If it’s a private registry, ensure `secretRef` is correct and the secret exists and contains valid credentials.
    • Check `image-reflector-controller` logs: kubectl logs -f -n flux-system deploy/image-reflector-controller.
  2. Issue: `ImagePolicy` is not selecting the expected latest image.

    Solution:

    • Examine the `ImagePolicy` resource status: kubectl get imagepolicy <name> -n flux-system -o yaml. Check `status.latestImage` and `status.conditions`.
    • Verify your `policy.semver.range` or `policy.regex` is correct and matches the tags you expect.
    • Ensure your image tags strictly follow Semantic Versioning if using `semver` policy.
    • Make sure the `ImageRepositoryRef` points to the correct `ImageRepository`.
  3. Issue: Flux is not committing updates to Git, or the commit message is wrong.

    Solution:

    • Check the `ImageUpdateAutomation` resource status: kubectl get imageupdateautomation <name> -n flux-system -o yaml. Look for `status.lastAutomationRunTime` and any errors in `status.conditions`.
    • Verify `spec.git.checkout.ref.branch` is correct and the `flux-system` Git credentials have write access to that branch.
    • Check `image-automation-controller` logs: kubectl logs -f -n flux-system deploy/image-automation-controller.
    • Ensure `spec.update.path` correctly points to the directory containing your deployment manifests.
    • Confirm `spec.update.strategy` is `Setters` and your deployment annotations are correct (e.g., `image.toolkit.fluxcd.io/container.my-app` and `image.toolkit.fluxcd.io/tag.semver`).
  4. Issue: The deployment in Kubernetes is not updating after a new image is pushed to Git by Flux.

    Solution:

    • Verify that Flux made a commit to your Git repository (check `git log`).
    • Check the `Kustomization` resource that manages your application (e.g., `flux-system`): kubectl get kustomization <name> -n flux-system -o yaml. Ensure it’s healthy and has synced the latest Git commit.
    • Check `kustomize-controller` logs: kubectl logs -f -n flux-system deploy/kustomize-controller.
    • Ensure your deployment manifest has the correct placeholder for image automation (e.g., `image: ghcr.io/kubezilla/my-app:#[image]`).
  5. Issue: Error “no matches for kind “ImageRepository” in version “image.toolkit.fluxcd.io/v1beta1” or similar CRD errors.

    Solution:

    • This usually means the image automation CRDs were not installed.
    • Ensure you used `–components-extra=image-reflector-controller,image-automation-controller` during your `flux bootstrap` command.
    • If not, you might need to re-bootstrap Flux or manually apply the CRDs: flux install --components-extra=image-reflector-controller,image-automation-controller --export | kubectl apply -f - (this creates the CRDs without re-bootstrapping everything if Flux is already running).
  6. Issue: Automated updates are too slow or too frequent.

    Solution:

    • Adjust the `interval` for your `ImageRepository` to control how often Flux scans the registry.
    • Adjust the `interval` for your `ImageUpdateAutomation` to control how often Flux checks for updates and commits to Git.
    • Be mindful of registry rate limits, especially for public registries.

FAQ Section

  1. What is the difference between Flux CD’s `ImageUpdateAutomation` and manually updating image tags?

    Manual updates involve a developer manually editing YAML, committing, and pushing. `ImageUpdateAutomation` automates this entire process. Flux monitors the registry, detects new tags based on a policy, updates the manifest directly in Git (creating a commit), and then syncs the cluster. This reduces human error, speeds up releases, and maintains Git as the single source of truth with full auditability.

  2. Can Flux update images across multiple environments (e.g., dev, staging, prod)?

    Yes, but you’ll typically configure separate `ImagePolicy` and `ImageUpdateAutomation` resources for each environment, often pointing to different branches or paths in your Git repository. For example, `dev` might use a `1.x.x` policy, `staging` a `1.2.x` policy, and `prod` a `1.2.3` exact tag or `1.2.x` after manual promotion. This allows for controlled rollout strategies. You might also look into Flux’s cross-cluster automation for more complex scenarios.

  3. How does Flux handle image pull secrets for private registries?

    You define a Kubernetes `Secret` of type `kubernetes.io/dockerconfigjson` in the `flux-system` namespace (or the namespace where your `ImageRepository` resides) containing your registry credentials. Then, you reference this secret in your `ImageRepository` resource using `spec.secretRef.name`. This allows Flux’s `image-reflector-controller` to authenticate with the private registry.

  4. What if a new image introduced by automation breaks my application?

    This is a critical concern. Flux CD Image Automation is a powerful tool, but it doesn’t replace robust testing. You should always:

    • Use strict `ImagePolicy` rules (e.g., `semver: 1.0.x`) to limit changes to patch versions.
    • Have automated integration and end-to-end tests running in a staging environment before any automated update reaches production.
    • Implement monitoring and alerting for your applications to detect regressions quickly.
    • Be prepared to manually revert the Git commit if a problem occurs, which will trigger a rollback by Flux.

    Consider integrating with tools like Sigstore and Kyverno for ensuring image integrity and compliance before deployment.

  5. Can I use Flux to update other fields in my manifests besides image tags?

    While `ImageUpdateAutomation` is specifically designed for image tags, Flux’s underlying `KustomizeController` and `HelmController` can manage any field in your manifests. For non-image related automated changes, you would typically use external tools or custom scripts that modify your Git repository, which Flux would then pick up. The `setters` strategy used by image automation is a specialized form of Kustomize patches that focuses on image tags.

Cleanup Commands

To remove Flux CD and all its components from your cluster, as well as the example application:


# Remove the application deployment and service
kubectl delete deployment my-app -n default
kubectl delete service my-app -n default

# Remove the Flux CD components, including image automation
flux uninstall --keep-namespace

Verify:


kubectl get pods -n flux-system
# Expected: No resources found in flux-system namespace.

kubectl get deployments -n default
# Expected: my-app deployment should be gone.

You should also manually remove the files you added to your Git repository and revert the commits made by Flux automation if you no longer need them.


git rm -r clusters/my-cluster
git commit -m "Remove example application and Flux automation configs"
git push origin main

Next Steps / Further Reading

Congratulations! You’ve successfully implemented automated image updates with Flux CD. This is a significant step towards a fully automated, hands-off continuous delivery pipeline. To deepen your understanding and expand your GitOps capabilities, consider exploring:

Leave a comment