Administrar Objetos en Kubernetes

Interactuando con el API de Kubernetes aplicando paradigmas declarativo e imperativo.

1 - Administración declarativa de Objetos en Kubernetes usando archivos de Configuración

Objetos en Kubernetes pueden ser creados, actualizados y eliminados utilizando archivos de configuración almacenados en un directorio. Usando el comando kubectl apply podrá crearlos o actualizarlos de manera recursiva según sea necesario. Este método retiene cualquier escritura realizada contra objetos activos en el sistema sin unirlos de regreso a los archivos de configuración. kubectl diff le permite visualizar de manera previa los cambios que apply realizará.

Antes de empezar

Instale kubectl.

Debes tener un cluster Kubernetes a tu dispocición, y la herramienta de línea de comandos kubectl debe estar configurada. Si no tienes un cluster, puedes crear uno utilizando Minikube, o puedes utilizar una de las siguientes herramientas en línea:

Para comprobar la versión, introduzca kubectl version.

Modos de administración

La herramienta kubectl soporta tres modos distintos para la administración de objetos:

  • Comandos imperativos
  • Configuración de objetos imperativa
  • Configuración de objetos declarativa

Acceda Administración de objetos de Kubernetes para una discusión de las ventajas y desventajas de cada modo distinto de administración.

Visión general

La configuración de objetos declarativa requiere una comprensión firme de la definición y configuración de objetos de Kubernetes. Si aún no lo ha hecho, lea y complete los siguientes documentos:

A continuación la definición de términos usados en este documento:

  • archivo de configuración de objeto / archivo de configuración: Un archivo en el que se define la configuración de un objeto de Kubernetes. Este tema muestra como utilizar archivos de configuración con kubectl apply. Los archivos de configuración por lo general se almacenan en un sistema de control de versiones, como Git.
  • configuración activa de objeto / configuración activa: Los valores de configuración activos de un objeto, según estén siendo observados por el Clúster. Esta configuración se almacena en el sistema de almacenamiento de Kubernetes, usualmente etcd.
  • escritor de configuración declarativo / escritor declarativo: Una persona o componente de software que actualiza a un objeto activo. Los escritores activos a los que se refiere este tema aplican cambios a los archivos de configuración de objetos y ejecutan kubectl apply para aplicarlos.

Como crear objetos

Utilice kubectl apply para crear todos los objetos definidos en los archivos de configuración existentes en un directorio específico, con excepción de aquellos que ya existen:

kubectl apply -f <directorio>/

Esto definirá la anotación kubectl.kubernetes.io/last-applied-configuration: '{...}' en cada objeto. Esta anotación contiene el contenido del archivo de configuración utilizado para la creación del objeto.

El siguiente es un ejemplo de archivo de configuración para un objeto:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

Ejecute kubectl diff para visualizar el objeto que será creado:

kubectl diff -f https://k8s.io/examples/application/simple_deployment.yaml

Cree el objeto usando kubectl apply:

kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml

Despliegue la configuración activa usando kubectl get:

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

La salida le mostrará que la anotación kubectl.kubernetes.io/last-applied-configuration fue escrita a la configuración activa, y es consistente con los contenidos del archivo de configuración:

kind: Deployment
metadata:
  annotations:
    # ...
    # Esta es la representación JSON de simple_deployment.yaml
    # Fue escrita por kubectl apply cuando el objeto fue creado
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

Como actualizar objetos

También puede usar kubectl apply para actualizar los objetos definidos en un directorio, aún cuando esos objetos ya existan en la configuración activa. Con este enfoque logrará lo siguiente:

  1. Definir los campos que aparecerán en la configuración activa.
  2. Eliminar aquellos campos eliminados en el archivo de configuración, de la configuración activa.
kubectl diff -f <directorio>/
kubectl apply -f <directorio>/

Este es un ejemplo de archivo de configuración:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

Cree el objeto usando kubectl apply:

kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml

Despliegue la configuración activa usando kubectl get:

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

La salida le mostrará que la anotación kubectl.kubernetes.io/last-applied-configuration fue escrita a la configuración activa, y es consistente con los contenidos del archivo de configuración:

kind: Deployment
metadata:
  annotations:
    # ...
    # Esta es la representación JSON de simple_deployment.yaml
    # Fue escrita por kubectl apply cuando el objeto fue creado
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

De manera directa, actualice el campo replicas en la configuración activa usando kubectl scale. En este caso no se usa kubectl apply:

kubectl scale deployment/nginx-deployment --replicas=2

Despliegue la configuración activa usando kubectl get:

kubectl get deployment nginx-deployment -o yaml

La salida le muestra que el campo replicas ha sido definido en 2, y que la anotación last-applied-configuration no contiene el campo replicas:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # note que la anotación no contiene replicas
    # debido a que el objeto no fue actualizado usando apply
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  replicas: 2 # definido por scale
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
      # ...

Actualice el archivo de configuración simple_deployment.yaml para cambiar el campo image de nginx:1.14.2 a nginx:1.16.1, y elimine el campo minReadySeconds:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1 # actualice el valor de image
        ports:
        - containerPort: 80

Aplique los cambios realizados al archivo de configuración:

