Orquestación de contenedores
Contenido
- 1 Paso 1: Minikube: versión reducida de Kubernetes
- 2 Paso 2: Crear máquina virtual
- 3 Paso 3: Iniciar máquina virtual e instalar dependencias
- 4 Paso 4: Instalación de kubernetes
- 5 Paso 5: Iniciar un cluster de minikube
- 6 Paso 6: Crear un deployment
- 7 Paso 7: Crear un servicio
- 8 Paso 8: Eliminando deployment, pods y services
- 9 Paso 9: Creando deployments y services desde ficheros
Paso 1: Minikube: versión reducida de Kubernetes
Minikube es una versión reducida de Kubernetes para poder ejecutar todo en la misma máquina y no necesitar 3 nodos como necesita Kubernetes.
Para poder instalar minikube necesitaremos una nueva máquina virtual con los siguientes requisitos:
- Disco de mayor tamaño tamaño que los creados hasta ahora, unos 10-15 GB
- Al menos 2 CPU y 2GB de memoria RAM
- docker instalado
- kubectl instalado
Puedes descargar la imagen como se describe en el Virtualización con libvirt. Esta imagen ocupa 2 Gbytes únicamente, para redimensionar la imagen, puedes seguir lo descrito en el Paso 9 de Sistemas de archivos.
Paso 2: Crear máquina virtual
Lo segundo será crear una máquina virtual, utilizando las imágenes creadas en el paso anterior y también muy importante, que la configuración de CPU sea igual o mayor a 2 y la memoria igual o mayor a 2048 MB.
Los pasos serán similares a los de la práctica 1, Paso 4, teniendo en cuentas los cambios de la configuración.
Paso 3: Iniciar máquina virtual e instalar dependencias
Kubernetes require docker. Instala docker en la máquina virtual como se describe en Contenedores con Docker, a partir del paso 1.
Paso 4: Instalación de kubernetes
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt install kubectl
Instalar minikube:
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo mv minikube /usr/local/bin/
sudo chmod +x /usr/local/bin/minikube
Paso 5: Iniciar un cluster de minikube
Con todas las dependencias instaladas, vamos a crear nuestro primer cluster de minikube. Vamos a utilizar una opción que tiene minikube para que el cluster, en vez de montarlo en una máquina virtual, lo monte en el propio sistema, porque sino el cluster estaría en una máquina virtual, dentro de otra máquina virtual.
sudo minikube start --vm-driver=none
Como nos dice en la salida si todo ha ido bien, vamos a darle permisos a nuestro usuario para poder ejecutar kubectl:
sudo mv /home/ubuntu/.kube /home/ubuntu/.minikube $HOME
sudo chown -R $USER $HOME/.kube $HOME/.minikube
Ahora, veremos la información del cluster que acabamos de crear:
kubectl cluster-info
Deberíamos de obtener una salida similar a:
Kubernetes master is running at https://192.168.122.46:8443
KubeDNS is running at https://192.168.122.46:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Paso 6: Crear un deployment
Un deployment es un controlador para los pods, que asegura que los pods tengan una correcta configuración y que exista el número correcto de ellos.
Un pod es un objeto de kubernetes que ejecuta uno o más contenedores.
Vamos a crear una imagen Docker de ejemplo a partir de python. Creamos el fichero endpoint.py con el siguiente contenido:
import hug
@hug.get('/welcome')
def welcome(username="unknow"):
""" Say welcome to username """
return "Welcome " + username
Creamos el fichero Dockerfile con el siguiente contenido:
FROM python:alpine
RUN mkdir /app
RUN pip install hug
COPY endpoint.py /app
WORKDIR /app
CMD hug -f endpoint.py
Ahora vamos a construir nuestra imagen y comprobar que se ha creado:
sudo docker build -t app:v1 .
docker images
Ahora utilizaremos esta imagen para crear un deployment:
kubectl create deployment my-server --image=app:v1
Ahora comprobaremos que el deployment está bien creado:
kubectl get deployments
También comprobaremos que el deployment ha creado un pod:
kubectl get pods
que muestra un status running que indica éxito al crear el deployment:
NAME READY STATUS RESTARTS AGE
my-server-7c7cc5b4-gwtx7 1/1 Running 0 17m
Si el status muestra ImagePullBackOff, probablemente hemos especificado una imagen Docker inexistente. Para depurar problemas, podemos emplear la orden describe:
kubectl describe pod my-server
que mostrará algo parecido a:
Name: my-server4-7c7cc5b4-gwtx7
Namespace: default
Priority: 0
Node: minikube/192.168.122.52
Start Time: Wed, 15 Jan 2020 15:58:10 +0000
Labels: app=my-server4
pod-template-hash=7c7cc5b4
Annotations: <none>
Status: Running
IP: 172.17.0.7
IPs:
IP: 172.17.0.7
Controlled By: ReplicaSet/my-server4-7c7cc5b4
Containers:
miapp:
Container ID: docker://1458bd042e0b1447f619c595241aaab9edf7f7101c4e6c1ec8d1f43a49ba43d2
Image: miapp:v1
Image ID: docker://sha256:9781b807af04b0586588f365252ef9a2583c4b6da6cd0e6f1949d46896b9f959
Port: <none>
Host Port: <none>
State: Running
Started: Wed, 15 Jan 2020 15:58:11 +0000
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-wwcpg (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
default-token-wwcpg:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-wwcpg
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 13m default-scheduler Successfully assigned default/my-server4-7c7cc5b4-gwtx7 to minikube
Normal Pulled 13m kubelet, minikube Container image "miapp:v1" already present on machine
Normal Created 13m kubelet, minikube Created container miapp
Normal Started 13m kubelet, minikube Started container miapp
En particular, la parte de Events nos da pistas sobre qué puede haber ido mal. El ejemplo de arriba muestra que el deployment my-server que emplea la imagen miapp se ha lanzado con éxito.
Paso 7: Crear un servicio
Por defecto, un pod es accesible solo internamente desde el cluster, para hacerlo accesible hacía fuera, necesitaremos crear un servicio que exponga el el deployment:
kubectl expose deployment my-server --type=LoadBalancer --port=8000
Es importante que el puerto especificado con --port indique el puerto del servidor que se crea en el deployment. El puerto 8000 es empleado por python hug en el ejemplo de unos de los pasos anteriores.
Comprobaremos que se ha creado correctamente:
kubectl get services
Veremos una salida similar a la siguiente:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4h25m
my-server LoadBalancer 10.103.110.240 <pending> 8000:32607/TCP 5s
Veremos en la parte de puerto que el puerto 8000 interno lo está exponiendo en el 32607, así que vamos ahora a comprobar si esto funciona:
curl -X GET http://localhost:32607/welcome?username=LSO
Ya tenemos con kubernetes creado un deployment que está ejecutando un pod y se está exponiendo a través de un servicio.
Paso 8: Eliminando deployment, pods y services
Eliminemos primero el servicio:
kubectl delete service my-server
Comprobamos que ya no existe:
kubectl get services
Ahora vamos a intentar eliminar un pod y ver lo que ocurre. Para eliminarlo, vamos a listar los pods primero para saber el nombre:
kubectl get pods
Tenemos la siguiente salida:
NAME READY STATUS RESTARTS AGE
my-server-bc9b8955b-llkth 1/1 Running 0 27m
Vamos a eliminar el pod:
kubectl delete pod my-server-bc9b8955b-llkth
Ahora veamos que ha pasado:
kubectl get pods
Tenemos la siguiente salida:
NAME READY STATUS RESTARTS AGE
my-server-bc9b8955b-p82qc 1/1 Running 0 27m
Hemos borrado un pod, pero ahora hay otro levantado. Esto ocurre por que el deployment es el encargado de asegurar que siempre haya un pod levantado, así que lo eliminamos o falla por cualquier motivo, el deplyment levantá otro automáticamente. Esta es la magia de kubernetes, se da por hecho que los sistemas van a fallar y no vamos a tener tiempo para arreglarlos, así que lo que hacemos es olvidarnos del que está fallando o el que se ha eliminado y levantar uno nuevo.
Pasemos ahora a eliminar el deployment:
kubectl delete deployment my-server
Veamos si verdaderamente se ha eliminado:
kubectl get deployments
Vemos que el deplyment si es eliminado.
Paso 9: Creando deployments y services desde ficheros
Desde línea de comandos podemos realizar todo lo necesario, aunque lo recomendable para kubernetes es crear ficheros de configuración y aplicarlos.
Paso 9.1: Creando deployment a partir de fichero
Veamos un ejemplo para crear un deployment, para ello creamos el fichero deployment.yml:
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-container
image: app:v1
ports:
- containerPort: 8000
resources:
limits:
cpu: "0.1"
volumeMounts:
- mountPath: /home/ubuntu/data
name: data
Comentamos el fichero por línea:
- apiVersion: es la versión de la API utilizada para definir este fichero
- kind: el tipo de objeto de kubernetes, puede ser un Pod, Service o un Deployment
- metadata: esto nos sirve para dar información al deployment
- spec: aquí añadiremos la especificación del deployment
- replicas: añadiremos la cantidad de réplicas/pods que habrá dentro del deployment
- template: definimos el pod aquí
- spec: especificación del pod
- containers: especificación del contenedor (nombre, imagen, puerto, volumen).
También podremos añadir la cantidad de recursos que consumirá el contenedor
Pasemos a crear el deployment creado:
kubectl create -f deployment.yml
Ahora veremos lo que ha creado:
kubectl get deployments
Aquí tenemos un deployment, el cual vemos que tiene dos pods, vamos a verlos:
kubectl get pods
Ahora, veamos que podemos modificar un fichero, aplicar los cambios, y estos se apicarán rápidamente. Vamos a modificar el fichero deployment.yml y vamos a poner 3 réplicas en vez de 2, después aplicamos los cambios y observamos
kubectl apply -f deployment.yml
kubectl get pods
Si hacemos rápidamente los dos comandos, veremos que rápidamente kubernetes se pone a crear otro pod más:
NAME READY STATUS RESTARTS AGE
my-deployment-7595cb9c96-7wq46 0/1 ContainerCreating 0 2s
my-deployment-7595cb9c96-jb97b 1/1 Running 0 16m
my-deployment-7595cb9c96-x465b 1/1 Running 0 16m
Unos segundos después, ya está todo corriendo:
NAME READY STATUS RESTARTS AGE
my-deployment-7595cb9c96-7wq46 1/1 Running 0 5s
my-deployment-7595cb9c96-jb97b 1/1 Running 0 16m
my-deployment-7595cb9c96-x465b 1/1 Running 0 16m
Podemos hacer ahora el cambio del revés y ver como kubernetes se encargará de dejar de nuevo dos réplicas y parará una de las que estén corriendo.
Paso 9.2: Creando services desde fichero
Ahora veamos como crear un servicio con ficheros de configuración, ya que un deployment sin servicio no nos servirá de mucho. Fichero service.yml:
---
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 8000
type: LoadBalancer
Como vemos, los datos son muy similares a los anteriores escritos en el fichero deployment.yml, aquí una de las cosas más importantes es el selector, que es donde tendremos que elegir el la app correcta. Después, también ver que en los puertos, le hemos dicho que el 8000 es por donde sale la información, kubernetes ya se encargará de exponerlo en algún puerto que lueggo veremos.
Vamos a ejecutar el servicio:
kubectl create -f service.yml
Ahora veamos el servicio:
kubectl get services
Aquí veremos nuestro servicio corriendo:
my-service LoadBalancer 10.104.207.24 <pending> 8000:30819/TCP 1m
Y veremos que el puerto al que está expuesto es el 30819, vamos a realizar una petición para ver si funciona correctamente:
curl -X GET http://localhost:32607/welcome?username=LSO
También podremos ver desde fuera de nuestra máquina virtual, en nuestra máquina host, corriendo este servicio. Hacemos un ifconfig para ver nuestra ip, y una vez que la sepamos, accedemos con nuestro navegador a la dirección:
http://NUESTRA_IP:30819/welcome?username=LSO
Por último veamos de nuevo que funciona correctamente el deployment, y siempre vamos a tener ejecutándose el número de réplicas correcto y el servicio no dejará de funcionar. Mantegamos abierto el navegador, y hagamos lo siguiente en nuestra máquina virtual:
kubectl get pods
Vamos a borrar todos los pods y, seguidamente, comprobamos en nuestro navegador si sigue funcionando el servicio:
kubectl delete pod my-deployment-7595cb9c96-9pz4c my-deployment-7595cb9c96-dzxnt my-deployment-7595cb9c96-mq6pn
Veremos que el servicio sigue funcionando en todo momento, y si revisamos, veremos que tendremos de nuevo la cantidad correcta de pods funcionando:
kubectl get pods
Finalmente, vamos a apagar nuestro cluster:
sudo minikube stop