Ejecutar contenedores de Docker en Kubernetes

Ya hemos visto cómo tener un primer entorno de Kubernetes en nuestro local utilizando VirtualBox. El siguiente paso es ver cómo se trabaja con contenedores de Docker en este tipo de clúster. Hoy quiero contarte algunos conceptos básicos y cómo aplicarlos a tu nuevo entorno.

Algunos conceptos

Es posible que si vienes de trabajar directamente con Docker, o con Swarm puedas perderte un poco con los nuevos conceptos que te encontrarás en Kubernetes. Para empezar, creo que estos son los más importantes:

  • Nodos: son las máquinas, virtuales o no, que forman parte de nuestro clúster.
  • Pods: son uno o más contenedores que comparten red y son como una unidad. Cuando se despliegan todos los contenedores del pod caen en un mismo nodo. Se puede decir que es la forma de agrupar contenedores dentro de Kubernetes.
  • Despliegues: un despliegue está por encima de los pods y supervisa el estado del mismo, el número de réplicas, etcétera.
  • Servicios: es una abstracción de los pods, que proporciona una IP virtual y un nombre. Existen diferentes tipos de servicio, que nos ayudarán a que otros pods o desde el exterior puedan conectarse al conjunto lógico que define. El tipo por defecto es ClusterIP, con el que el servicio sólo es accesible desde dentro del clúster, y es el que veremos en este artículo.

Desplegar una aplicación en Kubernetes

Las operaciones sobre Kubernetes se llevan a cabo a través del comando kubectl, al igual que para swarm utilizábamos docker-compose. Cuando se despliega una aplicación lo que normalmente se hace es un despliegue. Rara vez se crean pods directamente, ya que estaríamos perdiendo esa capa donde se especifica el estado deseado de nuestros pods. Sin embargo, vamos a crear de los dos tipos para que veas la diferencia.

Crear un pod

La forma más sencilla para ejecutar un pod es a través de kubectl run, al igual que en docker utilizamos docker run:

kubectl run hello-world-pod --image=gcr.io/google-samples/hello-app:2.0 --generator=run-pod/v1

Para ver si se está ejecutando correctamente, y dónde, puedes utilizar el siguiente comando:

kubectl get pods -o wide

Verás que aparece el estado del mismo, qué IP tiene el pod dentro de nuestro clúster y además en qué nodo está desplegado.

Este servicio sólo es visible desde la red interna del clúster. Por lo que desde el master podemos hacer uso de cURL para acceder al contenido que está sirviendo:

curl http://10.0.1.2:8080

Este comando sólo generará un pod pero no un despliegue, por lo que no hay nadie que cuide de él mas que nosotros. Si ejecutamos el siguiente comando verás que no tenemos ningún despliegue relacionado con el mismo.

kubectl get deployments

Crear un despliegue

Para crear un despliegue podemos utilizar el comando kubectl apply y asociarle un archivo yaml que contenga todos los parámetros necesarios para el mismo, como hacíamos con docker-compose en Swarm. El formato que tiene este archivo yaml difiere un poco de lo que hemos visto hasta ahora:

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

Puedes ver que el tipo que contiene este YAML es de tipo Deployment, que vamos a crear tres réplicas y que la imagen a utilizar es nginx. La forma de lanzarlo es la siguiente (te lo he dejado en mi GitHub para que te sea más fácil):

kubectl apply -f https://raw.githubusercontent.com/0GiS0/kubernetes-scripts/master/deployments/nginx-deployment.yaml

Si ahora consultas tus pods verás que aparecen cuatro:

kubectl get pods -o wide

El primero de ellos es el que lanzamos como pod y los otros tres se corresponden con el despliegue de Nginx que acabamos de realizar.

Si quisiéramos, podríamos acceder a cada uno de los pods de Nginx de la misma forma que hicimos con el pod de hello-world-pod a través de cURL:

curl http://10.0.2.2
Accediendo a uno de los pods de Nginx

Pero como te puedes imaginar, lo ideal es que tuviéramos un balanceador por delante que nos permitiera el acceso al despliegue en sí, no a los pods directamente, ya que estos son efímeros y en cualquier momento pueden desaparecer. Para ello, entra en juego el último concepto que te expliqué al inicio del artículo: el servicio. Este se crea a través del comando kubectl expose, que por defecto será de tipo ClusterIP, y se debe especificar el puerto por el cual queremos acceder.

kubectl expose deployment nginx-deployment --port=8000

Para que veas bien la diferencia, he expuesto mi despliegue a través del puerto 8000 del servicio, aunque el puerto por el que se accederá a los pods será el 80. Al hacer esto, si visualizamos los servicios que tenemos disponibles veremos lo siguiente:

kubectl get services

Si ahora accedemos a través de cURL a la IP del clúster que se nos ha asignado para nuestro servicio nginx, verás que podemos acceder sin problemas a cualquiera de las replicas de nuestro despliegue.

curl 10.101.27.18:8000

Configurar el autocompletado de comandos

Para terminar por hoy, creo que es bastante útil que configures el autocompletado de comandos, ya que te será más fácil a la hora de trabajar con kubectl. Para hacerlo, ejecuta las siguientes líneas en tu máster.

sudo apt-get install bash-completion
echo "source <(kubectl completion bash)" >> ~/.bashrc
source ~/.bashrc

Simplemente tienes que pulsar tab, una o dos veces, para que autocomplete o te muestre las opciones disponibles.

¡Saludos!