kubectl diff -f https://k8s.io/examples/application/update_deployment.yaml
kubectl apply -f https://k8s.io/examples/application/update_deployment.yaml

Despliegue la configuración activa usando kubectl get:

kubectl get -f https://k8s.io/examples/application/update_deployment.yaml -o yaml

La salida le mostrará los siguientes cambios hechos a la configuración activa:

  • El campo replicas retiene el valor de 2 definido por kubectl scale. Esto es posible ya que el campo fue omitido en el archivo de configuración.
  • El campo image ha sido actualizado de nginx:1.16.1 a nginx:1.14.2.
  • La anotación last-applied-configuration ha sido actualizada con la nueva imagen.
  • El campo minReadySeconds ha sido despejado.
  • La anotación last-applied-configuration ya no contiene el campo minReadySeconds
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # La anotación contiene la imagen acutalizada a nginx 1.11.9,
    # pero no contiene la actualización de las replicas a 2
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
    # ...
spec:
  replicas: 2 # Definido por `kubectl scale`.  Ignorado por `kubectl apply`.
  # minReadySeconds fue despejado por `kubectl apply`
  # ...
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.16.1 # Definido `kubectl apply`
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

Como eliminar objetos

Hay dos opciones diferentes para eliminar objetos gestionados por kubectl apply.

Manera recomendada: kubectl delete -f <archivo>

La manera recomendada de eliminar objetos de manera manual es utilizando el comando imperativo, ya que es más explícito en relación a lo que será eliminado, y es menos probable que resulte en algo siendo eliminado sin la intención del usuario.

kubectl delete -f <archivo>

Manera alternativa: kubectl apply -f <directorio/> --prune -l etiqueta=deseada

Únicamente utilice esta opción si está seguro de saber lo que está haciendo.

Como una alternativa a kubectl delete, puede usar kubectl apply para identificar objetos a ser eliminados, luego de que sus archivos de configuración han sido eliminados del directorio. El commando apply con --prune consulta a la API del servidor por todos los objetos que coincidan con un grupo de etiquetas, e intenta relacionar la configuración obtenida de los objetos activos contra los objetos según sus archivos de configuración. Si un objeto coincide con la consulta, y no tiene un archivo de configuración en el directorio, pero si tiene una anotación last-applied-configuration, entonces será eliminado.

kubectl apply -f <directorio/> --prune -l <etiquetas>

Como visualizar un objeto

Puede usar kubectl get con -o yaml para ver la configuración de objetos activos:

kubectl get -f <archivo|url> -o yaml

Como son las diferencias calculadas y unidas por apply

Cuando kubectl apply actualiza la configuración activa para un objeto, lo hace enviando una solicitud de patch al servidor de API. El patch define actualizaciones para campos específicos en la configuración del objeto activo. El comando kubectl apply calcula esta solicitud de patch usando el archivo de configuración, la configuración activa, y la anotación last-applied-configuration almacenada en la configuración activa.

Calculando la unión de un patch

El comando kubectl apply escribe los contenidos de la configuración a la anotación kubectl.kubernetes.io/last-applied-configuration. Esto es usado para identificar aquellos campos que han sido eliminados de la configuración y deben ser limpiados. Los siguientes pasos son usados para calcular que campos deben ser eliminados o definidos:

  1. Calculo de campos por eliminar. Estos son los campos presentes en last-applied-configuration pero ausentes en el archivo de configuración.
  2. Calculo de campos por agregar o definir. Estos son los campos presentes en el archivo de configuración, con valores inconsistentes con la configuración activa.

A continuación un ejemplo. Suponga que este es el archivo de configuración para un objeto de tipo Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1 # actualice el valor de image
        ports:
        - containerPort: 80

También, suponga que esta es la configuración activa para ese mismo objeto de tipo Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # tome nota de que la anotación no contiene un valor para replicas
    # dado que no fue actualizado usando el comando apply
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  replicas: 2 # definidas por scale
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
      # ...

Estos son los cálculos de unión que serían realizados por kubectl apply:

  1. Calcular los campos por eliminar, leyendo los valores de last-applied-configuration y comparándolos con los valores en el archivo de configuración. Limpiar los campos definidos en null de manera explícita en el archivo de configuración sin tomar en cuenta si se encuentran presentes en la anotación last-applied-configuration. En este ejemplo, minReadySeconds aparece en la anotación last-applied-configuration pero no aparece en el archivo de configuración. Acción: Limpiar minReadySeconds de la configuración activa.
  2. Calcular los campos por ser definidos, al leer los valores del fichero de configuración y compararlos con los valores en la configuración activa. En este ejemplo, el valor image en el archivo de configuración, no coincide con el valor en la configuración activa. Acción: Definir el campo image en la configuración activa.
  3. Definir el valor de la anotación last-applied-configuration para que sea consistente con el archivo de configuración.
  4. Unir los resultados de 1, 2 y 3, en una única solicitud de patch para enviar al servidor de API.

Esta es la configuración activa como resultado de esta unión:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # La anotación contiene la imágen actualizada a nginx 1.11.9,
    # pero no contiene la actualización a 2 replicas
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
    # ...
