Skip to content

11.05 Managing Directories with Kustomize

Abstract

Kustomize can manage Kubernetes manifests spread across multiple directories.

This keeps large applications organized while still allowing one kustomization.yaml file to build and apply everything together.


Why Manage Multiple Directories?

Small projects may keep all YAML files in one folder:

k8s/
├── api-depl.yaml
├── api-service.yaml
├── db-depl.yaml
└── db-service.yaml

This works, but as the application grows, one folder becomes hard to maintain.

Warning

Keeping every manifest in a single directory can become messy when applications include many services, databases, caches, queues, and environment-specific configs.


Better Directory Structure

A cleaner approach is to group related resources by component.

k8s/
├── api/
│   ├── api-depl.yaml
│   └── api-service.yaml
├── db/
│   ├── db-depl.yaml
│   └── db-service.yaml
└── kustomization.yaml

Apply each directory manually:

kubectl apply -f k8s/api/
kubectl apply -f k8s/db/

But this still requires multiple commands.

Tip

Use a top-level kustomization.yaml file to manage all directories from one place.


Top-Level kustomization.yaml

The root kustomization.yaml can reference files inside subdirectories.

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

resources:
  - api/api-depl.yaml
  - api/api-service.yaml
  - db/db-depl.yaml
  - db/db-service.yaml

Build the final manifests:

kustomize build k8s/

Apply them to the cluster:

kustomize build k8s/ | kubectl apply -f -

Or use native kubectl support:

kubectl apply -k k8s/

Success

This creates all resources together while keeping the source files organized by component.


Example: Larger Application

For larger systems, you may have more components:

k8s/
├── api/
│   ├── api-depl.yaml
│   └── api-service.yaml
├── db/
│   ├── db-depl.yaml
│   └── db-service.yaml
├── cache/
│   ├── redis-depl.yaml
│   ├── redis-service.yaml
│   └── redis-config.yaml
├── kafka/
│   ├── kafka-depl.yaml
│   ├── kafka-service.yaml
│   └── kafka-config.yaml
└── kustomization.yaml

Root kustomization:

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

resources:
  - api/api-depl.yaml
  - api/api-service.yaml
  - db/db-depl.yaml
  - db/db-service.yaml
  - cache/redis-depl.yaml
  - cache/redis-service.yaml
  - cache/redis-config.yaml
  - kafka/kafka-depl.yaml
  - kafka/kafka-service.yaml
  - kafka/kafka-config.yaml

Note

This approach works, but the root file can become long if every YAML file is listed individually.


Directory-Level kustomization.yaml

A better production structure is to place a kustomization.yaml inside each component directory.

k8s/
├── kustomization.yaml
├── api/
│   ├── kustomization.yaml
│   ├── api-depl.yaml
│   └── api-service.yaml
├── db/
│   ├── kustomization.yaml
│   ├── db-depl.yaml
│   └── db-service.yaml
├── cache/
│   ├── kustomization.yaml
│   ├── redis-depl.yaml
│   ├── redis-service.yaml
│   └── redis-config.yaml
└── kafka/
    ├── kustomization.yaml
    ├── kafka-depl.yaml
    ├── kafka-service.yaml
    └── kafka-config.yaml

Root k8s/kustomization.yaml:

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

resources:
  - api/
  - db/
  - cache/
  - kafka/

Example k8s/db/kustomization.yaml:

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

resources:
  - db-depl.yaml
  - db-service.yaml

Tip

Referencing directories keeps the root file clean and allows each team or component to manage its own resources.


Applying Multiple Directories

kustomize build k8s/

Apply:

kustomize build k8s/ | kubectl apply -f -
kubectl apply -k k8s/
kustomize build k8s/ | kubectl delete -f -

Or:

kubectl delete -k k8s/

Note

kustomize build only renders the final YAML.

It does not deploy anything unless you pipe the output to kubectl apply -f - or use kubectl apply -k.


Recommended Production Layout

