Actualiza Objetos del API en su sitio (in Place) usando kubectl 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:
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
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
:
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ámetro | tipo de unión |
---|---|
json | JSON Patch, RFC 6902 |
merge | JSON Merge Patch, RFC 7386 |
strategic | Strategic 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 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
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
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
Nota:
Si ejecutaskubectl 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.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.