spec:
  selector:
    matchLabels:
      # ...
      app: nginx
  replicas: 2 # Definido por `kubectl scale`.  Ignorado por `kubectl apply`.
  # minReadySeconds eliminado por `kubectl apply`
  # ...
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.16.1 # Definido por `kubectl apply`
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

Como se unen los diferentes tipos de campos

La manera en la que los campos en un archivo de configuración son unidos con la configuración activa depende del tipo de campo. Existen varios tipos de campos:

  • primitivo: Campos de cadena de texto (string), enteros (integer), o lógicos (boolean). Por ejemplo, image y replicas son campos de tipo primitivo. Acción: Reemplazarlos.

  • mapa, también llamados objeto: Campo de tipo mapa o un tipo complejo que contiene sub-campos. Por ejemplo, labels, annotations,spec y metadata son todos mapas. Acción: Unir los elementos o sub-campos.

  • lista: Campos que contienen una lista de elementos que pueden ser de tipo primitivo o mapa. Como ejemplos, containers, ports, y args son listas. Acción: Varía.

Cuando kubectl apply actualiza un campo de tipo mapa o lista, típicamente no reemplaza el campo completo, sino actualiza los sub-elementos individuales. Por ejemplo, cuando se hace una unión del campo spec en un Deployment, el spec completo no es reemplazado, por el contrario, únicamente los sub-campos de spec como replica son comparados y unidos.

Uniendo cambios en campos primitivos

Campos primitivos son limpiados o reemplazados.

Campo en el archivo de configuraciónCampo en la configuración activaCampo en last-applied-configurationAcción
SiSi-Define el valor en el archivo de configuración como activo.
SiNo-Define el valor a la configuración local.
No-SiElimina de la configuración activa.
No-NoNo hacer nada. Mantiene el valor activo.

Uniendo cambios en campos de un mapa

Los campos que conjuntamente representan un mapa, son unidos al comparar cada uno de los subcampos o elementos del mapa:

Propiedad en archivo de configuraciónPropiedad en configuración activaCampo en last-applied-configurationAcción
SiSi-Comparar valores de sub-propiedades.
SiNo-Usar configuración local.
No-SiEliminar de la configuración activa.
No-NoNo hacer nada. Mantener el valor activo.

Uniendo cambios en campos de tipo lista

El unir cambios en una lista utiliza una de tres posibles estrategias:

  • Reemplazar la lista si todos sus elementos son primitivos.
  • Unir elementos individuales en líneas de elementos complejos.
  • Unir una lista de elementos primitivos.

Se define la estrategia elegida con base en cada campo.

Reemplazar una lista si todos sus elementos son primitivos

Trata la lista como si fuese un campo primitivo. Reemplaza o elimina la lista completa. Esto preserva el orden de los elementos.

Ejemplo: Usando kubectl apply para actualizar el campo args de un Contenedor en un Pod. Esto define el valor de args en la configuración activa, al valor en el archivo de configuración. Cualquier elemento de args que haya sido previamente agregado a la configuración activa se perderá. El orden de los elementos definidos en args en el archivo de configuración, serán conservados en la configuración activa.

# valor en last-applied-configuration
    args: ["a", "b"]

# valores en archivo de configuración
    args: ["a", "c"]

# configuración activa
    args: ["a", "b", "d"]

# resultado posterior a la unión
    args: ["a", "c"]

Explicación: La unión utilizó los valores del archivo de configuración para definir los nuevos valores de la lista.

Unir elementos individuales en una lista de elementos complejos

Trata la lista como un mapa, y trata cada campo específico de cada elemento como una llave. Agrega, elimina o actualiza elementos individuales. Esta operación no conserva el orden.

Esta estrategia de unión utiliza una etiqueta especial en cada campo llamada patchMergeKey. La etiqueta patchMergeKey es definida para cada campo en el código fuente de Kubernetes: types.go Al unir una lista de mapas, el campo especificado en patchMergeKey para el elemento dado se utiliza como un mapa de llaves para ese elemento.

Ejemplo: Utilice kubectl apply para actualizar el campo containers de un PodSpec. Esto une la lista como si fuese un mapa donde cada elemento utiliza name por llave.

# valor en last-applied-configuration
    containers:
    - name: nginx
      image: nginx:1.16
    - name: nginx-helper-a # llave: nginx-helper-a; será eliminado en resultado
      image: helper:1.3
    - name: nginx-helper-b # llave: nginx-helper-b; será conservado
      image: helper:1.3

# valor en archivo de configuración
    containers:
    - name: nginx
      image: nginx:1.16
    - name: nginx-helper-b
      image: helper:1.3
    - name: nginx-helper-c # llavel: nginx-helper-c; será agregado en el resultado
      image: helper:1.3

# configuración activa
    containers:
    - name: nginx
      image: nginx:1.16
    - name: nginx-helper-a
      image: helper:1.3
    - name: nginx-helper-b
      image: helper:1.3
      args: ["run"] # Campo será conservado
    - name: nginx-helper-d # llave: nginx-helper-d; será conservado
      image: helper:1.3

# resultado posterior a la unión
    containers:
    - name: nginx
      image: nginx:1.16
      # Elemento nginx-helper-a fue eliminado
    - name: nginx-helper-b
      image: helper:1.3
      args: ["run"] # Campo fue conservado
    - name: nginx-helper-c # Elemento fue agregado
      image: helper:1.3
    - name: nginx-helper-d # Elemento fue ignorado
      image: helper:1.3

