Kustomize lets you manage Kubernetes configurations declaratively, and overriding image tags is a common task for promoting application versions across different environments.

Let’s see it in action. Imagine you have a base Kubernetes deployment manifest, and you want to deploy version v1.2.0 to your staging environment and v1.3.0 to production.

Here’s a simplified base/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app-container
        image: my-registry/my-app:latest # This is what we'll override
        ports:
        - containerPort: 8080

Now, we’ll create a kustomization.yaml in a base directory:

# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml

To override the image tag for staging, create a staging directory with its own kustomization.yaml:

# staging/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../base

images:
  - name: my-registry/my-app # The image name to match
    newTag: v1.2.0          # The new tag to apply

When you run kustomize build staging, it will output a deployment manifest with the image tag changed:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app-container
        image: my-registry/my-app:v1.2.0 # Overridden!
        ports:
        - containerPort: 8080

For production, you’d create a production directory:

# production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../base

images:
  - name: my-registry/my-app
    newTag: v1.3.0

The problem Kustomize solves here is managing configuration drift across environments. Instead of having separate, manually edited YAML files for dev, staging, and prod, you define a common base and then specify only the differences for each environment. This dramatically reduces errors and makes promotion workflows much smoother. The images field in kustomization.yaml is a powerful declarative way to target and replace image specifications across all resources defined in that Kustomization’s scope.

Internally, Kustomize reads your kustomization.yaml files. When it encounters the images directive, it walks through all the Kubernetes resources it’s processing (defined in resources or bases). For each resource, it inspects its spec.template.spec.containers (and initContainers, ephemeralContainers) to find any container that matches the name specified in the images directive. If a match is found, it replaces the image field with the newName (if provided) and newTag (if provided). This is a strategic merge patch operation under the hood, but Kustomize abstracts that complexity away.

You can also specify a newName if you’re promoting to a different registry or repository. For example, if your staging images are in staging-registry/my-app and production is in prod-registry/my-app:

# staging/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../base

images:
  - name: my-registry/my-app # The original image name
    newName: staging-registry/my-app # New repository
    newTag: v1.2.0          # New tag

The most surprising thing about Kustomize’s image override is that it doesn’t just look at the top-level Deployment or StatefulSet object. It recursively descends into the spec.template of Pods defined within Deployments, StatefulSets, DaemonSets, Jobs, and CronJobs, and then examines all containers listed there (including initContainers and ephemeralContainers) to find the matching image name. This means a single images entry in your kustomization.yaml can update image tags across many different types of workload controllers, ensuring consistency.

The next concept you’ll likely encounter is managing secrets and config maps across environments, which Kustomize also handles elegantly with its configMapGenerator and secretGenerator directives.

Want structured learning?

Take the full Kustomize course →