Actualiza Objetos del API en su sitio (in Place) usando kubectl patch

Usa kubectl patch para actualizar objetos del API de kubernetes sin reemplazarlos. Usa strategic merge patch o JSON merge patch.

Esta tarea muestra cómo utilizar kubectl patch para actualizar un objeto del API sin reemplazarlo. Los ejercicios de esta tarea demuestran el uso de "strategic merge patch" y "JSON merge patch"

Antes de empezar

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.

Usa strategic merge patch para actualizar un Deployment

Aquí está el archivo de configuración para un Deployment con dos réplicas. Cada réplica es un Pod que tiene un contenedor:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: patch-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: patch-demo-ctr
        image: nginx
      tolerations:
      - effect: NoSchedule
        key: dedicated
        value: test-team

Crea el Deployment:

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

Revisa los Pods asociados con tu Deployment:

kubectl get pods

El resultado muestra que el Deployment tiene dos Pods. El 1/1 indica que cada Pod tiene un contenedor:

NAME                        READY     STATUS    RESTARTS   AGE
patch-demo-28633765-670qr   1/1       Running   0          23s
patch-demo-28633765-j5qs3   1/1       Running   0          23s

Toma nota de los nombres de los Pods que se están ejecutando. Verás que estos Pods son terminados y reemplazados posteriormente.

En este punto cada Pod tiene un contenedor que ejecuta una imagen de nginx. Ahora supón que quieres que cada Pod tenga dos contenedores: uno que ejecute nginx y otro que ejecute redis.

Crea un archivo llamado patch-file.yaml con el siguiente contenido:

spec:
  template:
    spec:
      containers:
      - name: patch-demo-ctr-2
        image: redis

Modifica tu Deployment usando Patch:

kubectl patch deployment patch-demo --patch-file patch-file.yaml

Revisa el Deployment modificado:

kubectl get deployment patch-demo --output yaml

El resultado muestra que el PodSpec del Deployment tiene dos contenedores:

containers:
- image: redis
  imagePullPolicy: Always
  name: patch-demo-ctr-2
  ...
- image: nginx
  imagePullPolicy: Always
  name: patch-demo-ctr
  ...

Revisa los Pods asociados con tu Deployment modificado:

kubectl get pods

El resultado muestra que los Pods tienen un nombre distinto a los que se estaban ejecutando anteriormente. El Deployment terminó los Pods viejos y creo dos nuevos que cumplen con la especificación actualizada del Deployment. El 2/2 indica que cada Pod tiene dos contenedores:

NAME                          READY     STATUS    RESTARTS   AGE
patch-demo-1081991389-2wrn5   2/2       Running   0          1m
patch-demo-1081991389-jmg7b   2/2       Running   0          1m

Un vistazo más de cerca a uno de los Pods del patch-demo:

kubectl get pod <your-pod-name> --output yaml

El resultado muestra que el Pod tienen dos contenedores: uno ejecutando nginx y otro redis:

containers:
- image: redis
  ...
- image: nginx
  ...

Notas acerca de strategic merge patch

El patch que hiciste en el ejercicio anterior se llama strategic merge patch. Toma en cuenta que el path no reemplazó la lista containers. Sino que agregó un contenedor nuevo a la lista. En otras palabras, la lista en el patch fue agregada a la lista ya existente. Esto no es lo que pasa siempre que se utiliza strategic merge patch en una lista. En algunos casos la lista existente podría ser reemplazada en lugar de unir ambas.

Con strategic merge patch, la lista existente puede ser reemplazada o unida con la nueva dependiendo de la estrategia de patch. La estrategia de patch se especifica en el valor de la clave patchStrategyen un campo tag del código fuente de Kubernetes. Por ejemplo el campo Containers de la struct PodSpec tiene un valor de merge en su clave patchStrategy:

