Saltar al contenido principal

K8s en CentOS 8

· 8 min de lectura
Rei Izumi

Con la aparición de la virtualización, el mundo cambió, ahora podías dividir tu mega-servidor en pequeños servidores y así utilizar todo su potencial, sin duda, fue una gran mejora y quienes se opusieron a ello, acabaron cambiando de mentalidad.

Después de esto, apareció la Cloud, un timo en toda regla, donde pagas una barbaridad por un servicio que podrías tener en tu servidor físico por un precio claramente inferior, algo inaudito fue ver cómo la gente se movió hacia la Cloud creyendo que todo sería más barato, no lo fue, pero aun así su avance no ha parado (ni su precio).

No suficiente con ello, otro gran cambio apareció con los contenedores, ya no requieres virtualizar, puedes dividir el potenciar de tu servidor distribuyendo contenedores con los servicios que necesitas, y, además, estos se pueden replicar "fácilmente" entre otros servidores, lo que te permite tener pequeños servidores junto a grandes servidores (sí, ya existen cajas donde poner varios Raspberrys para crear un cluster realmente eficiente, aunque ojo que su CPU es ARM y no todos los contenedores son compatibles).

Hacia la cabeza de estos sistemas está Docker como creador y gestor de contenedores, y Kubernetes como gestor de despliegues. Existen otras opciones a Kubernetes (como Docker Swarm, que funciona perfectamente y es mucho más sencillo), pero no hay nada más extendido y libre que este.

0- Previos

El master de Kubernetes (K8s en adelante) no puede hacer de nodo (es posible cambiarlo, pero no recomendable), así que mínimo necesitamos 2 servidores. Para alta disponibilidad se aconseja 3 masters y al menos 2 nodos.

CentOS 8 será mi base, esto tiene algunos problemas ya que las versiones 8 de CentOS y Red Hat no apuestan por Docker y este me hace falta para K8s, si se instala CentOS en la versión server, habrá que desinstalar todo el sistema de contenedores, algo nada aconsejable. Yo utilizaré los servidores instalados según la configuración que expliqué en otro post.

En todos los casos utilizaré el usuario root.

La idea es desplegar la última versión de Docker en todos los servidores, instalar el K8s en todos los servidores, iniciar el master y unir el resto a este master.

K8s NO recomienda tener partición swap (¡normalmente no inicia!), es preferible no crear una partición para este ya que sería una pérdida de espacio.

Antes de nada, este artículo explica cómo instalar Kubernetes, pero no su uso, y no es nada fácil, en caso de iniciarse en este mundo, yo aconsejaría instalar únicamente Docker, y aprender de él antes de saltar a Kubernetes, incluso aprender Docker-Compose y Docker Swarm (y quedarse ahí) son buenas ideas antes de hacer el salto.

Ahora si, ¡empezamos!

1- Preparando el sistema

Todos los nodos deben ser capaces de comunicarse entre ellos, así que o los asignamos en un servidor de DNS, o modificamos el fichero de /etc/hosts y los incluimos manualmente en todos ellos.

La nueva seguridad de CentOS no es compatible con Docker, así que habrá que hacer unos cuantos cambios.

Primero desactivamos SELinux para que los pods puedan conectarse a los servicios.

setenforce 0
sed -i --follow-symlinks 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux

Y añadimos la masquerade en el firewall para que el clúster se pueda comunicar.

modprobe br_netfilter
firewall-cmd --add-masquerade --permanent
firewall-cmd --reload

Modificamos el iptables para permitir el tráfico

cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF

Y aplicamos todos estos cambios.

sysctl --system

Finalmente desconectamos el swap.

swapoff -a

Si nuestro servidor tiene una partición swap definida, además habrá que quitarla de /etc/fstab.

Con estos cambios ya podemos empezar a instalar.

2- Instalación de Docker

Docker será la base de todo, pero tal como explicaba, la versión 8 no es compatible con este, así que no dispone de un repositorio propio, se utiliza el de CentOS 7.

Con los cambios anteriores, únicamente necesitamos añadir el repositorio, instalar y activar el servicio.

dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
dnf install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm -y
dnf install docker-ce -y
systemctl start docker
systemctl enable docker

Y ya solo nos queda comprobar que funciona y la versión que tenemos.

docker version

Realmente sencillo una vez sabes los trucos.

En caso de querer dejarlo aquí, Docker tiene algunos problemas con el firewall que K8s esquiva a su manera, así que seguramente hará falta algunas modificaciones extras para hacerlo funcionar con sistemas más complejos, si únicamente queremos hacer pruebas y pequeños despliegues, es posible que sea suficiente.

2- Instalación de Kubernetes

