En este post expondremos una breve introducción al orquestador de contenedores Kubernetes (K8s). Te recomendamos tener conocimientos básicos de Docker para tener una visión global de lo que son los contenedores y porque que en este post se usará Docker como sistema de contenedores.
- ¿Qué es Kubernetes?
- Conceptos básicos
- Clúster
- Pod
- Servicio
Instalación
- Común
- Inicialización del clúster
- Añadir trabajadores
- Haciendo pruebas
- Eliminar recursos
Qué es Kubernetes?
Según la documentación de Kubernetes:
Kubernetes es una plataforma de código abierto para automatizar la implementación, el escalado y la administración de aplicaciones en contenedores.
Para entrar más en detalle con la definición, Kubernetes es un sistema de control del ciclo de vida de contenedores usando distintos métodos que permiten tener un alto nivel de disponibilidad y escabilidad, entre otras características.
Conceptos básicos
Clúster
Un clúster es un conjunto de ordenadores. En nuestro caso será un clúster de Kubernetes y cada ordenador tendrá un rol, que pueden ser dos:
- Máster: solo hay uno en el conjunto y es el que se encarga de repartir la carga de trabajo entre los demás nodos, mantener el estado deseable de trabajo, escalar las aplicaciones o actualizarlas.
- Trabajador: los demás nodos que no son máster. Son los que ejecutan las aplicaciones por medio de contenedores. El mínimo número de trabajadores deseables es 3.
La comunicación entre el máster y los trabajadores se hace por medio de la API de Kubernetes, a través del máster (aunque también los usuarios finales pueden interactuar con la API). Los trabajadores son conectados al máster por medio del proceso kubelet.
Un clúster de Kubernetes puede ser implementado en una máquina física o en una máquina virtual. También es posible usar Minikube, una implementación ligera de Kubernetes que crea una máquina virtual localmente con un solo trabajador.
Pod
Es la mínima unidad de ejecución de Kubernetes. Representa procesos en ejecución en el clúster. Un Pod contiene uno o varios contenedores (de Docker, por ejemplo) y administra los recursos de la aplicación, dirección IP y distintas opciones que determina como funcionan los contenedores.
Servicio
Es una abstracción que define un conjunto de pods los cuales ejecutan un micro-servicio como puede ser el frontend.
Los pods son finitos, es decir, “nacen” y “mueren” pero no pueden “resucitar”. Se crean y eliminan a lo largo de la ejecución del Deployment. Cada pod tiene su dirección IP propia, por lo que las direcciones IP de los pods que se ejecutan en un momento determinado serán diferentes que las que se ejecuten en otro instante. Esto supone un problema dado que querremos tener una dirección IP fija a la hora de acceder a los pods. Por ello existe el concepto de servicio, para solucionar este problema.
Instalación
Como se ha dicho anteriormente, necesitamos tener un servidor que actúe como máster y uno como trabajador, por lo que al menos necesitaremos 2 servidores VPS. La imagen a seleccionar a la hora de inicializarlos será la de Docker, en este caso se usará sobre Ubuntu 18.04. Para no tener problemas, los servidores deben tener al menos dos procesadores, aunque se puede forzar con menos pero puede que el rendimiento no sea el deseado.
Común
Las siguientes dependencias y el propio Kubernetes hay que instalarlos en todas las máquinas que forman el clúster, independientemente de su rol en él.
- Desactivar swap:
# swapon -s && swapoff -a
Para desactivar la partición swap de forma permanente, abrimos el fichero /etc/fstab (con vim, por ejemplo) y comentamos la línea correspondiente a la partición swap, como la siguiente imagen:
- Inicialización del servicio de Docker y programarlo al inicio:
# systemctl enable docker.service && systemctl start docker.service
- Actualizar sistema:
# apt update && apt upgrade -y && apt dist-upgrade -y
- Dependencias (por si acaso no estuvieran ya instaladas):
# apt install -y apt-transport-https
- Importar la clave del repositorio de Kubernetes:
# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add
- Añadir repositorio:
# echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list
- Instalar Kubernetes:
# apt update && apt install -y kubeadm kubelet kubectl
Inicialización del clúster
Ahora vamos a inicializar el clúster en el nodo que actúa como máster. Para ello, debemos ejecutar las siguientes órdenes solo en el máster:
# kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address DIRECCION_IP_MASTER
Donde DIRECCION_IP_MASTER es la IP pública de nuestro VPS máster.
Si nos da el siguiente error por culpa del número de procesadores:
([ERROR NumCPU]: the number of available CPUs 1 is less than the required 2)
podemos ejecutarlo igualmente aunque lógicamente el rendimiento será menor añadiendo la siguiente opción a la orden anterior:
--ignore-preflighterrors=NumCPU.
Si todo ha ido bien, deberíamos obtener un mensaje como éste (puede que tarde varios minutos en ejecutar todas las órdenes):
Deberemos copiar la orden que empieza por “kubeadm join …” (al final del mensaje) dado que es la que nos va a permitir añadir nodos a nuestro clúster.
- Configurar el clúster: debemos crear una nueva configuración para el clúster en el directorio $HOME/.kube. Para ello, podemos copiar la que tiene por defecto Kubernetes con las siguientes órdenes:
# mkdir -p $HOME/.kube
# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# chown $(id -u):$(id -g) $HOME/.kube/config
Desplegar el flannel para administrar las direcciones IP de los contenedores dado que Kubernetes asume que cada pod tiene su IP única:
# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
Para comprobar los nodos activos y los pods y su estado, ejecutamos las siguientes dos órdenes, respectivamente:
# kubectl get nodes
# kubectl get pods --all-namespaces
Antes de añadir nodos, debemos añadir las normas en el firewall. En mi caso, he decidido permitir todo el tráfico TCP entre trabajador y máster con la siguiente configuración, donde la IP que aparece es la del trabajador:
Añadir trabajadores
Para añadir un nuevo nodo al clúster, es necesario disponer de la orden “kubectl join …” dicha anteriormente ya que tiene la clave para añadir un nodo:
# kubeadm join 85.208.20.82:6443 --token *** --discovery-token-ca-cert-hash sha256: ***
Donde los asteriscos son las claves concretas.
Después de varios minutos, deberemos tener el siguiente mensaje, que confirmará que todo ha ido como se esperaba:
Podemos comprobar que el nodo se ha añadido al clúster desde el máster, ejecutando de nuevo
# kubectl get nodes
Haciendo pruebas
Ya que tenemos al menos un nodo, podemos comprobar si este funciona correctamente. Para ello vamos a desplegar una simple página web de nginx.
- Creamos la carpeta en el trabajador donde se va a alojar nuestro servidor web:
# mkdir -p nginx/
# cd nginx/
- Debemos crear un archivo YAML con la configuración que deseamos, por ejemplo el siguiente:
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 # imagen y versión a usar
ports:
- containerPort: 80 # puerto en el que se ejecuta, por defecto para un servidor HTTP es el 80
Y lo guardamos en un archivo con extensión .yaml, por ejemplo en nginx.yaml.
- Creamos un nuevo recurso a partir del YAML:
# kubectl create -f nginx.yaml
Y recibiremos el siguiente mensaje:
deployment.apps/nginx-deployment created
Podemos ver los despliegues y su estado con la siguiente orden:
# kubectl get deployments
lo que nos devolverá:
También podemos obtener más información acerca de un recurso en concreto, podemos ejecutar:
# kubectl describe deployment DESPLIEGUE
donde DESPLIEGE en nuestro caso es nginxdeployment:
- Después del despliegue se han creado dos pods más (dado que hemos puesto replicas: 2), lo que podemos comprobar fácilmente con la orden anteriormente vista:
# kubectl get pods
Y, como es lógico, obtener más información de cada pod con:
# kubectl describe pod POD
donde POD es el nombre obtenido en la orden anterior.
Para terminar, es necesario crear un servicio ya que si no no veremos el resultado de nuestro servidor HTTP.
- Creamos un archivo YAML con el siguiente
<ahref=”https://raw.githubusercontent.com/kubernetes/website/master/content/en/examples/service/networking/nginx-svc.yaml”>contenido en nginx-svc.yaml:
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
run: nginx-svc
spec:
type: NodePort
ports:
- port: 80
protocol: TCP
selector:
app: nginx
- Creamos el servicio igual que antes con:
# kubectl create -f nginx-svc.yaml
Vemos la lista de servicios con:
# kubectl get service
Como se ve en la lista, el puerto a través del que tenemos que acceder al servidor web no es el 80, sino el 31890 (en mi caso)por lo que a la hora de escribirlo en la barra de direcciones de un navegador web tendremos que poner http://IP:PUERTO y quedará el siguiente resultado:
Eliminar recursos
A la hora de eliminar distintos tipos de recursos, pods o servicios, es posible sabiendo el identificador del mismo con la orden “kubectl delete”:
- Servicios:
# kubectl delete svc/SERVICIO
- Pods:
# kubectl delete pod/POD
- Desplegables:
# kubectl delete deployment/DEPLOYMENT
Autor: David Población.