Hasta ahora en los post anteriores hemos estado trabajando con solo un POD o una instancia de cada POD. Pero para realmente tener ese escenario no necesitamos kubernetes podiamos hacerlo igual con docker o con docker-conpose. Veamos ahora realmente algo de lo que nos ofrece realmente kubernetes que es la posibilidad de gestionar multiples instancias de un mismo POD.

Esto lo hace kubernetes posible haciendo uso de los objetos con tipo Deployment, es un objeto muy similar al POD con el que hemos estado trabajando solo que nos permite indicarle cuantas instancias queremos de un mismo pod. Para ver un ejemplo podemos hacer, como siempre, uso de un comando dry-run:

kubectl create deployment mario-deploy --image=pengbai/docker-supermario:latest --port=8080 --dry-run=client -o yaml > mario-deployment.yaml

Esto nos creará un documento similar a este:

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: mario-deploy
  name: mario-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mario-deploy
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: mario-deploy
    spec:
      containers:
      - image: pengbai/docker-supermario:latest
        name: docker-supermario
        ports:
        - containerPort: 8080
        resources: {}
status: {}

Veamos un poco que es lo que tenemos aquí:

  • metadata: Ya hemos visto en el resto de posts que es esto. Contiene labels identificativos que nos pueden ser utiles para hacer referencia desde otros objetos del cluster de kubernetes. Y también tiene su name para identificar este objeto como tal.

Dentro del spec, que recordemos que es donde realmente se define la magia tenemos nuevo:

  • replicas: Creo que es autoexplicativo. Podemos indicar la cantidad de instancias que queremos de un tipo de POD.
  • selector: Al igual que pasaba con el objeto de tipo service, dentro de este selector indicamos los labels que tienen los pods que debe gestionar este objeto de tipo deployment.
  • template: Aquí es donde definimos el POD en cuestión que tiene que usar como plantilla, es decir, usando un objeto de tipo deployment ya no es necesario tener por otro lado un objeto de tipo POD, puede estar definido dentro de esta template (si los comparamos la definión debe ser muy similar)

Una vez repasadas más o menos las diferencias veamos que pasa, cambiemos la cantidad de replicas a 2 y ejecutemos el típico create

Captura-de-pantalla-2021-01-16-a-las-20.05.28

Si comprobamos los pods que tenemos ahora veremos algo distinto

Captura-de-pantalla-2021-01-16-a-las-20.07.34

Vemos como ahora ahora los pods se crean de otra manera, contienen el nombre del objeto deploy y además una conjunto alfanumerico, eso convierte el nombre del pod un identificador único. Además de comprobar los pods, ahora podemos usar otro comando específico para deployments

kubectl get deployments

Captura-de-pantalla-2021-01-16-a-las-20.10.29

Que como podemos comprar nos muestra cuando pods tiene el deployment, cuandos estan activos y cuantos estan actualizados con la última versión (ya hablaremos de esto). Si ahora nosotros eliminamos uno de los pods, veremos como automáticamente nos crea uno nuevo.

Captura-de-pantalla-2021-01-16-a-las-20.12.43

Kubernetes, como siempre, en su ciclo de vida (llamada bucle de reconciliación) comprueba que el estado de los objetos que están en funcionamiento cumple con sus definiones/plantillas y si no, pues actua en consecuencia, en este caso con la creación de un nuevo POD usando la plantilla que tiene el objeto de tipo deployment.

Pero claro ahora mismo hemos definido de antemano el número de replicas que queremos de un mismo POD dentro de la plantilla de deploy, pero... ¿y si tengo que escalar mi aplicación ahora mismo entando en producción? pues para ello tenemos varias opciones:

  • Editar el estado actual de nuestro deploy en la API
kubectl edit deploy mario-deploy

Nos aparecerá la definición que está actualmente en la API de kubernetes, lo que podemos hacer es editar el número de réplicas y esto nos debería escalar el número de instancias de pods

  • Otra forma es usando el comando scale
kubectl scale deployment mario-deploy --replicas=3

En cualquiera de los 2 casos si comprobamos los pods que tenemos deberían haber aumentado

Captura-de-pantalla-2021-01-16-a-las-20.28.51

Y lo mismo podemos hacer para reducirlos, si disminuimos el número de replicas nos eliminará el número de instancias activas

kubectl scale deployment mario-deploy --replicas=1

Comprobamos que empieza con la eliminación de 2 de las instancias y al final nos deja solo con una

Captura-de-pantalla-2021-01-16-a-las-20.30.59