Explicación:

  • El contenedor llamado "nginx-helper-a" fué eliminado al no aparecer ningún contenedor llamado "nginx-helper-a" en el archivo de configuración.
  • El contenedor llamado "nginx-helper-b" mantiene los cambios existentes en args en la configuración activa. kubectl apply pudo identificar que el contenedor "nginx-helper-b" en la configuración activa es el mismo "nginx-helper-b" que aparece en el archivo de configuración, aún teniendo diferentes valores en los campos (no existe args en el archivo de configuración). Esto sucede debido a que el valor del campo patchMergeKey (name) es idéntico en ambos.
  • El contenedor llamado "nginx-helper-c" fue agregado ya que no existe ningún contenedor con ese nombre en la configuración activa, pero si existe uno con ese nombre en el archivo de configuración.
  • El contendor llamado "nginx-helper-d" fue conservado debido a que no aparece ningún elemento con ese nombre en last-applied-configuration.

Unir una lista de elementos primitivos

A partir de Kubernetes 1.5, el unir listas de elementos primitivos no es soportado.

Valores de campo por defecto

El Servidor de API define algunos campos a sus valores por defecto si no son especificados al momento de crear un objeto.

Aquí puede ver un archivo de configuración para un Deployment. Este archivo no especifica el campo strategy:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

Cree un nuevo objeto kubectl apply:

kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml

Despliegue la configuración activa usando kubectl get:

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

La salida muestra que el servidor de API definió varios campos con los valores por defecto en la configuración activa. Estos campos no fueron especificados en el archivo de configuración.

apiVersion: apps/v1
kind: Deployment
# ...
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  replicas: 1 # valor por defecto definido por apiserver
  strategy:
    rollingUpdate: # valor por defecto definido por apiserver - derivado de strategy.type
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate # valor por defecto definido por apiserver
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        imagePullPolicy: IfNotPresent # valor por defecto definido por apiserver
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP # valor por defecto definido por apiserver
        resources: {} # valor por defecto definido por apiserver
        terminationMessagePath: /dev/termination-log # valor por defecto definido por apiserver
      dnsPolicy: ClústerFirst # valor por defecto definido por apiserver
      restartPolicy: Always # valor por defecto definido por apiserver
      securityContext: {} # valor por defecto definido por apiserver
      terminationGracePeriodSeconds: 30 # valor por defecto definido por apiserver
# ...

En una solicitud de patch, los campos definidos a valores por defecto no son redefinidos a excepción de cuando hayan sido limpiados de manera explícita como parte de la solicitud de patch. Esto puede causar comportamientos no esperados para campos cuyo valor por defecto es basado en los valores de otros campos. Cuando el otro campo ha cambiado, el valor por defecto de ellos no será actualizado de no ser que sean limpiados de manera explícita.

Por esta razón, se recomienda que algunos campos que reciben un valor por defecto del servidor sean definidos de manera explícita en los archivos de configuración, aun cuando el valor definido sea idéntico al valor por defecto. Esto facilita la identificación de valores conflictivos que podrían no ser revertidos a valores por defecto por parte del servidor.

Ejemplo:

# last-applied-configuration
spec:
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

# archivo de configuración
spec:
  strategy:
    type: Recreate # valor actualizado
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

# configuración activa
spec:
  strategy:
    type: RollingUpdate # valor por defecto
    rollingUpdate: # valor por defecto derivado del campo type
      maxSurge : 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

# resultado posterior a la unión - ERROR!
spec:
  strategy:
    type: Recreate # valor actualizado: incompatible con RollingUpdate
    rollingUpdate: # valor por defecto: incompatible con "type: Recreate"
      maxSurge : 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

Explicación:

  1. El usuario crea un Deployment sin definir strategy.type.
  2. El servidor define strategy.type a su valor por defecto de RollingUpdate y agrega los valores por defecto a strategy.rollingUpdate.
  3. El usuario cambia strategy.type a Recreate. Los valores de strategy.rollingUpdate se mantienen en su configuración por defecto, sin embargo el servidor espera que se limpien. Si los valores de strategy.rollingUpdate hubiesen sido definidos inicialmente en el archivo de configuración, hubiese sido más claro que requerían ser eliminados.
  4. Apply fallará debido a que strategy.rollingUpdate no fue eliminado. El campo strategy.rollingupdate no puede estar definido, si el valor de strategy.type es Recreate.

Recomendación: Estos campos deberían de ser definidos de manera explícita en el archivo de configuración:

  • Etiquetas de Selectors y PodTemplate en cargas de trabajo como Deployment, StatefulSet, Job, DaemonSet, ReplicaSet, y ReplicationController
  • Estrategia de rollout para un Deployment

Como limpiar campos definidos a valores por defecto por el servidor, o definidos por otros escritores

Campos que no aparecen en el archivo de configuración pueden ser limpiados si se define su valor a null y luego se aplica el archivo de configuración. Para los campos definidos a valores por defecto por el servidor, esto provoca que se reestablezca a sus valores por defecto.

Como cambiar al propietario de un campo entre un archivo de configuración y un escritor imperativo

