Skip to main content
Kimbernetes uses Kustomize overlays to manage configurations across environments. This pattern allows you to define base configurations once and customize them for specific environments without duplication.

What are Kustomize Overlays?

Kustomize overlays are a way to customize Kubernetes manifests without modifying the original files. Think of it as inheritance in object-oriented programming - you have a base class (base configuration) and derived classes (overlays) that extend or override specific properties.

Base Layer

Generic, reusable configurations that work across any environment

Overlay Layer

Environment-specific customizations that extend or patch the base

No Duplication

Write configuration once, customize as needed per environment

Clear Separation

Infrastructure code separated from environment-specific values

The Two-Layer Pattern

Kimbernetes implements a two-layer overlay structure:
overlays/
├── base/              # Layer 1: Generic configurations
│   └── cert-manager/
│       ├── kustomization.yaml
│       ├── namespace.yaml
│       ├── helm-repository.yaml
│       └── helm-release.yaml
└── kimawesome/        # Layer 2: Environment-specific
    └── infrastructure/
        └── cert-manager/
            └── kustomization.yaml  # References base + adds customizations

Base Configurations

Base configurations contain environment-agnostic definitions. They should be generic enough to work in any environment with appropriate overlays.

Example: cert-manager Base

The base kustomization file lists all resources:
resources:
  - namespace.yaml
  - helm-repository.yaml
  - helm-release.yaml
Simple and straightforward - just references the component’s manifests.

Environment Overlays

Environment overlays reference the base and add customizations. They inherit all base resources and can:
  • Set namespaces
  • Add additional resources
  • Patch existing resources
  • Override values

Example: cert-manager Kimawesome Overlay

The kimawesome overlay for cert-manager is minimal:
# overlays/kimawesome/infrastructure/cert-manager/kustomization.yaml
namespace: cert-manager
resources:
  - ../../../base/cert-manager
This overlay:
  1. References the base: ../../../base/cert-manager includes all base resources
  2. Sets the namespace: All resources will be deployed to cert-manager namespace
  3. Can be extended: Additional resources or patches can be added here

Overlay with Customizations

For more complex cases, overlays can add resources and patches:
# overlays/kimawesome/infrastructure/cert-manager/kustomization.yaml
namespace: cert-manager
resources:
  - ../../../base/cert-manager
  - cluster-issuer.yaml          # Environment-specific resource
  - certificate.yaml             # Environment-specific certificate

patches:
  - patch: |
      - op: add
        path: /spec/values/prometheus
        value:
          enabled: true
    target:
      kind: HelmRelease
      name: cert-manager
This adds:
  • ClusterIssuer resource specific to kimawesome (e.g., Let’s Encrypt production)
  • Certificate resource for kimawesome domains
  • Helm values patch to enable Prometheus monitoring

Patching Strategies

Kustomize supports several patching strategies for modifying resources:
Merge new values with existing configuration:
patches:
  - patch: |
      apiVersion: helm.toolkit.fluxcd.io/v2
      kind: HelmRelease
      metadata:
        name: cert-manager
        namespace: cert-manager
      spec:
        values:
          replicaCount: 2
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
    target:
      kind: HelmRelease
      name: cert-manager
This merges the new values with existing ones in the HelmRelease.

Complete Example: MetalLB

Let’s examine a complete overlay example from Kimbernetes:
1

Base Configuration

overlays/base/metallb/kustomization.yaml:
resources:
  - namespace.yaml
  - helm-repository.yaml
  - helm-release.yaml
overlays/base/metallb/helm-release.yaml:
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: metallb
  namespace: kube-system
spec:
  chart:
    spec:
      chart: metallb
      sourceRef:
        kind: HelmRepository
        name: metallb
      version: "=0.15.3"
  interval: 24h
  releaseName: metallb
  install:
    crds: Create
  upgrade:
    crds: CreateReplace
2

Environment Overlay

overlays/kimawesome/loadbalancer/kustomization.yaml:
namespace: kube-system
resources:
  - ../../base/metallb
  - ip-address-pool.yaml
  - l2-advertisement.yaml
The kimawesome overlay adds environment-specific IP pools and L2 advertisement configuration.
3

Environment-Specific Resources

overlays/kimawesome/loadbalancer/ip-address-pool.yaml:
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default
  namespace: kube-system
spec:
  addresses:
    - 192.168.0.200-192.168.0.250  # kimawesome-specific IP range
overlays/kimawesome/loadbalancer/l2-advertisement.yaml:
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: kube-system
spec:
  ipAddressPools:
    - default
These resources are specific to the kimawesome environment and would differ in other environments.
4

Flux Reconciliation

overlays/kimawesome/loadbalancer/kustomization.flux.yaml:
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: metallb
  namespace: kube-system
spec:
  interval: 10m
  path: "./overlays/kimawesome/loadbalancer"
  prune: true
  sourceRef:
    kind: GitRepository
    name: flux-system
    namespace: flux-system
This tells Flux to reconcile the kimawesome loadbalancer overlay every 10 minutes.

Overlay Organization Patterns

