Kustomize es la herramienta de Kubernetes para personalizar manifiestos YAML sin plantillas: mantienes una base con lo común y aplicas overlays con las diferencias de cada entorno. Viene integrada en kubectl, así que no necesitas instalar nada adicional para usarla. En este tutorial construirás una aplicación de ejemplo con una base y dos overlays (desarrollo y producción), usarás patches, generarás un ConfigMap y desplegarás el resultado en un clúster.
Requisitos previos
- Una máquina con Ubuntu 24.04 LTS (tu equipo o un VPS de CubePath) con
kubectlinstalado. - Acceso a un clúster de Kubernetes con permisos para crear namespaces y Deployments. Sirve un clúster local con kind o k3s.
- Conocimientos básicos de Deployments y Services.
Comprueba que kubectl llega al clúster y qué versión de Kustomize trae integrada:
kubectl version
Client Version: v1.33.1
Kustomize Version: v5.6.0
Server Version: v1.33.1
Cualquier kubectl reciente incluye Kustomize v5, que es la versión que se usa en esta guía.
Paso 1: Crear la estructura del proyecto
Kustomize trabaja con directorios. Cada directorio contiene un kustomization.yaml que lista los recursos y las transformaciones que se aplican. Crea la estructura:
mkdir -p ~/mi-aplicacion/base ~/mi-aplicacion/overlays/desarrollo ~/mi-aplicacion/overlays/produccion
cd ~/mi-aplicacion
Al terminar el tutorial el proyecto tendrá esta forma:
base/:deployment.yaml,service.yamlykustomization.yaml, comunes a todos los entornos.overlays/desarrollo/:kustomization.yamlcon los cambios para desarrollo.overlays/produccion/:kustomization.yaml, un patch de réplicas y recursos, y el archivoapp.envdel ConfigMap.
Paso 2: Definir la base
La base contiene los manifiestos que comparten todos los entornos. Crea el Deployment:
nano base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mi-aplicacion
spec:
replicas: 1
selector:
matchLabels:
app: mi-aplicacion
template:
metadata:
labels:
app: mi-aplicacion
spec:
containers:
- name: app
image: nginx:1.27
ports:
- containerPort: 80
env:
- name: ENTORNO
value: base
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
memory: 128Mi
Crea el Service:
nano base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: mi-aplicacion
spec:
selector:
app: mi-aplicacion
ports:
- port: 80
targetPort: 80
Por último, el kustomization.yaml de la base, que enumera los recursos y añade una etiqueta común:
nano base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
labels:
- pairs:
app.kubernetes.io/part-of: mi-aplicacion
app.kubernetes.io/managed-by: kustomize
Notael campo
labelssustituye acommonLabels, que está obsoleto en Kustomize v5. A diferencia decommonLabels,labelsno modifica los selectores por defecto, lo que evita errores al cambiar etiquetas en un Deployment ya desplegado (los selectores son inmutables).
Renderiza la base para comprobar que es válida:
kubectl kustomize base
La salida es el YAML final con la etiqueta app.kubernetes.io/part-of añadida a ambos recursos. kubectl kustomize no toca el clúster: solo imprime lo que se aplicaría.
Paso 3: Crear el overlay de desarrollo
Un overlay referencia la base en resources y declara solo lo que cambia. Para desarrollo usarás un namespace propio, un prefijo en los nombres y un patch inline que cambia una variable de entorno:
nano overlays/desarrollo/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: desarrollo
namePrefix: dev-
patches:
- patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: mi-aplicacion
spec:
template:
spec:
containers:
- name: app
env:
- name: ENTORNO
value: desarrollo
Notael campo antiguo
bases:está obsoleto. Las bases se incluyen ahora enresources:, igual que cualquier otro manifiesto.
Este patch es de tipo strategic merge: se escribe como un fragmento del recurso y Kustomize lo fusiona con la base, usando el nombre del contenedor (app) y el de la variable (ENTORNO) como claves.
Renderiza el overlay:
kubectl kustomize overlays/desarrollo | grep -E 'name:|namespace:|value:'
name: dev-mi-aplicacion
namespace: desarrollo
name: dev-mi-aplicacion
namespace: desarrollo
- name: ENTORNO
value: desarrollo
name: app
Los dos recursos tienen ahora el prefijo dev- y el namespace desarrollo, y la variable ENTORNO vale desarrollo.
Paso 4: Crear el overlay de producción con patches y un ConfigMap
Producción necesita más réplicas, más recursos, una imagen fijada y configuración propia. Empieza por un patch strategic merge en un archivo aparte:
nano overlays/produccion/patch-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mi-aplicacion
spec:
replicas: 3
template:
spec:
containers:
- name: app
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
memory: 512Mi
Crea el archivo de variables con el que Kustomize generará un ConfigMap:
nano overlays/produccion/app.env
LOG_LEVEL=info
CACHE_TTL=300
Ahora el kustomization.yaml de producción. Combina un patch desde archivo, un patch JSON 6902 para un cambio puntual, el cambio de imagen y el generador:
nano overlays/produccion/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
namespace: produccion
namePrefix: prod-
images:
- name: nginx
newTag: "1.27-alpine"
configMapGenerator:
- name: app-config
envs:
- app.env
patches:
- path: patch-deployment.yaml
- target:
kind: Deployment
name: mi-aplicacion
patch: |-
- op: replace
path: /spec/template/spec/containers/0/env/0/value
value: produccion
- op: add
path: /spec/template/spec/containers/0/envFrom
value:
- configMapRef:
name: app-config
Qué hace cada bloque:
imagescambia la etiqueta de la imagennginxen todos los recursos sin tocar la base.configMapGeneratorcrea un ConfigMap a partir deapp.envy añade un sufijo con el hash de su contenido (por ejemploprod-app-config-7h2k9fmt4b). Kustomize actualiza automáticamente la referenciaapp-configdel Deployment, así que cada cambio de configuración provoca un rollout.- El patch JSON 6902 usa operaciones exactas (
replace,add,remove) sobre rutas del objeto. Es útil cuando el strategic merge no basta, por ejemplo para listas sin clave de fusión.
Renderiza y revisa las partes clave:
kubectl kustomize overlays/produccion | grep -E 'replicas:|image:|app-config|value: produccion'
name: prod-app-config-7h2k9fmt4b
replicas: 3
value: produccion
name: prod-app-config-7h2k9fmt4b
image: nginx:1.27-alpine
Advertencia
secretGeneratorfunciona igual queconfigMapGenerator, pero no guardes contraseñas en archivos que vayan al repositorio. Genera los Secrets fuera de Git o usa una herramienta como Sealed Secrets o External Secrets.
Paso 5: Desplegar los overlays en el clúster
Kustomize no crea el namespace si no lo incluyes como recurso. Créalos:
kubectl create namespace desarrollo
kubectl create namespace produccion
Antes de aplicar, revisa las diferencias con lo que hay en el clúster. La primera vez todo aparece como nuevo:
kubectl diff -k overlays/produccion
Aplica ambos overlays con la opción -k, que ejecuta Kustomize antes de enviar los manifiestos:
kubectl apply -k overlays/desarrollo
kubectl apply -k overlays/produccion
configmap/prod-app-config-7h2k9fmt4b created
service/prod-mi-aplicacion created
deployment.apps/prod-mi-aplicacion created
Comprueba que el Deployment de producción tiene tres réplicas listas y la variable correcta:
kubectl -n produccion rollout status deployment/prod-mi-aplicacion
kubectl -n produccion exec deploy/prod-mi-aplicacion -- printenv ENTORNO LOG_LEVEL
deployment "prod-mi-aplicacion" successfully rolled out
produccion
info
Paso 6: Actualizar la imagen desde un pipeline de CI/CD
En un pipeline no conviene editar YAML a mano. La CLI independiente de Kustomize incluye kustomize edit, que modifica el kustomization.yaml de forma segura. Descarga el script oficial de instalación, revísalo y ejecútalo; deja el binario en el directorio actual:
curl -fsSLO https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh
less install_kustomize.sh
bash install_kustomize.sh
sudo install -m 0755 kustomize /usr/local/bin/kustomize
kustomize version
Fija la nueva versión de la imagen en el overlay de producción:
cd ~/mi-aplicacion/overlays/produccion
kustomize edit set image nginx=nginx:1.28-alpine
grep -A2 images kustomization.yaml
images:
- name: nginx
newTag: 1.28-alpine
En el pipeline, tras este comando, haz commit del cambio y deja que la herramienta de GitOps lo despliegue, o aplícalo directamente con kubectl apply -k . seguido de kubectl -n produccion rollout status deployment/prod-mi-aplicacion.
Si usas Argo CD, no necesitas configurar nada especial: detecta el kustomization.yaml del directorio indicado en path y lo renderiza:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: mi-aplicacion-produccion
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your_org/mi-aplicacion.git
targetRevision: main
path: overlays/produccion
destination:
server: https://kubernetes.default.svc
namespace: produccion
syncPolicy:
automated:
prune: true
selfHeal: true
Solución de problemas
accumulating resources: ... no such file or directory: una ruta de resources o patches no existe. Las rutas son relativas al directorio del kustomization.yaml que las declara, no al directorio desde el que ejecutas el comando.
El patch no se aplica o crea un recurso nuevo: el metadata.name y el kind del patch deben coincidir con el recurso de la base, con el nombre original (sin namePrefix).
field is immutable al aplicar: has cambiado etiquetas que forman parte de spec.selector, algo típico al usar commonLabels. Usa labels sin includeSelectors o recrea el Deployment.
Validar contra el esquema del clúster sin aplicar:
kubectl apply -k overlays/produccion --dry-run=server
Conclusión
Has creado una base reutilizable y dos overlays que la adaptan a desarrollo y producción con patches strategic merge y JSON 6902, un ConfigMap generado con hash y un cambio de imagen automatizable. Como siguientes pasos, puedes gestionar los overlays con Argo CD o Flux, añadir componentes reutilizables con kind: Component para funcionalidades opcionales, o combinar Kustomize con Skaffold para el desarrollo local.