Estos son los únicos métodos que debe usar para cambiar un campo individual de un objeto:

  • Usando kubectl apply.
  • Escribiendo de manera directa a la configuración activa sin modificar el archivo de configuración: por ejemplo, usando kubectl scale.

Cambiando al propietario de un campo de un escritor imperativo a un archivo de configuración

Añada el campo al archivo de configuración, y no realice nuevas actualizaciones a la configuración activa que no sucedan por medio de kubectl apply.

Cambiando al propietario de un archivo de configuración a un escritor imperativo

A partir de Kubernetes 1.5, el cambiar un campo que ha sido definido por medio de un archivo de configuración para que sea modificado por un escritor imperativo requiere pasos manuales:

  • Eliminar el campo del archivo de configuración.
  • Eliminar el campo de la anotación kubectl.kubernetes.io/last-applied-configuration en el objeto activo.

Cambiando los métodos de gestión

Los objetos en Kubernetes deberían de ser gestionados utilizando únicamente un método a la vez. El alternar de un método a otro es posible, pero es un proceso manual.

Migrando de gestión imperativa con comandos a configuración declarativa de objetos

El migrar de gestión imperativa utilizando comandos a la gestión declarativa de objetos requiere varios pasos manuales:

  1. Exporte el objeto activo a un archivo local de configuración:

    kubectl get <tipo>/<nombre> -o yaml > <tipo>_<nombre>.yaml
    
  2. Elimine de manera manual el campo status del archivo de configuración.

  3. Defina la anotación kubectl.kubernetes.io/last-applied-configuration en el objeto:

    kubectl replace --save-config -f <tipo>_<nombre>.yaml
    
  4. Modifique el proceso para usar kubectl apply para gestionar el objeto de manera exclusiva.

Migrando de gestión imperativa de la configuración de objetos a gestión declarativa

  1. Defina la anotación kubectl.kubernetes.io/last-applied-configuration en el objeto:

    kubectl replace --save-config -f <tipo>_<nombre>.yaml
    
  2. Modifique el proceso para usar kubectl apply para gestionar el objeto de manera exclusiva.

Definiendo los selectores para el controlador y las etiquetas de PodTemplate

La forma recomendada es definir una etiqueta única e inmutable para PodTemplate usada únicamente por el selector del controlador sin tener ningún otro significado semántico.

Ejemplo:

selector:
  matchLabels:
      controller-selector: "apps/v1/deployment/nginx"
template:
  metadata:
    labels:
      controller-selector: "apps/v1/deployment/nginx"

Siguientes pasos

2 - Manejo Declarativo de Objectos de Kubernetes usando Kustomize

Kustomize es una herramienta independiente para personalizar objetos de Kubernetes a través de un archivo de kustomization.

Desde la versión 1.14, Kubectl también admite la gestión de objetos de Kubernetes utilizando un archivo de kustomización. Para ver Recursos encontrados en un directorio que contiene un archivo de kustomización, ejecuta el siguiente comando:

kubectl kustomize <directorio_de_kustomización>

Para aplicar esos Recursos, ejecuta kubectl apply con la bandera --kustomize o -k :

kubectl apply -k <directorio_de_kustomización>

Antes de empezar

Instala kubectl.

Debes tener un cluster Kubernetes a tu dispocición, y la herramienta de línea de comandos kubectl debe estar configurada. Si no tienes un cluster, puedes crear uno utilizando Minikube, o puedes utilizar una de las siguientes herramientas en línea:

Para comprobar la versión, introduzca kubectl version.

Descripción General de Kustomize

Kustomize es una herramienta para personalizar configuraciones de Kubernetes. Ofrece características para manejar archivos de configuración de aplicaciones, tales como:

  • Generar recursos a partir de otras fuentes.
  • Establecer campos transversales para los recursos.
  • Componer y personalizar colecciones de recursos.

Generando Recursos

ConfigMaps y Secrets almacenan configuración o datos sensibles utilizados por otros objetos de Kubernetes, como los Pods. La fuente de verdad de los ConfigMaps o Secrets suele ser externa a un clúster, como un archivo .properties o un archivo de clave SSH. Kustomize tiene secretGenerator y configMapGenerator, que generan Secret y ConfigMap a partir de archivos o literales.

configMapGenerator

Para generar un ConfigMap desde un archivo, añade una entrada en la lista files en configMapGenerator. Aquí tienes un ejemplo de cómo generar un ConfigMap con un elemento de datos de un archivo .properties:

# Crear un archivo application.properties
cat <<EOF >application.properties
FOO=Bar
EOF

cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-1
  files:
  - application.properties
EOF

El ConfigMap generado se puede examinar con el siguiente comando:

kubectl kustomize ./

El ConfigMap generado es:

apiVersion: v1
data:
  application.properties: |
    FOO=Bar    
kind: ConfigMap
metadata:
  name: example-configmap-1-8mbdf7882g

Para generar un ConfigMap desde un archivo env, añade una entrada en la lista de envs en configMapGenerator. Aquí tienes un ejemplo de cómo generar un ConfigMap con un elemento de datos de un archivo .env:

# Crear un archivo .env
cat <<EOF >.env
FOO=Bar
EOF

cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-1
  envs:
  - .env
EOF

El ConfigMap generado se puede examinar con el siguiente comando:

kubectl kustomize ./

El ConfigMap generado es:

apiVersion: v1
data:
  FOO: Bar
kind: ConfigMap
metadata:
  name: example-configmap-1-42cfbf598f

Los ConfigMaps también pueden generarse a partir de pares clave-valor literales. Para generar un ConfigMap a partir de una literal clave-valor, añade una entrada a la lista literals en configMapGenerator. Aquí hay un ejemplo de cómo generar un ConfigMap con un elemento de datos de un par clave-valor:

cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-2
  literals:
  - FOO=Bar
EOF

El ConfigMap generado se puede verificar con el siguiente comando:

kubectl kustomize ./

El ConfigMap generado es:

apiVersion: v1
data:
  FOO: Bar
kind: ConfigMap
metadata:
  name: example-configmap-2-g2hdhfc6tk

Para usar un ConfigMap generado en un Deployment, refiérelo por el nombre del configMapGenerator. Kustomize reemplazará automáticamente este nombre con el nombre generado.

Este es un ejemplo de un Deployment que utiliza un ConfigMap generado:

# Crear un archivo application.properties
cat <<EOF >application.properties
FOO=Bar
EOF

cat <<EOF >deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: app
        image: my-app
        volumeMounts:
        - name: config
          mountPath: /config
      volumes:
      - name: config
        configMap:
          name: example-configmap-1
EOF

cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
configMapGenerator:
- name: example-configmap-1
  files:
  - application.properties
EOF

Genera el ConfigMap y Deployment:

kubectl kustomize ./

El Deployment generado hara referencia al ConfigMap generado por nombre:

apiVersion: v1
data:
  application.properties: |
    FOO=Bar    
kind: ConfigMap
metadata:
  name: example-configmap-1-g4hk9g2ff8
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: my-app
  name: my-app
spec:
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - image: my-app
        name: app
        volumeMounts:
        - mountPath: /config
          name: config
      volumes:
      - configMap:
          name: example-configmap-1-g4hk9g2ff8
        name: config

secretGenerator

Puedes generar Secrets a partir de archivos o pares clave-valor literales. Para generar un Secret a partir de un archivo, añade una entrada a la lista files en secretGenerator. Aquí tienes un ejemplo de cómo generar un Secret con un elemento de datos de un archivo.

# Crea un archivo password.txt
cat <<EOF >./password.txt
username=admin
password=secret
EOF

cat <<EOF >./kustomization.yaml
secretGenerator:
- name: example-secret-1
  files:
  - password.txt
EOF

El Secret generado se vería de la siguiente manera:

apiVersion: v1
data:
  password.txt: dXNlcm5hbWU9YWRtaW4KcGFzc3dvcmQ9c2VjcmV0Cg==
kind: Secret
metadata:
  name: example-secret-1-t2kt65hgtb
type: Opaque

Para generar un Secret a partir de una literal clave-valor, añade una entrada a la lista literals en secretGenerator. Aquí tienes un ejemplo de cómo generar un Secret con un elemento de datos de un par clave-valor.

cat <<EOF >./kustomization.yaml
secretGenerator:
- name: example-secret-2
  literals:
  - username=admin
  - password=secret
EOF

El Secret generado se verá de la siguiente manera:

apiVersion: v1
data:
  password: c2VjcmV0
  username: YWRtaW4=
kind: Secret
metadata:
  name: example-secret-2-t52t6g96d8
type: Opaque

Al igual que los ConfigMaps, los Secrets generados pueden utilizarse en Deployments refiriéndose al nombre del secretGenerator.

# Crea un archivo password.txt 
cat <<EOF >./password.txt
username=admin
password=secret
EOF

cat <<EOF >deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: app
        image: my-app
        volumeMounts:
        - name: password
          mountPath: /secrets
      volumes:
      - name: password
        secret:
          secretName: example-secret-1
EOF

cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
secretGenerator:
- name: example-secret-1
  files:
  - password.txt
EOF

generatorOptions

Los ConfigMaps y Secrets generados tienen un sufijo de hash de contenido añadido. Esto asegura que se genere un nuevo ConfigMap o Secret cuando se cambian los contenidos. Para desactivar el comportamiento de añadir un sufijo, se puede utilizar generatorOptions. Además, es posible especificar opciones transversales para los ConfigMaps y Secrets generados.

cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: example-configmap-3
  literals:
  - FOO=Bar
generatorOptions:
  disableNameSuffixHash: true
  labels:
    type: generated
  annotations:
    note: generated
EOF

Ejecuta kubectl kustomize ./ para visualizar el ConfigMap generado:

apiVersion: v1
data:
  FOO: Bar
kind: ConfigMap
metadata:
  annotations:
    note: generated
  labels:
    type: generated
  name: example-configmap-3

Establecer campos transversales

Es bastante común establecer campos transversales para todos los recursos de Kubernetes en un proyecto. Algunos casos de uso para establecer campos transversales:

  • Establecer el mismo espacio de nombres para todos los Recursos
  • Agregar el mismo prefijo o sufijo de nombre
  • Agregar el mismo conjunto de etiquetas
  • Agregar el mismo conjunto de anotaciones

