<ins> --- title: Actualiza Objetos del API en su sitio (in Place) usando kubectl patch description:  Usa kubectl patch para actualizar objetos del API de kubernetes sin reemplazarlos. Usa strategic merge patch o JSON merge patch. content_type: task weight: 50 --- <!-- overview --> 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" ## {{% heading "prerequisites" %}} {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} <!-- steps --> ## 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: {{% code_sample file="application/deployment-patch.yaml" %}} Crea el Deployment: ```shell kubectl apply -f https://k8s.io/examples/application/deployment-patch.yaml ``` Revisa los Pods asociados con tu Deployment: ```shell 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: ```yaml spec: template: spec: containers: - name: patch-demo-ctr-2 image: redis ``` Modifica tu Deployment usando Patch: ```shell kubectl patch deployment patch-demo --patch-file patch-file.yaml ``` Revisa el Deployment modificado: ```shell kubectl get deployment patch-demo --output yaml ``` El resultado muestra que el PodSpec del Deployment tiene dos contenedores: ```yaml 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: ```shell 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: ```shell 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 `patchStrategy`en 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`: ```go type PodSpec struct { ... Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...` ... } ``` También puedes consultar la estrategia de patch en [OpenApi spec](https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/swagger.json): ```yaml "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" } ``` <!-- for editors: intentionally use yaml instead of json here, to prevent syntax highlight error. --> Y puedes consultar la estrategia de patch en la [Documentación del API Kubernetes](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podspec-v1-core). Crea un archivo llamado `patch-file-tolerations.yaml` que tenga el siguiente contenido: ```yaml spec: template: spec: tolerations: - effect: NoSchedule key: disktype value: ssd ``` Modifica tu Deployment utilizando Patch: ```shell kubectl patch deployment patch-demo --patch-file patch-file-tolerations.yaml ``` Revisa el Deployment modificado: ```shell kubectl get deployment patch-demo --output yaml ``` El resultado muestra que el PodsSpec del Deployment tiene solo un Toleration: ```yaml 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`. ```go 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](https://tools.ietf.org/html/rfc7386). 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: <table> <tr><th>Valor del parámetro</th><th>tipo de unión</th></tr> <tr><td>json</td><td><a href="https://tools.ietf.org/html/rfc6902">JSON Patch, RFC 6902</a></td></tr> <tr><td>merge</td><td><a href="https://tools.ietf.org/html/rfc7386">JSON Merge Patch, RFC 7386</a></td></tr> <tr><td>strategic</td><td>Strategic merge patch</td></tr> </table> Para una comparación entre JSON patch y JSON merge patch, revisa [JSON Patch y JSON Merge Patch](https://erosb.github.io/post/json-patch-vs-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: ```yaml 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` ```shell kubectl patch deployment patch-demo --type merge --patch-file patch-file-2.yaml ``` Revisa el Deployment modificado: ```shell 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. ```yaml spec: containers: - image: gcr.io/google-samples/node-hello:1.0 ... name: patch-demo-ctr-3 ``` Revisa los Pods en ejecución: ```shell 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. ```shell 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`: {{% code_sample file="application/deployment-retainkeys.yaml" %}} Crea el Deployment: ```shell 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: ```yaml spec: strategy: type: Recreate ``` Modifica tu Deployment: ```shell 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: ```yaml 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: ```shell kubectl patch deployment retainkeys-demo --type strategic --patch-file patch-file-retainkeys.yaml ``` Revisa el contenido del Deployment: ```shell kubectl get deployment retainkeys-demo --output yaml ``` El resultado muestra que el objeto `strategy` en el Deployment ya no contiene la clave `rollingUpdate`: ```yaml 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 `patchStrategy`en 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` ```go 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](https://raw.githubusercontent.com/kubernetes/kubernetes/master/api/openapi-spec/swagger.json): ```yaml "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" }, .... } ``` <!-- para los editiores: intencionalmente se utilizó yaml en lugar de json para evitar errores de resaltado por sintaxis. --> Además puedes revisar la estrategia `retainKeys` en la [documentación del API de k8s](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#deploymentspec-v1-apps). ### 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: ```json { "spec": { "template": { "spec": { "containers": [ { "name": "patch-demo-ctr-2", "image": "redis" } ] } } } } ``` Los siguientes comandos son equivalentes: ```shell 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-2n     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` {#scale-kubectl-patch} {{< feature-state for_k8s_version="v1.24" state="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: {{% code_sample file="application/deployment.yaml" %}} Crea el Deployment: ```shell kubectl apply -f https://k8s.io/examples/application/deployment.yaml ``` Revisa los Pods asociados al Deployment ```shell 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]`: ```shell kubectl patch deployment nginx-deployment --subresource='scale' --type='merge' -p '{"spec":{"replicas":3}}' ``` El resultado es : ```shell scale.autoscaling/nginx-deployment patched ``` Revisa los Pods asociados al Deployment modificado: ```shell 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 ```shell kubectl get deployment nginx-deployment -o yaml ``` ```yaml ... spec: replicas: 3 ... status: ... availableReplicas: 3 readyReplicas: 3 replicas: 3 ``` {{< note >}} Si ejecutas `kubectl patch` y especificas la bandera `--subresource` para un recurso que no soporte un subrecurso en particular, el servidor del API regresará un error 404 Not Found. {{< /note >}} ## 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](/docs/reference/generated/kubectl/kubectl-commands/#annotate), [kubectl edit](/docs/reference/generated/kubectl/kubectl-commands/#edit), [kubectl replace](/docs/reference/generated/kubectl/kubectl-commands/#replace), [kubectl scale](/docs/reference/generated/kubectl/kubectl-commands/#scale), y [kubectl apply](/docs/reference/generated/kubectl/kubectl-commands/#apply). {{< note >}} Strategic merge patch no tiene soporte para Custom Resources (CRs). {{< /note >}} ## {{% heading "whatsnext" %}} * [Manejo de Objetos de Kubernetes](/docs/concepts/overview/working-with-objects/object-management/) * [Manejo de Objetos de Kubernetes usando comandos imperativos](/docs/tasks/manage-kubernetes-objects/imperative-command/) * [Manejo Imperativo de Objetos de Kubernetes usando archivos de configuración](/docs/tasks/manage-kubernetes-objects/imperative-config/) * [Manejo Declarativo de Objetos de Kubernetes usando archivos de configuración](/docs/tasks/manage-kubernetes-objects/declarative-config/) </ins>