En este post, vamos a ver cómo realizar la instalación de un clúster Kubernetes ( también conocido cómo k8s ), en el sistema operativo Ubuntu Server 20.04 LTS.
Características de nuestra infraestructura
Nuestra infraestructura, va a contar los siguientes elementos:
Rol de Server | Hostname | Recursos | IP Red Interna | IP Adaptador Puente |
Master | k8smaster.k8s.local | 4GB Ram, 2vcpus | 10.10.18.1/24 | 192.168.1.3/24 |
Worker1 | k8snode1.k8s.local | 4GB Ram, 2vcpus | 10.10.18.2/24 | 192.168.1.4/24 |
Worker2 | k8snode2.k8s.local | 4GB Ram, 2vcpus | 10.10.18.3/24 | 192.168.1.5/24 |
Todos los nodos de este tutorial están virtualizados. En mi caso, he utilizado la herramienta VirtualBox, disponible tanto para Windows, Mac y Linux.
Todos los nodos, dispondrán de dos tarjetas de red, una en modo «Adaptador puente (Bridge)» y otra en modo «Red Interna». La primera, la utilizaremos para conectarnos a los nodos por SSH desde Putty o cualquier otra herramienta, la segunda, será la red interna por la cual se comunicarán los nodos del clúster de k8s.
Documentación oficial de Kubernetes
Antes de comenzar, es recomendable conocer la infraestructura de Kubernetes, por lo tanto, en estos casos, lo mejor es leer la documentación del fabricante:
https://kubernetes.io/es/docs/home/
Requerimientos mínimos
Hay dos tipos de servidores utilizados en el despliegue de clusters Kubernetes:
- Maestro: Un maestro de Kubernetes es donde se ejecutan las llamadas a la API de control para los pods, controladores de réplica, servicios, nodos y otros componentes de un clúster de Kubernetes.
- Nodo: Un Nodo es un sistema que proporciona los entornos de ejecución para los contenedores. Un conjunto de pods de contenedores puede abarcar varios nodos.
Los requisitos mínimos para una configuración viable son:
- Memoria: 2 GiB o más de RAM por máquina
- CPUs: Al menos 2 CPUs en la máquina del control plane
- Se requiere conectividad a Internet para el pull de los contenedores (también se puede utilizar un registro privado)
- Conectividad de red completa entre las máquinas del cluster – Esta es privada o pública
Configuración de la red de los nodos
En este paso, se da por entendido que todos sabéis instalar Ubuntu Server sin problema, con una instalación básica y el servidor OpenSSH habilitado es más que suficiente.
Por lo tanto, aclarado este punto, dejo por aquí la configuración de los ficheros de red y el /etc/hosts que debeis configurar en cada máquina, adaptando lo necesario a vuestras necesidades / gustos personales.
Nodo Master
Fichero de red |
ubuntu@k8smaster:~$ cat /etc/netplan/00-installer-config.yaml |
Fichero /etc/hosts |
ubuntu@k8smaster:~$ cat /etc/hosts |
Nodo Worker1
Fichero de red |
ubuntu@k8snode1:~$ cat /etc/netplan/00-installer-config.yaml |
Fichero /etc/hosts |
ubuntu@k8snode1:~$ cat /etc/hosts |
Nodo Worker2
Fichero de red |
ubuntu@k8snode2~$ cat /etc/netplan/00-installer-config.yaml |
Fichero /etc/hosts |
ubuntu@k8snode2:~$ cat /etc/hosts |
Paso 1. Actualización de paquetería y reinicio de nodos
Antes de empezar ya definitivamente con el proceso de instalación de Kubernetes en sí, es recomendable realizar una actualización de la paquetería. Estos pasos los realizaremos en todos los nodos del clúster.
sudo apt update
sudo apt -y upgrade && sudo systemctl reboot
Paso 2. Instalar kubelet, kubeadm y kubectl
Cuando se reinicien los nodos, ejecutar de nuevo en todos los siguientes comandos:
sudo apt update
sudo apt -y install curl apt-transport-https
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 /etc/apt/sources.list.d/kubernetes.list
Con lo anterior, añadimos los repos necesarios para instalar los paquetes de kubernetes. Ahora procedemos con la instalación:
sudo apt update
sudo apt -y install vim git curl wget kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
Para confirmar la versión que se ha instalado, ejecutar:
kubectl version --client && kubeadm version
Client Version: version.Info{Major:»1″, Minor:»22″, GitVersion:»v1.22.2″, GitCommit:»8b5a19147530eaac9476b0ab82980b4088bbc1b2″, GitTreeState:»clean», BuildDate:»2021-09-15T21:38:50Z», GoVersion:»go1.16.8″, Compiler:»gc», Platform:»linux/amd64″}
kubeadm version: &version.Info{Major:»1″, Minor:»22″, GitVersion:»v1.22.2″, GitCommit:»8b5a19147530eaac9476b0ab82980b4088bbc1b2″, GitTreeState:»clean», BuildDate:»2021-09-15T21:37:34Z», GoVersion:»go1.16.8″, Compiler:»gc», Platform:»linux/amd64″}
Paso 3. Deshabilitar la swap.
En el fichero /etc/fstab, de todos los nodos, comentar la siguiente línea:
Ejecutar también:
sudo swapoff -a
Ahora, habilitamos los módulos del kernel necesarios y configuramos sysctl:
# Habilitar modulos del kernel
sudo modprobe overlay
sudo modprobe br_netfilter
# Añadir la configuracion de kubernetes a sysctl
sudo tee /etc/sysctl.d/kubernetes.conf<<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
# Recargar sysctl
sudo sysctl --system
Paso 4. Instalar runtime de contenedores.
En nuestro caso, vamos a instalar solo Docker, aunque kubernetes soporta los siguientes. Repetir esta instalación en todos los nodos:
- Docker
- CRI-O
- Containerd
NOTA: solo es posible elegir un runtime a la vez.
Instalación del runtime Docker
# Configuración de nuevos repositorios e instalación
sudo apt update
sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt update
sudo apt install -y containerd.io docker-ce docker-ce-cli
# Creación de los directorios requeridos
sudo mkdir -p /etc/systemd/system/docker.service.d
# Creación del fichero json para el demonio de Docker
sudo tee /etc/docker/daemon.json <<EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
# Iniciar y habilitar servicios
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl enable docker
Paso 5. Inicialización del nodo Master.
Iniciar sesión en el nodo Master y asegurarse de que el modulo «br_netfilter» está cargado (loaded):
ubuntu@k8smaster:~$ lsmod | grep br_netfilter
br_netfilter 28672 0
bridge 176128 1 br_netfilter
Habilitar el servicio de kubelet:
sudo systemctl enable kubelet
Ahora debemos inicializar la máquina que ejecutará los componentes del control plane, que incluye etcd (la base de datos del clúster) y el servidor API.
Hacemos un pull de las imágenes de los contenedores:
ubuntu@k8smaster:~$ sudo kubeadm config images pull
[config/images] Pulled k8s.gcr.io/kube-apiserver:v1.22.2
[config/images] Pulled k8s.gcr.io/kube-controller-manager:v1.22.2
[config/images] Pulled k8s.gcr.io/kube-scheduler:v1.22.2
[config/images] Pulled k8s.gcr.io/kube-proxy:v1.22.2
[config/images] Pulled k8s.gcr.io/pause:3.5
[config/images] Pulled k8s.gcr.io/etcd:3.5.0-0
[config/images] Pulled k8s.gcr.io/coredns/coredns:v1.8.4
—
NOTA: Estas son las opciones básicas de kubeadm init que se utilizan para arrancar el cluster.
–control-plane-endpoint : establece el punto final compartido para todos los nodos del plano de control. Puede ser DNS/IP –pod-network-cidr : Se utiliza para establecer el CIDR del network add-on de los pods –cri-socket : Se utiliza si se tiene más de un runtime de contenedores, para establecer la ruta del socket en tiempo de ejecución –apiserver-advertise-address : Establece la dirección IP para el servidor API de este nodo de control en particular |
Creación del clúster:
ubuntu@k8smaster:~$ sudo kubeadm init --pod-network-cidr=10.20.0.0/16 --upload-certs --control-plane-endpoint=k8smaster.k8s.local
10.20.0.0/16 –> Podemos poner cualquier subred interna que no esté en uso
INFO: el socket del runtime de Docker se encuentra en /var/run/docker.sock
Ahora, es necesario configurar kubectl, utilizando los comandos de la salida del comando anterior:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Comprobar el estado del clúster:
ubuntu@k8smaster:~$ kubectl cluster-info
Kubernetes control plane is running at https://k8smaster.k8s.local:6443
CoreDNS is running at https://k8smaster.k8s.local:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Paso 6. Instalar el plugin de red en el nodo Master.
kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml
kubectl create -f https://docs.projectcalico.org/manifests/custom-resources.yaml
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
Confirmar que todos los pods están corriendo:
ubuntu@k8smaster:~$ watch kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-78fcd69978-2btfq 1/1 Running 0 163m
kube-system coredns-78fcd69978-p8v5h 1/1 Running 0 163m
kube-system etcd-k8smaster 1/1 Running 0 164m
kube-system kube-apiserver-k8smaster 1/1 Running 0 164m
kube-system kube-controller-manager-k8smaster 1/1 Running 5 164m
kube-system kube-flannel-ds-amd64-7td96 1/1 Running 4 (42m ago) 43m
kube-system kube-flannel-ds-amd64-v6pd7 1/1 Running 4 (42m ago) 43m
kube-system kube-flannel-ds-kz6jl 1/1 Running 0 42m
kube-system kube-flannel-ds-pt7rh 1/1 Running 0 42m
kube-system kube-proxy-hpn8w 1/1 Running 0 163m
kube-system kube-proxy-lmmng 1/1 Running 0 46m
kube-system kube-scheduler-k8smaster 1/1 Running 5 164m
kubernetes-dashboard dashboard-metrics-scraper-c45b7869d-lr6w4 1/1 Running 0 76m
kubernetes-dashboard kubernetes-dashboard-576cb95f94-66nww 1/1 Running 0 76m
tigera-operator tigera-operator-59f4845b57-vnfbj 1/1 Running 0 144m
Confirmar que el nodo Master está en estado «Ready»:
ubuntu@k8smaster:~$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8smaster Ready control-plane,master 165m v1.22.2 10.10.18.1 <none> Ubuntu 20.04.3 LTS 5.4.0-88-generic docker://20.10.9
Paso 7. Añadir nodos Workers al clúster.
Con el comando que nos ha salido por pantalla, al iniciar el clúster, en los nodos workers, ejecutar:
ubuntu@k8snode1:~$ sudo kubeadm join k8smaster.k8s.local:6443 --token iu5vzp.egr842fe327y3hl3 --discovery-token-ca-cert-hash sha256:d107e3cb6333c7c64feaae90cbd0e35624b5c1e8e84191692420ee7574872713 --v=5
ubuntu@k8snode2:~$ sudo kubeadm join k8smaster.k8s.local:6443 --token iu5vzp.egr842fe327y3hl3 --discovery-token-ca-cert-hash sha256:d107e3cb6333c7c64feaae90cbd0e35624b5c1e8e84191692420ee7574872713 --v=5
Ahora, desde el nodo Master, comprobar el estado de los nodos:
ubuntu@k8smaster:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8smaster Ready control-plane,master 177m v1.22.2
k8snode1 Ready <none> 60m v1.22.2
k8snode2 Ready <none> 34s v1.22.2
Paso 8. Desplegar aplicación en el clúster para pruebas.
Desplegamos:
ubuntu@k8smaster:~$ kubectl apply -f https://k8s.io/examples/pods/commands.yaml
pod/command-demo created
Comprobamos:
ubuntu@k8smaster:~$ kubectl get pods
NAME READY STATUS RESTARTS AGE
command-demo 0/1 Completed 0 25s
Paso 9. Instalar el panel de control de Kubernetes (opcional).
El panel de control de Kubernetes puede utilizarse para desplegar aplicaciones en un clúster de Kubernetes, solucionar problemas de su aplicaciónes y gestionar los recursos del clúster.
Desplegar el panel de control de Kubernetes
Para desplegar el panel de control, ejecutar, en el nodo Master:
ubuntu@k8smaster:~$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended.yaml
Configurar el servicio para usar NodePort
Esto utilizará los valores por defecto para el despliegue. Si quieres hacer algunas modificaciones en el archivo, tendrás que descargarlo en tu máquina local. Para ello, lo descargamos y lo editamos:
ubuntu@k8smaster:~$ wget https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended.yaml -O kubernetes-dashboard-deployment.yml
ubuntu@k8smaster:~$ vim kubernetes-dashboard-deployment.yml
Modificaremos el servicio del panel de control de Kubernetes para que sea del tipo «NodePort»:
—
kind: Service
apiVersion: v1
metadata:
labels:
k8s-app: kubernetes-dashboard
name: kubernetes-dashboard
namespace: kubernetes-dashboard
spec:
ports:
- port: 443
targetPort: 8443
nodePort: 32000
type: NodePort
selector:
k8s-app: kubernetes-dashboard
—
Guardar los cambios y salir del fichero.
INFO: NodePort expone el Servicio en la IP de cada Nodo en un puerto estático (el NodePort). Un ClusterIP Service, al que el Servicio NodePort se dirige, se crea automáticamente.
Aplicamos los cambios cuando hayamos modificado lo anterior:
ubuntu@k8smaster:~$ kubectl apply -f kubernetes-dashboard-deployment.yml
Para comprobar que el nuevo despliegue se ha lanzado correctamente, ejecutar:
ubuntu@k8smaster:~$ kubectl get deployments -n kubernetes-dashboard
NAME READY UP-TO-DATE AVAILABLE AGE
dashboard-metrics-scraper 1/1 1 1 102m
kubernetes-dashboard 1/1 1 1 102m
Ya que hemos cambiado el tipo de servicio a NodePort, confirmamos si el servicio fue realmente creado, ejecutando:
ubuntu@k8smaster:~$ kubectl get service -n kubernetes-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dashboard-metrics-scraper ClusterIP 10.110.254.40 <none> 8000/TCP 103m
kubernetes-dashboard NodePort 10.101.147.103 <none> 443:32000/TCP 103m
Acceder al panel de control vía web
Cómo hemos desplegado el servicio en el puerto 32000/TCP, para acceder a él, basta con acceder a la IP de la tarjeta de red de tipo «Adaptador puente» de la máquina virtual del nodo Master, en mi caso, la 192.168.1.3:
Para poder entrar, vamos a crear un usuario administrador de kubernetes específico para esto.
En el nodo maestro, crear un fichero de nombre «admin-sa.yml», con el siguiente contenido:
ubuntu@k8smaster:~$ cat admin-sa.yml
—
apiVersion: v1
kind: ServiceAccount
metadata:
name: devops
namespace: kube-system
Aplicar el manifiesto YAML para crear la nueva cuenta:
ubuntu@k8smaster:~$ kubectl apply -f admin-sa.yml
El siguiente paso, es otorgarle de privilegios a este nuevo usuario, para ello, crear un fichero de nombre «admin-rbac.yml», con el siguiente contenido:
ubuntu@k8smaster:~$ cat admin-rbac.yml
—
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: devops
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: devops
namespace: kube-system
Aplicar de nuevo el manifiesto YAML que hemos creado:
ubuntu@k8smaster:~$ kubectl apply -f admin-rbac.yml
Por último, ahora necesitamos saber el Token del usuario para poder acceder al panel de control de Kubernetes. Para ello, ejecutamos lo siguiente:
ubuntu@k8smaster:~$ echo SA_NAME="devops" >> $HOME/.profile
ubuntu@k8smaster:~$ echo export $SA_NAME >> $HOME/.profile
ubuntu@k8smaster:~$ SA_NAME="devops"
ubuntu@k8smaster:~$ export $SA_NAME
Para obtener el token:
ubuntu@k8smaster:~$ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep ${SA_NAME} | awk '{print $1}')
ubuntu@k8smaster:~$ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep ${SA_NAME} | awk '{print $1}')
Name: devops-token-5cwf5
Namespace: kube-system
Labels: <none>
Annotations: kubernetes.io/service-account.name: devops
kubernetes.io/service-account.uid: 304525f1-d4b2-4e42-8a66-4a501b4ff325
Type: kubernetes.io/service-account-token
Data
====
namespace: 11 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6Ik54N2RJTjBLSE5vR3drQkZqQ1V6QnNaN3BrUTcyQTR0Zy1LNGFYLXI3ckkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkZXZvcHMtdG9rZW4tNWN3ZjUiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGV2b3BzIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMzA0NTI1ZjEtZDRiMi00ZTQyLThhNjYtNGE1MDFiNGZmMzI1Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmRldm9wcyJ9.bRLZwfem6JESvkBXi_IZr_gfIzGb4MieQysBnimPndWr293GubyeNGSKaqtFM0P7R4xMdMBebqvRnVpCEQ-Xl9CI2iG76vthIK1g1WQeFFHmMBUr91DzDu6Jr8yqmCEBCsvQQuVdqJKk1pKryaVMB08JzIO91-CeYMNvPIkUa5_SXddw5vEnEcuLC6_ySulJcHRCMgqlyHgjTp8CKPXmKdIWc5KwoZKU9eSTNW19zd9GKOD0yEHE-TXN6HCvtLXNTpplx8ZDe3QZMJHksyn3x-_w_eOYhujxfx4m-BrzjPgr4OHnF04LicNwVHJUs6HP_2gtfEZ_41BO7UFi7JOgDw
ca.crt: 1099 bytes
Con este token, acceder de nuevo al panel de control de Kubernetes y elegir esta opción:
El resultado tras iniciar sesión, será similar a esto:
Pues hasta aquí el post de hoy, espero que os sea de utilidad y cualquier duda / sugerencia no olvidéis escribirlas en los comentarios (os leo).
Un saludo Sysadmins! 🙂
Enlaces de interés:
Documentación oficial de k8s: https://kubernetes.io/es/docs/home/
Documentación oficial de Docker: https://docs.docker.com/
Instalación de clúster k8s en Ubuntu Server: https://computingforgeeks.com/deploy-kubernetes-cluster-on-ubuntu-with-kubeadm/
Instalación de dashboard k8s: https://computingforgeeks.com/how-to-install-kubernetes-dashboard-with-nodeport/
Creación de usuario admin del dashboard de k8s: https://computingforgeeks.com/create-admin-user-to-access-kubernetes-dashboard/