Aquí hay un ejemplo:

# Crea un deployment.yaml
cat <<EOF >./deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
EOF

cat <<EOF >./kustomization.yaml
namespace: my-namespace
namePrefix: dev-
nameSuffix: "-001"
commonLabels:
  app: bingo
commonAnnotations:
  oncallPager: 800-555-1212
resources:
- deployment.yaml
EOF

Ejecuta kubectl kustomize ./ para ver que esos campos están todos establecidos en el Recurso Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    oncallPager: 800-555-1212
  labels:
    app: bingo
  name: dev-nginx-deployment-001
  namespace: my-namespace
spec:
  selector:
    matchLabels:
      app: bingo
  template:
    metadata:
      annotations:
        oncallPager: 800-555-1212
      labels:
        app: bingo
    spec:
      containers:
      - image: nginx
        name: nginx

Componiendo y Personalizando Recursos

Es común componer un conjunto de recursos en un proyecto y gestionarlos dentro del mismo archivo o directorio.

Kustomize ofrece la composición de recursos desde diferentes archivos y la aplicación de parches u otras personalizaciones a ellos.

Composición

Kustomize admite la composición de diferentes recursos. El campo resources, en el archivo kustomization.yaml, define la lista de recursos para incluir en una configuración. Establece la ruta al archivo de configuración de un recurso en la lista resources.

Aquí hay un ejemplo de una aplicación NGINX compuesta por un Deployment y un Service:

# Crea un archivo deployment.yaml 
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

# Crea un archivo service.yaml 
cat <<EOF > service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx
EOF

# Crea un  kustomization.yaml que los integra
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF

Los Recursos de kubectl kustomize ./ contienen tanto los objetos de Deployment como los de Service.

Personalizando

Los parches pueden usarse para aplicar diferentes personalizaciones a los recursos. Kustomize admite diferentes mecanismos de parcheo a través de patchesStrategicMerge y patchesJson6902. patchesStrategicMerge es una lista de rutas de archivo. Cada archivo debe resolverse en un parche de fusión estratégica. Los nombres dentro de los parches deben coincidir con los nombres de recursos que ya están cargados. Se recomiendan pequeños parches que hagan una sola cosa. Por ejemplo, crear un parche para aumentar el número de réplicas del Deployment y otro parche para establecer el límite de memoria.

# Crea un archivo deployment.yaml
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

# Crea un parche increase_replicas.yaml
cat <<EOF > increase_replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3
EOF

# Crea otro parche set_memory.yaml
cat <<EOF > set_memory.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  template:
    spec:
      containers:
      - name: my-nginx
        resources:
          limits:
            memory: 512Mi
EOF

cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
patchesStrategicMerge:
- increase_replicas.yaml
- set_memory.yaml
EOF

Ejecuta kubectl kustomize ./ para visualizar el Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - image: nginx
        name: my-nginx
        ports:
        - containerPort: 80
        resources:
          limits:
            memory: 512Mi

No todos los recursos o campos admiten parches de fusión estratégica. Para admitir la modificación de campos arbitrarios en recursos arbitrarios, Kustomize ofrece la implementacion a través de JSON patch patchesJson6902. Para encontrar el Recurso correcto para un parche Json, el grupo, versión, tipo y nombre de ese recurso necesitan ser especificados en kustomization.yaml. Por ejemplo, aumentar el número de réplicas de un objeto de Deployment también se puede hacer a través de patchesJson6902.

# Crea un archivo deployment.yaml 
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

# Crea un parche en json
cat <<EOF > patch.yaml
- op: replace
  path: /spec/replicas
  value: 3
EOF

# Crea un  kustomization.yaml
cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml

patchesJson6902:
- target:
    group: apps
    version: v1
    kind: Deployment
    name: my-nginx
  path: patch.yaml
EOF

Ejecuta kubectl kustomize ./ para ver que el campo replicas está actualizado:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - image: nginx
        name: my-nginx
        ports:
        - containerPort: 80

Además de los parches, Kustomize también ofrece personalizar imágenes de contenedores o inyectar valores de campos de otros objetos en contenedores sin crear parches. Por ejemplo, puedes cambiar la imagen utilizada dentro de los contenedores especificando la nueva imagen en el campo images en kustomization.yaml.

cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

cat <<EOF >./kustomization.yaml
resources:
- deployment.yaml
images:
- name: nginx
  newName: my.image.registry/nginx
  newTag: 1.4.0
EOF

Ejecuta kubectl kustomize ./ para ver que el campo image ha sido actualizado:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - image: my.image.registry/nginx:1.4.0
        name: my-nginx
        ports:
        - containerPort: 80

A veces, la aplicación que se ejecuta en un Pod puede necesitar usar valores de configuración de otros objetos. Por ejemplo, un Pod de un objeto de Deployment necesita leer el nombre del Service correspondiente desde Env o como un argumento de comando.

Dado que el nombre del Service puede cambiar a medida que se agrega namePrefix o nameSuffix en el archivo kustomization.yaml. No se recomienda codificar de manera fija el nombre del Service en el argumento del comando. Para este uso, Kustomize puede inyectar el nombre del Service en los contenedores a través de vars.