k8s/
├── base/
│   ├── api/
│   ├── db/
│   ├── cache/
│   ├── kafka/
│   └── kustomization.yaml
└── overlays/
    ├── dev/
    │   └── kustomization.yaml
    ├── staging/
    │   └── kustomization.yaml
    └── prod/
        └── kustomization.yaml

Production recommendation

Use base for shared resources and overlays for environment-specific changes.

This avoids duplication and keeps dev, staging, and production consistent.


Example Base kustomization.yaml

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

resources:
  - api/
  - db/
  - cache/
  - kafka/

commonLabels:
  app.kubernetes.io/managed-by: kustomize

Example Prod Overlay

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

resources:
  - ../../base

commonLabels:
  environment: prod

patches:
  - path: api-replica-patch.yaml

Example patch:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  replicas: 5

Example

The base defines the common application structure.

The overlay modifies only what changes for that environment.


Do's

  • Group manifests by application component
  • Add a kustomization.yaml in each major directory
  • Keep the root kustomization.yaml clean
  • Use base and overlays for environments
  • Validate output before applying
kustomize build k8s/

Don'ts

  • Don't keep hundreds of YAML files in one flat directory
  • Don't manually apply many directories one by one in production
  • Don't duplicate the same manifests across dev, staging, and prod
  • Don't mix unrelated services in one component folder
  • Don't apply generated output without reviewing it in critical environments

Production Best Practices

Recommended

  • Use GitOps-friendly structure
  • Keep one component per directory
  • Use clear names like api, db, cache, and kafka
  • Use overlays for environment-specific configuration
  • Keep secrets out of plain YAML unless encrypted with tools like Sealed Secrets or SOPS
  • Run validation in CI before applying manifests

Common Mistakes

Avoid these

  • Forgetting to include a directory in the root resources
  • Referencing files with wrong relative paths
  • Creating duplicate resource names across directories
  • Applying subdirectories separately and causing drift
  • Mixing generated manifests with source manifests

Troubleshooting

Issue What to Check
Resource not created Is the file or directory listed under resources?
Build fails Check indentation and relative paths
Duplicate resource error Check repeated names across directories
Overlay not applied Confirm overlay references the correct base
kubectl apply fails Run kustomize build first and inspect output

Useful commands:

kustomize build k8s/
kubectl apply -k k8s/
kubectl delete -k k8s/
kubectl diff -k k8s/

Tip

kubectl diff -k k8s/ is useful before applying changes in production.


Summary

Quote

  • Kustomize can manage manifests across multiple directories
  • A root kustomization.yaml can reference files or folders
  • Directory-level kustomization.yaml files keep large projects clean
  • Use base and overlays for production-ready structure
  • Apply with kubectl apply -k k8s/ or kustomize build k8s/ | kubectl apply -f -

Root vs Subdirectory Customizations

Kustomize applies transformations only to the resources listed in the current kustomization.yaml.

If you add a label, namespace, annotation, image transformer, or name prefix inside a subdirectory such as k8s/api/kustomization.yaml, the change applies only to the resources listed in that subdirectory file.

If you add the same transformation in the root k8s/kustomization.yaml, it applies to everything referenced from the root file, including all resources coming from subdirectories such as api/ and db/.

Note

A subdirectory kustomization.yaml controls only its local resource list. The root kustomization.yaml controls everything it includes.

# k8s/api/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - api-depl.yaml
  - api-service.yaml

commonLabels:
  app.kubernetes.io/part-of: api

This label is applied only to api-depl.yaml and api-service.yaml.

# k8s/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - api/
  - db/

commonLabels:
  app.kubernetes.io/managed-by: kustomize

This label is applied globally to all resources included through api/ and db/.

Warning

Be careful with root-level transformations in production. A global namespace, namePrefix, nameSuffix, or commonLabels setting can affect every component included from the root file.

Example

In the shown structure, adding commonLabels inside k8s/db/kustomization.yaml affects only DB resources. Adding commonLabels inside the root k8s/kustomization.yaml affects both API and DB resources.