kubectl has been shipping with Kustomize baked in for a while now, and it’s a game-changer for managing Kubernetes configurations. You can finally ditch that separate kustomize binary and integrate Kustomize workflows directly into your kubectl apply commands.

Let’s see how this actually looks. Imagine you have a standard Kubernetes deployment manifest, deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app-container
        image: nginx:latest

And you want to customize it for a staging environment, perhaps by increasing replicas and changing the image tag. Instead of a separate kustomization.yaml file and running kustomize build . | kubectl apply -f -, you can do this directly:

kubectl apply -k ./my-kustomization-dir

Here, ./my-kustomization-dir is a directory containing your kustomization.yaml file and any base manifests it references.

The Kustomize functionality within kubectl works by looking for a kustomization.yaml file in the specified directory. This file acts as the blueprint for your customizations. It tells kubectl what base resources to start with and what patches, modifications, or additions to apply.

A typical kustomization.yaml might look like this:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - ../base

patchesStrategicMerge:
  - deployment-patch.yaml

And deployment-patch.yaml could contain:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: my-app-container
        image: nginx:1.21.3

When you run kubectl apply -k ./my-kustomization-dir, kubectl internally invokes Kustomize. It reads kustomization.yaml, finds the base resources (in this case, referenced by ../base), applies the strategic merge patch from deployment-patch.yaml, and then sends the resulting, fully customized manifest to the Kubernetes API server. This eliminates the need for an intermediate build step and simplifies your deployment pipeline.

The core problem Kustomize solves is managing the complexity of Kubernetes YAML, especially across different environments (dev, staging, prod). Instead of maintaining separate YAML files for each environment, you define a common base and then apply environment-specific overlays. This promotes DRY (Don’t Repeat Yourself) principles and reduces the chance of configuration drift.

Internally, kubectl apply -k triggers the Kustomize library. Kustomize parses your kustomization.yaml, resolves all resource references, applies patches (strategic merge, JSON patches), handles image tag modifications, and generates a single set of Kubernetes manifests. kubectl then takes these generated manifests and applies them to your cluster, performing its usual diffing and update logic.

The levers you control are primarily within the kustomization.yaml file. You define resources (bases), patches (strategic merge, JSON 6902), transformers (like commonLabels, images), and configurations (like vars for templating).

For instance, you can automate image tag updates across multiple deployments using the images transformer:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - deployment.yaml
  - deployment-backend.yaml

images:
  - name: nginx
    newName: nginx
    newTag: 1.21.4
  - name: my-backend-image
    newName: my-registry/my-backend
    newTag: v2.5.0

This tells Kustomize to find any container image named nginx in the resources and change it to nginx:1.21.4, and similarly for my-backend-image. When kubectl apply -k runs, all these image tags are updated automatically before being sent to the API server.

Here’s a crucial detail many miss: Kustomize is declarative and additive by default. When you use patchesStrategicMerge, it’s designed to merge fields. If a field is missing in the patch but present in the base, it’s kept. If a field is present in the patch, it overwrites the base. However, for more granular control, especially when you need to remove fields or perform complex transformations, you’ll often need to use patchesJson6902. This patch type allows you to use JSON Patch operations (add, remove, replace, copy, move, test) which gives you precise control over the YAML structure. It’s the difference between saying "change this value" and "ensure this value exists and is this, or remove it if it’s something else."

Once you’ve successfully applied your Kustomized configurations, the next logical step is often to manage secrets and configuration maps in a more robust, secure, and environment-aware manner, potentially using tools like Sealed Secrets or external secret management solutions integrated with your Kustomize workflow.

Want structured learning?

Take the full Kustomize course →