# Crea un archivo deployment.yaml (citando el delimitador de documento aquí)
cat <<'EOF' > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        command: ["start", "--host", "$(MY_SERVICE_NAME)"]
EOF

# Crea un archivo service.yaml 
cat <<EOF > service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx
EOF

cat <<EOF >./kustomization.yaml
namePrefix: dev-
nameSuffix: "-001"

resources:
- deployment.yaml
- service.yaml

vars:
- name: MY_SERVICE_NAME
  objref:
    kind: Service
    name: my-nginx
    apiVersion: v1
EOF

Ejecuta kubectl kustomize ./ para ver que el nombre del Service inyectado en la sección de contaierns es dev-my-nginx-001:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dev-my-nginx-001
spec:
  replicas: 2
  selector:
    matchLabels:
      run: my-nginx
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - command:
        - start
        - --host
        - dev-my-nginx-001
        image: nginx
        name: my-nginx

Bases y Overlays

Kustomize tiene los conceptos de bases y overlays. Una base es un directorio con un kustomization.yaml, que contiene un conjunto de recursos y personalización asociada. Una base puede ser un directorio local o un directorio de un repositorio remoto, siempre que haya un kustomization.yaml presente dentro. Un overlay es un directorio con un kustomization.yaml que se refiere a otros directorios de kustomization como sus bases. Una base no tiene conocimiento de un overlay y puede ser utilizada en múltiples overlays. Un overlay puede tener múltiples bases y compone todos los recursos de las bases y también puede tener personalizaciones encima de ellos.

Aquí hay un ejemplo de una base:


# Crea un directorio que tendrá la **base**

mkdir base

# Crea el archivo base/deployment.yaml
cat <<EOF > base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
EOF

# Crea el archivo base/service.yaml 
cat <<EOF > base/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx
EOF
# Crea un archivo base/kustomization.yaml
cat <<EOF > base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml
EOF

Esta base puede ser utilizada en múltiples overlays. Puedes agregar diferentes namePrefix u otros campos transversales en diferentes overlays. Aquí hay dos overlays utilizando la misma base.

mkdir dev
cat <<EOF > dev/kustomization.yaml
resources:
- ../base
namePrefix: dev-
EOF

mkdir prod
cat <<EOF > prod/kustomization.yaml
resources:
- ../base
namePrefix: prod-
EOF

Cómo aplicar/ver/eliminar objetos usando Kustomize

Usa --kustomize o -k en comandos de kubectl para reconocer recursos gestionados por kustomization.yaml. Nota que -k debe apuntar a un directorio de kustomization, tal como:

kubectl apply -k <kustomization directory>/

Dando como resultado el siguientekustomization.yaml,

# Crea un archivo deployment.yaml 
cat <<EOF > deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80
EOF

# Crea un archivo kustomization.yaml
cat <<EOF >./kustomization.yaml
namePrefix: dev-
commonLabels:
  app: my-nginx
resources:
- deployment.yaml
EOF

Ejecuta el siguiente comando para aplicar el objeto de Deployment dev-my-nginx:

> kubectl apply -k ./
deployment.apps/dev-my-nginx created

Ejecuta uno de los siguientes comandos para ver el objeto de Deployment dev-my-nginx:

kubectl get -k ./
kubectl describe -k ./

Ejecuta el siguiente comando para comparar el objecto Deployment dev-my-nginx contra el estado en el que estaría el clúster si se aplicara el manifiesto:

kubectl diff -k ./

Ejecuta el siguiente comando para eliminar el objeto de Deployment dev-my-nginx:

> kubectl delete -k ./
deployment.apps "dev-my-nginx" deleted

Kustomize Feature List

CampoTipoExplicación
namespacestringAgregar namespace a todos los recursos
namePrefixstringEl valor de este campo se antepone a los nombres de todos los recursos
nameSuffixstringEl valor de este campo se añade al final de los nombres de todos los recursos
commonLabelsmap[string]stringEtiquetas para agregar a los recursos y selectores.
commonAnnotationsmap[string]stringAnotaciones para agregar a todos los recursos
resources[]stringCada entrada en esta lista debe resolverse en un archivo de configuración de recurso existente
configMapGenerator[]ConfigMapArgsCada entrada en esta lista genera un ConfigMap
secretGenerator[]SecretArgsCada entrada en esta lista genera un Secret
generatorOptionsGeneratorOptionsModifica comportamientos de todos los generadores de ConfigMap y Secret
bases[]stringCada entrada en esta lista debe resolverse en un directorio que contenga un archivo kustomization.yaml
patchesStrategicMerge[]stringCada entrada en esta lista debe resolver un parche de fusión estratégica de un objeto de Kubernetes
patchesJson6902[]PatchCada entrada en esta lista debe resolverse en un objeto de Kubernetes y un parche Json
vars[]VarCada entrada es para capturar texto del campo de un recurso
images[]ImageCada entrada es para modificar el nombre, las etiquetas y/o el digesto de una imagen sin crear parches
configurations[]stringCada entrada en esta lista debe resolverse en un archivo que contenga Configuraciones de transformador de Kustomize
crds[]stringCada entrada en esta lista debería resolver a un archivo de definición OpenAPI para los tipos de Kubernetes.

Siguientes pasos