Kimbernetes organizes overlays by function rather than by technology:
Purpose: Load balancer configuration (MetalLB)Contains IP address pools and L2 advertisement settings specific to the kimawesome network.Why separate?: Load balancer is foundational infrastructure that other components depend on.
Purpose: Core infrastructure servicesSubdirectories include:
  • cert-manager/ - TLS certificate management
  • sealed-secrets/ - Secret encryption
  • observability/ - Monitoring and logging stack
  • gatewayapi/ - Gateway API resources
  • vpn/ - VPN connectivity
Why grouped?: These services provide infrastructure capabilities for applications.Dependency: Depends on metallb via dependsOn in Flux Kustomization.
Purpose: Application workloadsSubdirectories include:
  • dns-server/ - Internal DNS
  • tooling/ - Utility applications (n8n, yopass)
  • version-management/ - Version control systems
  • steering-k8s/ - Cluster management tools
Why grouped?: These are user-facing applications that consume infrastructure services.
Purpose: Website and documentationContains knowledge hub and article deployments.Why separate?: Website updates frequently and independently from infrastructure.

Creating a New Overlay

1

Create Base Configuration

Create a new directory in overlays/base/:
mkdir -p overlays/base/myapp
cd overlays/base/myapp
Create base manifests:
# kustomization.yaml
resources:
  - namespace.yaml
  - deployment.yaml
  - service.yaml
2

Write Base Manifests

Create generic Kubernetes manifests without environment-specific values:
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: myapp
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: myapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:latest
        ports:
        - containerPort: 8080
3

Create Environment Overlay

Create the kimawesome overlay:
mkdir -p overlays/kimawesome/applications/myapp
cd overlays/kimawesome/applications/myapp
Create the overlay kustomization:
# kustomization.yaml
namespace: myapp
resources:
  - ../../../base/myapp

patches:
  - patch: |
      - op: replace
        path: /spec/replicas
        value: 3
      - op: replace
        path: /spec/template/spec/containers/0/image
        value: myapp:v1.2.3
    target:
      kind: Deployment
      name: myapp
4

Create Flux Kustomization

Create the Flux Kustomization resource:
# kustomization.flux.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: myapp
  namespace: flux-system
spec:
  interval: 10m
  path: "./overlays/kimawesome/applications/myapp"
  prune: true
  sourceRef:
    kind: GitRepository
    name: flux-system
  dependsOn:
    - name: infrastructure
      namespace: flux-system
5

Add to Parent Kustomization

Reference the new Flux Kustomization in the parent:
# overlays/kimawesome/applications/kustomization.yaml
resources:
  - dns-server/kustomization.flux.yaml
  - tooling/kustomization.flux.yaml
  - myapp/kustomization.flux.yaml  # Add this line
6

Commit and Push

git add overlays/
git commit -m "Add myapp overlay configuration"
git push
Flux will detect the changes within 1 minute and reconcile the new application.

Advanced Techniques

Generate ConfigMaps from files or literals:
configMapGenerator:
  - name: myapp-config
    files:
      - config.json
    literals:
      - LOG_LEVEL=info
      - ENVIRONMENT=production
Kustomize automatically handles ConfigMap updates by appending a hash to the name, triggering pod restarts.

Best Practices

Keep Base Generic

Base configurations should work across environments without modification. Avoid hardcoding environment-specific values.

Use Descriptive Names

Name directories and files clearly. Use helm-release.yaml, not release.yaml.

Minimize Patches

Prefer adding new resources over patching existing ones. Patches can become complex and hard to maintain.

Document Overrides

Comment why environment-specific overrides exist, especially for non-obvious changes.

Test Locally

Use kustomize build to preview the final manifests before committing:
kustomize build overlays/kimawesome/applications/myapp

Organize by Function

Group related components together (infrastructure, applications, etc.) rather than by technology.

Debugging Overlays

Preview what Flux will apply:
# Build a specific overlay
kustomize build overlays/kimawesome/infrastructure/cert-manager

# Pipe to kubectl to validate
kustomize build overlays/kimawesome/infrastructure/cert-manager | kubectl apply --dry-run=client -f -

Troubleshooting Common Issues

Cause: The kustomization.yaml doesn’t reference any manifests.Solution: Ensure the resources list includes all necessary files or directories:
resources:
  - namespace.yaml
  - deployment.yaml
Cause: Multiple overlays are trying to create the same resource.Solution:
  • Check for duplicate resource definitions
  • Use namespaces to isolate resources
  • Ensure only one Kustomization manages each resource
Cause: The target selector doesn’t match any resources.Solution: Verify the target kind, name, and namespace match exactly:
target:
  kind: HelmRelease
  name: exact-name-here
  namespace: correct-namespace
Cause: Kustomize strategic merge vs JSON patch confusion.Solution: For complex value overrides, use JSON patch with explicit paths:
patches:
  - patch: |
      - op: replace
        path: /spec/values/image/tag
        value: v1.2.3
    target:
      kind: HelmRelease
      name: myapp

Next Steps

Adding Applications

Step-by-step guide to adding new applications using overlays

Managing Secrets

Learn how to handle secrets in overlays with Sealed Secrets

Flux Components

Understand how the kustomize-controller processes overlays

Repository Structure

Review the complete repository organization

Build docs developers (and LLMs) love