Actualizando versiones de nuestra aplicación y rollback

Todo lo que hemos visto en este post está muy bien, pero normalmente ninguna aplicación se mantiene en la misma versión para siempre, como tal, es necesario actualizarla en algún momento, en esta sección veremos como cambiar la versión de nuestra imagen y también como hacer rollback en caso de que algo falle. Todo esto es realmente sencillo gracias a kubernetes.

Primero de todo vamos a seleccionar una imagen que tenga varias versiones, para no complicarnos creando nosotros un contenedor específico me he decantado por usar la imagen oficial de NGINX, como se puede ver entre los tags de versiones tenemos dos que son fáciles de diferencias stable y latest

Captura-de-pantalla-2021-01-16-a-las-21.06.18

Primero creemos nuestro deployment con la imagen stable, para ello crearemos un fichero yaml con estos datos

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx-deploy
  name: nginx-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-deploy
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx-deploy
    spec:
      containers:
      - image: nginx:stable 
        name: nginx-pod 
        ports:
        - containerPort: 80
        resources: {}
status: {}

Como véis tenemos 2 replicas de la versión nginx:stable, ejecutemos el comando crear y comprobemos que pasa (recomiendo eliminar todo lo que hicimos anteriormente, recordar con kubectl delete ....)

kubectl create -f nginx-deploy.yaml

Captura-de-pantalla-2021-01-16-a-las-21.10.17

Ya tenemos nuestros 2 pods que hemos definido en el deploy, ahora comprobemos la versión con la que se han creado con el comando describe

kubectl describe deploy nginx-deploy

Captura-de-pantalla-2021-01-16-a-las-21.11.36

Si nos fijamos tenemos dentro de containers la imagen seleccionada que es nginx:stable, ahora veamos las opciones para actualizar de versión

  1. Usar el comando apply
    Tenemos la posibilidad de actualizar la configuración actual de un objeto en kubernetes usando el comando apply, modificando nuestro fichero de deploy. Cambiemos la versión en nuestro fichero
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: nginx-deploy
  name: nginx-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-deploy
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx-deploy
    spec:
      containers:
      - image: nginx:latest 
        name: nginx-pod 
        ports:
        - containerPort: 80
        resources: {}
status: {}

Y ejecutemos el comando

kubectl apply -f nginx-deploy.yaml

Si ahora ejecutamos nuestros comandos get pods y describe veremos como tenemos otra versión ya desplegada.

Captura-de-pantalla-2021-01-16-a-las-21.18.58

  1. Es posible, al igual que hicimos antes, usar el comando edit, para modificar el estado actual que está en la api de kubernetes (en teoría funciona pero a mi me da problemas, aviso por si acaso)
kubectl edit deploy nginx-deploy
  1. Tenemos la opción de modificar directamente la imagen de un deployment con la opción set
kubectl set image deployments/nginx-deploy nginx-pod=nginx:latest

Este comando indicamos que modifique la imagen dentro del deployment/nginx-deploy de los pods con nombre nginx-pod usando la imagen nginx-latest. Si nos fijamos en nuestra definición de nuestro objeto deployment el nombre que yo le he puesto es el de nginx-pod

Si comprobaramos nuestros ya típicos get pods y describe otra vez veríamos lo siguiente

Captura-de-pantalla-2021-01-16-a-las-21.26.13

Otra vez de nuevo nos ha cambiado la versión correctamente.

Como tal tenemos otro comando para comprobar que la actualización ha ido correctamente que es el comando rollout

kubectl rollout status deployment nginx-deploy

Captura-de-pantalla-2021-01-16-a-las-21.28.29

Este comando nos confirma que la actualización ha ido correctamente.

Haciendo rollback

Ya hemos visto como actualizar pero... ¿y si todo se ha roto al actualizar y queremos volver atras? Pues en este caso es tan sencillo como...

kubectl rollout undo deployment nginx-deploy

Et voilá

Captura-de-pantalla-2021-01-16-a-las-21.31.00

Nuestra versión vuelve a ser la de nginx:stable. Creo que en este caso no tengo mucho más que decir, solo comentar que esto se podría automatizar con los healthchecks que vimos en post anteriores (revisar la doc oficial que yo no he entrado en tanto detalle de momento), esto han sido unos primeros pasos para ver como lo podemos hacer nosotros todo manualmente.

No me enrollo más, espero que os haya gustado este post con el escalado y el rollback de nuestras aplicaciones, sin mucho más nos vemos en el siguienteeeee un abrazoooor