type PodSpec struct {
  ...
  Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...`
  ...
}

También puedes consultar la estrategia de patch en OpenApi spec:

"io.k8s.api.core.v1.PodSpec": {
    ...,
    "containers": {
        "description": "List of containers belonging to the pod.  ...."
    },
    "x-kubernetes-patch-merge-key": "name",
    "x-kubernetes-patch-strategy": "merge"
}

Y puedes consultar la estrategia de patch en la Documentación del API Kubernetes.

Crea un archivo llamado patch-file-tolerations.yaml que tenga el siguiente contenido:

spec:
  template:
    spec:
      tolerations:
      - effect: NoSchedule
        key: disktype
        value: ssd

Modifica tu Deployment utilizando Patch:

kubectl patch deployment patch-demo --patch-file patch-file-tolerations.yaml

Revisa el Deployment modificado:

kubectl get deployment patch-demo --output yaml

El resultado muestra que el PodsSpec del Deployment tiene solo un Toleration:

tolerations:
- effect: NoSchedule
  key: disktype
  value: ssd

Toma en cuenta que la lista de tolerations en el PodSpec fue reemplazada, no unida. Esto es porque el campo de Tolerations del PodSpec no tiene una clave patchStrategy en su campo de tag. por lo tanto strategic merge patch utiliza la estrategia de patch por defecto, la cual es replace.

type PodSpec struct {
  ...
  Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
  ...
}

Usa JSON merge patch para actualizar un Deployment

Un strategic merge patch es distinto a un JSON merge patch.

Con JSON merge patch, si quieres actualizar una lista tienes que especificar la lista nueva en su totalidad y reemplazar la lista existente con la lista nueva.

El comando kubectl patch tiene un parámetro type que acepta los siguientes valores:

Valor del parámetrotipo de unión
jsonJSON Patch, RFC 6902
mergeJSON Merge Patch, RFC 7386
strategicStrategic merge patch

Para una comparación entre JSON patch y JSON merge patch, revisa JSON Patch y JSON Merge Patch.

El valor predeterminado para el parámetro type es strategic. Entonces en el ejercicio anterior hiciste un strategic merge patch.

A continuación haz un JSON merge path en el mismo Deployment. Crea un archivo llamado patch-file-2.yaml que tenga el siguiente contenido:

spec:
  template:
    spec:
      containers:
      - name: patch-demo-ctr-3
        image: gcr.io/google-samples/node-hello:1.0

En el comando patch configura el valor de type como merge

kubectl patch deployment patch-demo --type merge --patch-file patch-file-2.yaml

Revisa el Deployment modificado:

kubectl get deployment patch-demo --output yaml

La lista containers que especificaste en el patch solo tiene un contenedor. el resultado muestra que tu lista con un contenedor reemplazó a la lista containers preexistente.

spec:
  containers:
  - image: gcr.io/google-samples/node-hello:1.0
    ...
    name: patch-demo-ctr-3

Revisa los Pods en ejecución:

kubectl get pods

En el resultado se puede ver que los Pods existentes fueron terminados y se crearon Pods nuevos. El 1/1 indica que cada Pod nuevo esta ejecutando un solo contenedor.

NAME                          READY     STATUS    RESTARTS   AGE
patch-demo-1307768864-69308   1/1       Running   0          1m
patch-demo-1307768864-c86dc   1/1       Running   0          1m

Usa strategic merge patch para actualizar un Deployment utilizando la estrategia retainKeys

Aquí esta el archivo de configuración para un Deployment que usa la estrategia RollingUpdate:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: retainkeys-demo
spec:
  selector:
    matchLabels:
      app: nginx
  strategy:
    rollingUpdate:
      maxSurge: 30%
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: retainkeys-demo-ctr
        image: nginx

Crea el Deployment:

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

En este punto, el Deployment es creado y está usando la estrategia RollingUpdate.

Crea un archivo llamado patch-file-no-retainkeys.yaml con el siguiente contenido:

spec:
  strategy:
    type: Recreate

Modifica tu Deployment:

kubectl patch deployment retainkeys-demo --type strategic --patch-file patch-file-no-retainkeys.yaml

En el resultado se puede ver que no es posible definir el type como Recreate cuando hay un value definido para spec.strategy.rollingUpdate:

The Deployment "retainkeys-demo" is invalid: spec.strategy.rollingUpdate: Forbidden: may not be specified when strategy `type` is 'Recreate'

La forma para quitar el valor para spec.strategy.rollingUpdate al momento de cambiar el valor type es usar la estrategia retainKeys para el strategic merge.

Crea otro archivo llamado patch-file-retainkeys.yaml con el siguiente contenido:

spec:
  strategy:
    $retainKeys:
    - type
    type: Recreate

Con este Patch definimos que solo queremos conservar la clave type del objeto strategy. Por lo tanto la clave rollingUpdate será eliminada durante la operación de modificación.

Modifica tu Deployment de nuevo con este nuevo Patch:

kubectl patch deployment retainkeys-demo --type strategic --patch-file patch-file-retainkeys.yaml

Revisa el contenido del Deployment:

kubectl get deployment retainkeys-demo --output yaml

El resultado muestra que el objeto strategy en el Deployment ya no contiene la clave rollingUpdate:

spec:
  strategy:
    type: Recreate
  template:

Notas acerca de strategic merge patch utilizando la estrategia retainKeys

La modificación realizada en el ejercicio anterior tiene el nombre de strategic merge patch con estrategia retainKeys. Este método introduce una nueva directiva $retainKeys que tiene las siguientes estrategias:

  • Contiene una lista de strings.
  • Todos los campos que necesiten ser preservados deben estar presentes en la lista $retainKeys.
  • Todos los campos que estén presentes serán combinados con el objeto existente.
  • Todos los campos faltantes serán removidos o vaciados al momento de la modificación.
  • Todos los campos en la lista $retainKeys deberán ser un superconjunto o idéntico a los campos presentes en el Patch.

La estrategia retainKeys no funciona para todos los objetos. Solo funciona cuando el valor de la key patchStrategyen el campo tag de el código fuente de Kubernetes contenga retainKeys. Por ejemplo, el campo Strategy del struct DeploymentSpec tiene un valor de retainKeys en su tag patchStrategy

type DeploymentSpec struct {
  ...
  // +patchStrategy=retainKeys
  Strategy DeploymentStrategy `json:"strategy,omitempty" patchStrategy:"retainKeys" ...`
  ...
}

También puedes revisar la estrategia retainKeys en la especificación de OpenApi:

"io.k8s.api.apps.v1.DeploymentSpec": {
    ...,
    "strategy": {
        "$ref": "#/definitions/io.k8s.api.apps.v1.DeploymentStrategy",
        "description": "The deployment strategy to use to replace existing pods with new ones.",
        "x-kubernetes-patch-strategy": "retainKeys"
    },
    ....
}

Además puedes revisar la estrategia retainKeys en la documentación del API de k8s.

Formas alternativas del comando kubectl patch

El comando kubectl patch toma como entrada un archivo en formato YAML o JSON desde el sistema de archivos o la línea de comandos.

Crea un archivo llamado patch-file.json que contenga lo siguiente:

{
   "spec": {
      "template": {
         "spec": {
            "containers": [
               {
                  "name": "patch-demo-ctr-2",
                  "image": "redis"
               }
            ]
         }
      }
   }
}

Los siguientes comandos son equivalentes:

kubectl patch deployment patch-demo --patch-file patch-file.yaml
kubectl patch deployment patch-demo --patch 'spec:\n template:\n  spec:\n   containers:\n   - name: patch-demo-ctr-2\n     image: redis'

kubectl patch deployment patch-demo --patch-file patch-file.json
kubectl patch deployment patch-demo --patch '{"spec": {"template": {"spec": {"containers": [{"name": "patch-demo-ctr-2","image": "redis"}]}}}}'

Actualiza la cantidad de réplicas de un objeto utilizando kubectl patch con --subresource

FEATURE STATE: Kubernetes v1.24 [alpha]

La bandera --subresource=[subresource-name] es utilizada con comandos de kubectl como get, patch y replace para obtener y actualizar los subrecursos status y scale de los recursos (aplicable para las versiones de kubectl de v1.24 en adelante). Esta bandera se utiliza con todos los recursos del API (incluidos en k8s o CRs) que tengan los subrecursos status o scale. Deployment es un ejemplo de un objeto con estos subrecursos.

A continuación se muestra un ejemplo de un Deployment con dos réplicas:

apiVersion: apps/v1 # Usa apps/v1beta2 para versiones anteriores a 1.9.0
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # indica al controlador que ejecute 2 pods
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

Crea el Deployment:

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

Revisa los Pods asociados al Deployment

kubectl get pods -l app=nginx

En el resultado se puede observar que el Deployment tiene dos Pods:

NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-7fb96c846b-22567   1/1     Running   0          47s
nginx-deployment-7fb96c846b-mlgns   1/1     Running   0          47s

Ahora modifica el Deployment utilizando Patch con la bandera --subresource=[subresource-name]:

kubectl patch deployment nginx-deployment --subresource='scale' --type='merge' -p '{"spec":{"replicas":3}}'

El resultado es :

scale.autoscaling/nginx-deployment patched

Revisa los Pods asociados al Deployment modificado:

kubectl get pods -l app=nginx

En el resultado se puede apreciar que se ha creado un Pod nuevo. Ahora tienes 3 Pods en ejecución.

NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-7fb96c846b-22567   1/1     Running   0          107s
nginx-deployment-7fb96c846b-lxfr2   1/1     Running   0          14s
nginx-deployment-7fb96c846b-mlgns   1/1     Running   0          107s

Revisa el Deployment modificado

kubectl get deployment nginx-deployment -o yaml
...
spec:
  replicas: 3
  ...
status:
  ...
  availableReplicas: 3
  readyReplicas: 3
  replicas: 3

Resumen

En este ejercicio utilizaste kubectl patch para cambiar la configuración en ejecución de un objeto de tipo Deployment. No hubo cambios al archivo de configuración que se utilizó originalmente para crear el Deployment. Otros comandos utilizados para actualizar objetos del API incluyen: kubectl annotate, kubectl edit, kubectl replace, kubectl scale, y kubectl apply.

Siguientes pasos

Última modificación June 20, 2024 at 12:44 PM PST: Sync changest from andygol/k8s-website (36d05bc8a1)