Igual que con Docker, tenemos que incluir el repositorio, instalar e iniciar el servicio.

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF
dnf upgrade -y
dnf install kubelet kubeadm kubectl --disableexcludes=kubernetes -y
systemctl start kubelet
systemctl enable kubelet

A partir de aquí, varía según si estamos trabajando con el master o nodo.

3- Preparación del Master de Kubernetes

Primero pre-descargamos los contenedores necesarios para el master.

kubeadm config images pull

K8s requiere una serie de puertos para permitir la comunicación, así que los abrimos.

firewall-cmd --zone=public --permanent --add-port={6443,2379,2380,10250,10251,10252}/tcp

También abrimos el rango de la red creada por Docker ya que nos puede bloquear conexiones entre pods.

Por defecto, Docker utiliza la red 172.17.0.0/16, esto lo podemos comprobar con un "ip a".

firewall-cmd --zone=public --permanent --add-rich-rule 'rule family=ipv4 source address=172.17.0.0/16 accept'

Igual que hemos abierto la red de Docker, tendremos que permitir el acceso para cada nodo, así que la siguiente línea requiere cambiar la sección de NODE_IP por la IP de cada nodo, y repetirla por cada uno de ellos.

firewall-cmd --zone=public --permanent --add-rich-rule 'rule family=ipv4 source address=NODE_IP/24 accept'

Reiniciamos los cambios del firewall

firewall-cmd --reload

Ahora ya podemos iniciar el master.

kubeadm init --pod-network-cidr=10.244.1.0/16

Al terminar, nos dirá el comando para unir nodos, que será similar a:

kubeadm join 192.168.1.30:6443 --token ud2rhx.ix85c9jnwl3hj8n9 \
--discovery-token-ca-cert-hash sha256:f760770fc9ade405d78944142b6576bc2d25b1a2bc1c3317baf5508d6288ee69

Dos detalles: el primero es que algunas veces, la contra barra (\) para separar en 2 líneas me ha dado algún problema, simplemente con quitarla y pasar a una línea se soluciona.

La otra es que, si no la encontramos o la hemos perdido, podemos volverla a generar con el siguiente comando:

kubeadm token create --print-join-command

Además de esa explicación, nos dice los siguientes cambios a realizar.

mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

Aún no hemos acabado, ¡falta definir una network! Hay muchas opciones, aunque últimamente he optado por las opciones de Calico con bastante éxito y seguiré con ella.

kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

Ahora sí, el master está terminado y podemos empezar a configurar los nodos.

En este punto, aconsejo dejar un watch activo mirando la lista de nodos para confirmar que se van añadiendo correctamente mientras nos conectamos a los nodos desde otro terminal.

watch kubectl get nodes

3- Preparación de los nodos de Kubernetes

Esto habrá que replicarlo por cada nodo que tengamos.

Primero abrimos los puertos necesarios.

firewall-cmd --zone=public --permanent --add-port={10250,30000-32767}/tcp
firewall-cmd --reload

Y utilizamos el comando de join que tengamos del master.

kubeadm join 192.168.1.30:6443 --token ud2rhx.ix85c9jnwl3hj8n9 \
--discovery-token-ca-cert-hash sha256:f760770fc9ade405d78944142b6576bc2d25b1a2bc1c3317baf5508d6288ee69

Nodo terminado, si todo ha ido bien, en el watch del master iremos viendo como aparece cada nodo, y, después de unos segundos, estos pasarán a Ready, indicando que ya está funcionando.

N- Borrar Kubernetes

Si la creación de master o nodos no ha ido bien, podemos reiniciar el sistema y volverlo a intentar

kubeadm reset && rm -rf /etc/cni/net.d

Final

En unos pocos minutos es posible desplegar un Kubernetes en CentOS 8, pero aquí es donde empieza lo complicado.

K8s es uno de los sistemas más complejos que me he encontrado, aunque es cierto que hay varias UI que pueden simplificar la vida, pero igualmente nos exige aprender una gran cantidad de comandos.

Otro de los problemas es que versiones se deprecan muy rápidamente, así que es normal encontrarse con errores de incompatibilidad en muchos ejemplos y cursos.

Por otro lado, si tenemos más de un nodo, tendremos el problema de los volumenes, los contenedores pueden ser reconstruidos y replicados por el sistema, y este lo asignará al nodo que así considere si no le hemos indicado algo diferente, los volumenes (el lugar donde se almacenan los ficheros que no queremos perder), se quedará en el nodo original, así que, si se despliega en otro nodo, no tendrá acceso. Los K8s cloud tienen esto solucionado con sus propios sistemas, pero las instalaciones manuales tienen que crear un sistema propio para solucionarlo, esto se explicará en futuros artículos.