kubeadm te permite crear un clúster mínimo viable de Kubernetes. Entre sus ventajas destacan su sencillez, su disponibilidad en prácticamente cualquier sistema y su integración con el aprovisionamiento automatizado y la gestión del ciclo de vida del clúster. Además, garantiza clústeres consistentes e interoperables dentro del Certified Kubernetes Conformance Program.
En la práctica, crear y operar un clúster de Kubernetes implica mucho más que gestionar sus componentes por separado: requiere prestar atención a numerosos detalles y seguir una secuencia ordenada de pasos, a menudo dispersos en distintas fuentes de documentación. En esta guía recorremos, paso a paso, el proceso completo de bootstrapping de un clúster con los siguientes componentes y versiones:
- Ubuntu 22.04.3 LTS
- Docker Engine 24.0.6
- cri-dockerd 0.3.4
- Kubernetes 1.27.5
- Calico 3.26.1
Este artículo asume que ya estás familiarizado con los componentes de un clúster de Kubernetes y está pensado como guía práctica.
Antes de comenzar
Antes de comenzar, asegúrate de que cada nodo que forme parte del clúster tenga configuradas las opciones necesarias para que los componentes funcionen correctamente.
Reenviar IPv4 y permitir que iptables vea el tráfico bridged
Los pods deben comunicarse de forma transparente en todo el clúster, independientemente del nodo donde estén desplegados, por lo que cada nodo debe tener habilitado el reenvío de tráfico. También es necesario asegurarte de que la superposición del sistema de archivos necesaria para componer las capas del contenedor esté disponible.
Crea un archivo que contenga los nombres de los módulos del kernel que deben cargarse en el momento del arranque:
1
2
3
4
cat << EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
Luego, carga los módulos del kernel:
1
2
sudo modprobe overlay
sudo modprobe br_netfilter
Verifica que los módulos estén cargados:
1
2
lsmod | grep br_netfilter
lsmod | grep overlay
Ahora crea un archivo que contenga la configuración de las variables del sistema que deben cargarse en el momento del arranque:
1
2
3
4
5
cat << EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
Aplica los parámetros del kernel en tiempo de ejecución para que los cambios anteriores surtan efecto sin reiniciar:
1
sudo sysctl --system
Finalmente, verifica que las variables del sistema estén configuradas en 1 en tu configuración de sysctl:
1
sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward
Verificación de la unicidad de MAC y product_uuid
Algunos componentes utilizan el ID del adaptador de red (dirección MAC) y/o el ID de la placa base (product_uuid) para identificar de forma exclusiva los nodos.
Verifica que la dirección MAC sea única para cada nodo:
1
ip link
Verifica que product_uuid sea único para cada nodo:
1
sudo cat /sys/class/dmi/id/product_uuid
Comprobación de los puertos necesarios
Cuando ejecutes Kubernetes en un entorno con límites de red estrictos, ten en cuenta los puertos y protocolos utilizados por tus componentes y verifica que estén abiertos para permitir la comunicación entre ellos.
En el plano de control/nodo(s) maestro(s):
1
nc -zv 127.0.0.1 6443 2379-2380 10250 10259 10257
En los nodos trabajadores:
1
nc -zv 127.0.0.1 10250 30000-32767
Deshabilitar la memoria de intercambio
Los componentes del clúster están diseñados principalmente para ofrecer rendimiento y fiabilidad. El uso de memoria de intercambio bajo presión del disco hace que estos objetivos sean más difíciles de lograr de forma predecible.
Deshabilita el intercambio en todos los dispositivos y archivos de intercambio conocidos:
1
sudo swapoff -a
Comprueba que el área de intercambio ha sido deshabilitada:
1
free -h
Elimina el archivo de intercambio innecesario:
1
sudo rm /swap.img
Finalmente, comenta toda la línea en el archivo fstab para evitar que el espacio de intercambio se monte de forma permanente al inicio:
1
2
3
sudo vi /etc/fstab
...
# /swap.img none swap sw 0 0
Instalación del tiempo de ejecución del contenedor
Instalación de Docker Engine
A continuación, instala un container runtime compatible con la interfaz de tiempo de ejecución de contenedor (CRI) para que los pods y contenedores puedan ejecutarse en cada nodo del clúster.
Ya que vas a instalar Docker Engine, agrega la clave GPG oficial de Docker:
1
2
3
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
Configura el repositorio:
1
2
3
4
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Actualiza el índice del paquete apt e instala los paquetes que permiten a APT usar un repositorio a través de HTTPS:
1
sudo apt update && sudo apt install -y ca-certificates curl gnupg
Instala Docker Engine, Containerd y Docker Compose:
1
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Para instalar una versión específica, primero verifica las versiones disponibles para cada paquete:
1 2 3 4 5 apt list -a docker-ce | awk '{print $2}' apt list -a docker-ce-cli | awk '{print $2}' apt list -a containerd.io | awk '{print $2}' apt list -a docker-buildx-plugin | awk '{print $2}' apt list -a docker-compose-plugin | awk '{print $2}'Y luego indique dicha versión en el comando de instalación:
1 sudo apt install -y docker-ce=<version> docker-ce-cli=<version> containerd.io=<version> docker-buildx-plugin=<version> docker-compose-plugin=<version>
Agrega tu usuario al grupo de Docker para administrar Docker como usuario no root:
1
sudo usermod -aG docker $USER
Vuelve a evaluar los grupos para activar los cambios sin tener que cerrar sesión e iniciar sesión de nuevo:
1
newgrp docker
Finalmente, verifica que puedas ejecutar comandos de Docker sin sudo:
1
docker run hello-world
Deberías obtener un resultado como este:
1
2
3
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
Configura Docker para que se inicie al arrancar:
1
2
sudo systemctl enable docker.service
sudo systemctl enable containerd.service
Instalando cri-dockerd
Originalmente, Docker Engine se integraba directamente en el código kubelet. Cuando Kubernetes pasó a utilizar la capa CRI, se agregó un adaptador temporal llamado dockershim entre CRI y Docker Engine. Con Kubernetes 1.24, Dockershim se eliminó del núcleo de Kubernetes, por lo que los usuarios deben instalar el adaptador cri-dockerd de terceros para integrar Docker Engine con Kubernetes.
Utiliza el paquete cri-dockerd prediseñado para instalar el binario y configurar el sistema para ejecutarlo como un servicio:
1
2
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.4/cri-dockerd_0.3.4.3-0.ubuntu-jammy_amd64.deb -P /tmp
sudo apt install -y /tmp/cri-dockerd_0.3.4.3-0.ubuntu-jammy_amd64.deb
Verifica que el servicio se esté ejecutando y escuchando en unix:///var/run/cri-dockerd.sock (el socket de punto final predeterminado):
1
2
systemctl status cri-docker.service
systemctl status cri-docker.socket
Instalación de las herramientas de Kube
A continuación, instala la herramienta utilizada para iniciar el clúster (kubeadm), el componente que inicia pods y contenedores (kubelet) y la herramienta de línea de comandos utilizada para comunicarse con el clúster (kubectl).
kubeadmno instalará ni administrarákubeletokubectlpor ti, por lo que debes asegurarte de que coincidan con la versión del plano de control de Kubernetes que deseas quekubeadminstala por ti.
Actualiza el índice del paquete apt e instala los paquetes necesarios para usar el repositorio apt de Kubernetes:
1
sudo apt update && sudo apt install -y apt-transport-https ca-certificates curl
Descarga la clave de firma pública de Google Cloud:
1
curl -fsSL https://dl.k8s.io/apt/doc/apt-key.gpg | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpg
Agrega el repositorio apto de Kubernetes:
1
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
Actualiza el índice del paquete apt e instala kubelet, kubeadm y kubectl para obtener la última versión:
1
sudo apt update && sudo apt install -y kubelet kubeadm kubectl
Para instalar una versión específica, primero verifica las versiones disponibles para los paquetes:
1 curl -s https://packages.cloud.google.com/apt/dists/kubernetes-xenial/main/binary-amd64/Packages | grep Version | awk '{print $2}' | sort -V | uniqY luego indique dicha versión en el comando de instalación:
1 sudo apt install -y kubelet=<version> kubeadm=<version> kubectl=<version>
Fija las versiones de kubelet, kubeadm y kubectl:
1
sudo apt-mark hold kubelet kubeadm kubectl
Habilita el autocompletado kubectl:
1
echo 'source <(kubectl completion bash)' >> ~/.bashrc
Amplía la finalización del shell para que funcione con el alias k (opcional):
1
2
echo 'alias k=kubectl' >> ~/.bashrc
echo 'complete -F __start_kubectl k' >> ~/.bashrc
Vuelve a cargar .bashrc para que la nueva configuración surta efecto en la sesión actual:
1
source ~/.bashrc
kubectles compatible con una versión secundaria (anterior o más reciente) de kube-apiserver.
Para saber en cualquier momento qué versiones de
kubectly kube-apiserver se están ejecutando, verifica la versión del cliente y del servidor respectivamente desde el resultado del siguiente comando:
1 kubectl version
Instalación de los componentes del plano de control del clúster
El nodo del plano de control (anteriormente conocido como nodo maestro) es la máquina donde se toman las principales decisiones del clúster. Ejecuta componentes como etcd (la base de datos del clúster) y el servidor API, con el que se comunica la herramienta de línea de comandos kubectl.
Inicialice el nodo del plano de control especificando un bloque CIDR adecuado para el complemento de red de pod basado en CNI y el punto final del tiempo de ejecución del contenedor:
1
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --cri-socket unix:///var/run/cri-dockerd.sock
Ten cuidado de que tu red pod no se superponga con ninguna de las redes host.
Copia el comando de unión de salida
kubeadmcon el token y el descubrimiento-token-ca-cert-hash para luego unir nodos adicionales al clúster mediante:
1 kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>
Haz que kubectl funcione para tu usuario no root:
1
2
3
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Instalación del complemento de red pod
Ahora implementa un complemento de red de pods basado en Container Network Interface (CNI) para que tus pods puedan comunicarse entre sí.
Hemos elegido Calico, una solución de red de código abierto para Kubernetes, ampliamente adoptada y probada en batalla, que proporciona dos servicios principales para aplicaciones nativas de la nube:
- Conectividad de red entre cargas de trabajo.
- Aplicación de políticas de seguridad de red entre cargas de trabajo.
Requisitos
Crea el siguiente archivo de configuración para evitar que NetworkManager interfiera con las interfaces:
1
2
3
4
5
sudo mkdir -p /etc/NetworkManager/conf.d/
cat << EOF | sudo tee /etc/NetworkManager/conf.d/calico.conf
[keyfile]
unmanaged-devices=interface-name:cali*;interface-name:tunl*;interface-name:vxlan.calico;interface-name:vxlan-v6.calico;interface-name:wireguard.cali;interface-name:wg-v6.cali
EOF
Instalación de Calico con el operador
Obtén la última etiqueta de versión estable del repositorio projectcalico/calico:
1
VERSION=$(curl -sL https://api.github.com/repos/projectcalico/calico/releases/latest | jq -r ".name")
Instala el operador Calico y las definiciones de recursos personalizados (CRD):
1
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/$VERSION/manifests/tigera-operator.yaml
Descarga los recursos personalizados necesarios para configurar Calico y personalizar el manifiesto para el CIDR 10.244.0.0/16:
1
2
curl https://raw.githubusercontent.com/projectcalico/calico/$VERSION/manifests/custom-resources.yaml -O
sed -i 's/cidr:.*/cidr: 10\.244\.0\.0\/16/' custom-resources.yaml
Finalmente, crea el manifiesto para instalar Calico:
1
kubectl create -f custom-resources.yaml
Espera hasta que cada pod esté en ejecución:
1
watch kubectl get pods -n calico-system
Comprobación de la instalación
El DNS del clúster (CoreDNS) solo se iniciará después de que una red esté instalada correctamente.
Verifica que los pods de CoreDNS se estén ejecutando:
1
kubectl get pods --all-namespaces
Verifica que tu nodo también esté listo:
1
kubectl get nodes -o wide
Elimina la contaminación en el plano de control para que pueda programar pods en él:
1
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
Si planeas mantener el nodo del plano de control dedicado a las cargas de trabajo del plano de control, puedes omitir el paso anterior. Sin embargo, al menos un nodo trabajador debe unirse al clúster más adelante para que puedas implementar tus aplicaciones.
Instalando calicoctl
La herramienta de línea de comandos calicoctl se utiliza para administrar las políticas de seguridad y de red de Calico, ver y administrar la configuración de puntos finales y administrar una instancia de nodo de Calico.
Para instalar calicoctl como binario en un único host:
1
2
3
4
POD=$(kubectl -n calico-system get pod -l k8s-app=calico-kube-controllers -o jsonpath="{.items[0].metadata.name}")
VERSION=$(kubectl -n calico-system describe pod $POD | grep Image: | cut -d ':' -f3)
sudo curl -L https://github.com/projectcalico/calico/releases/download/$VERSION/calicoctl-linux-amd64 -o /usr/local/bin/calicoctl
sudo chmod +x /usr/local/bin/calicoctl
Verifica que el comando se haya instalado correctamente:
1
calicoctl version
Asegúrate de instalar siempre la versión de
calicoctlque coincida con la versión de Calico que se ejecuta en tu clúster.
Unirse a un nuevo nodo trabajador
Ya sea que hayas permitido o no que los pods se ejecuten en el nodo del plano de control, ejecútalo en cualquier máquina que quieras unir al clúster existente:
1
sudo kubeadm join <control-plane-host>:<control-plane-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>
Verifica que el nuevo nodo se haya agregado correctamente ejecutando el siguiente comando en el nodo del plano de control:
1
kubectl get nodes
Si necesitas recuperar el token, ejecuta el siguiente comando en el nodo del plano de control:
1 kubeadm token list
Si necesitas recuperar el token-ca-cert-hash de descubrimiento, ejecuta el siguiente comando en el nodo del plano de control:
1 2 openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \ openssl dgst -sha256 -hex | sed 's/^.* //'
Si te unes a un nodo después de que el token haya caducado, ejecuta el siguiente comando en el nodo del plano de control:
1kubeadm token create --print-join-command
Desaprovisionamiento limpio de un nodo
Todo lo que tiene un principio tiene un final. Si deseas desaprovisionar tu clúster y revertir limpiamente todos los cambios realizados por el comando kubeadm, primero drene el nodo y asegúrate de que esté vacío, luego desconfigúralo.
Para drenar el nodo, márcalo como no programable para evitar que lleguen nuevos pods y desalojar o eliminar todos los pods existentes:
1
kubectl drain <node_name> --delete-emptydir-data --force --ignore-daemonsets
Luego, restablezca el estado creado por kubeadm:
1
sudo kubeadm reset
Si deseas restablecer las reglas de iptables manualmente, ejecuta:
1
sudo iptables -F && sudo iptables -t nat -F && sudo iptables -t mangle -F && sudo iptables -X
Si deseas restablecer las tablas IPVS manualmente, ejecuta:
1
sudo ipvsadm -C
Ahora puedes eliminar el nodo del clúster de forma segura:
1
kubectl delete node <node_name>
Ya estás listo para empezar de nuevo ejecutando kubeadm init o kubeadm join con los argumentos adecuados.
Control de tu clúster desde máquinas distintas al nodo del plano de control
Para usar kubectl en otra computadora para acceder a tu clúster, copia el archivo kubeconfig del administrador desde el nodo del plano de control a tu estación de trabajo.
Suponiendo que el acceso SSH para root esté deshabilitado en tu nodo del plano de control, copia el archivo kubeconfig a tu directorio de inicio y convierte a tu usuario en su propietario:
1
2
sudo cp /etc/kubernetes/admin.conf $HOME/.
sudo chown $USER: admin.conf
Copia el archivo kubeconfig del nodo del plano de control remoto y asígnele el nombre que desee:
1
2
scp $USER@<control-plane-host>:~/admin.conf ~/.kube/
mv ~/.kube/admin.conf ~/.kube/config-new
Agrega el archivo kubeconfig a tu variable de entorno KUBECONFIG actual y actualiza tu archivo kubeconfig:
1
2
export KUBECONFIG=~/.kube/config:~/.kube/config-new
kubectl config view --flatten > ~/.kube/config
Verifica que tu nuevo clúster aparezca como contexto de Kubernetes y configúrelo como el contexto actual de forma remota:
1
2
kubectl config get-contexts
kubectl config set-context <cluter_name>
Conclusión
En este punto, ya deberías contar con un clúster de Kubernetes totalmente funcional y operativo, con un plano de control funcionando correctamente, un proceso de registro de nodos en buen estado y una configuración de kubectl que te permita interactuar con él de forma remota. Los pasos que hemos cubierto en este artículo te ofrecen una base sólida para desplegar aplicaciones, probar cargas de trabajo y avanzar hacia temas más complejos como networking, almacenamiento, ingress y hardening del clúster.
Si estás montando un laboratorio personal o un entorno de desarrollo reducido, esta configuración te brinda un punto de partida sólido que podrás ampliar a medida que crezcan tus necesidades. En próximas entradas, profundizaremos con ejemplos prácticos como el despliegue de servicios, la configuración de redes y la exploración de conceptos de Kubernetes más avanzados.



