Antes de iniciar el despliegue del clúster, es necesario preparar un registro de imágenes privado (Harbor) que proporcionará las imágenes a los nodos workers.
- Preparación del registro Harbor
Descargue el paquete de instalación desde el repositorio oficial:
https://github.com/goharbor/harbor/releases
Extraiga el archivo y configure:
[root@harbor ~]# tar zxf harbor-offline-installer-v2.5.4.tgz
[root@harbor ~]# cd harbor
[root@harbor harbor]# cp harbor.yml.tmpl harbor.yml
[root@harbor harbor]# vim harbor.yml
Genere los certificados TLS para el registro:
[root@harbor harbor]# mkdir -p /data/cert
[root@harbor harbor]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout /data/cert/ch.key -addext "subjectAltName = DNS:reg.ch.cn" -x509 -days 365 -out /data/cert/ch.crt
Ejecute el instalador con soporte para Chartmuseum:
[root@harbor harbor]# ./install.sh --with-chartmuseum
Verifique el acceso desde el navegador usando las credenciales definidas en harbor.yml.
Configure la autenticación local para Docker:
[root@harbor harbor]# mkdir -p /etc/docker/certs.d/reg.ch.cn
[root@harbor harbor]# cp /data/cert/ch.crt /etc/docker/certs.d/reg.ch.cn/ca.crt
[root@harbor harbor]# docker login reg.ch.cn # requiere resolución DNS
Modifique el archivo /etc/docker/daemon.json en todos los nodos del clúster para que usen el registro privado:
{
"registry-mirrors": ["https://reg.ch.cn"]
}
Reinicie Docker y verifique: systemctl restart docker.service && docker info.
Copie los certificados y la configuración de login a cada nodo del clúster y asegúrese de que la resolución DNS apunte a reg.ch.cn.
- Entorno base
El despliegue se realiza sobre RHEL9 con la siguiente planificación:
| Hostname | IP | Rol |
|---|---|---|
| harbor | 192.168.1.25 | Registro Harbor |
| k8s-master | 192.168.1.200 | Control plane |
| k8s-node1 | 192.168.1.30 | Worker |
| k8s-node2 | 192.168.1.40 | Worker |
Requisitos comunes en todos los nodos:
- Deshabilitar SELinux y el firewall.
- Sincronización de hora y resolución de nombres (ejemplo de
/etc/hosts):
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.1.130 localhost
192.168.1.25 harbor reg.ch.cn
192.168.1.200 k8s-master
192.168.1.30 k8s-node1
192.168.1.40 k8s-node2
- Instalar Docker CE en todos los nodos.
- Deshabilitar swap (comentar línea en
/etc/fstaby reiniciar).
- Instalación de cri-docker
A partir de Kubernetes 1.24 se eliminó Dockershim. Es necesario instalar el plugin cri-dockerd para que Docker funcione como CRI.
Descargue desde: https://github.com/Mirantis/cri-dockerd
[root@k8s-master ~]# yum install *.rpm -y
Modifique el archivo de unidad de systemd para cri-docker:
[root@k8s-master ~]# vim /lib/systemd/system/cri-docker.service
# Especifique el plugin de red y la imagen del pod infra
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=reg.ch.cn/k8s/pause:3.9
[root@k8s-master ~]# systemctl daemon-reload
[root@k8s-master ~]# systemctl restart cri-docker.service
- Instalación de kubelet y kubeadm
Instale los paquetes en todos los nodos:
[root@k8s-master ~]# tar zxf k8s-1.30.tar.gz
[root@k8s-master ~]# yum install *.rpm -y
Habilite la finalización de comandos en el master:
[root@k8s-master ~]# echo "source <(kubectl completion bash)" >> ~/.bashrc
[root@k8s-master ~]# source ~/.bashrc
- Subir imágenes al registro privado
Cargue las imágenes de Kubernetes desde el archivo comprimido:
[root@k8s-master ~]# docker load -i k8s_docker_images-1.30.tar
Etiquete y suba las imágenes al registro privado:
[root@k8s-master ~]# docker images | awk 'NR>1 {print $1 ":" $2}' | while read src_image; do
img_name=$(echo "$src_image" | awk -F / '{print $3}')
dest_image="reg.ch.cn/k8s/$img_name"
docker tag "$src_image" "$dest_image"
done
[root@k8s-master ~]# docker images --format "{{.Repository}}:{{.Tag}}" | grep "reg.ch.cn/k8s/" | while read image; do
docker push "$image"
done
- Inicialización del clúster
Active kubelet en todos los nodos:
[root@k8s-master ~]# systemctl enable --now kubelet.service
Ejecute kubeadm init en el nodo master:
[root@k8s-master ~]# kubeadm init --pod-network-cidr=10.244.0.0/16 \
--image-repository reg.ch.cn/k8s \
--kubernetes-version v1.30.0 \
--cri-socket=unix:///var/run/cri-dockerd.sock
Configure el acceso a kubectl:
[root@k8s-master ~]# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
[root@k8s-master ~]# source ~/.bash_profile
Verifique el estado (el nodo aparecerá como NotReady hasta instalar el plugin de red):
[root@k8s-master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master NotReady control-plane 2m v1.30.0
Si pierde el tokan de unión, regenérelo con:
[root@k8s-master ~]# kubeadm token create --print-join-command
- Instalación de Flannel (plugin de red)
Descargue la imagen de Flannel y súbala al registro privado:
[root@k8s-master ~]# docker load -i flannel-0.25.5.tar.gz
[root@k8s-master ~]# docker tag flannel/flannel:v0.25.5 reg.ch.cn/flannel/flannel:v0.25.5
[root@k8s-master ~]# docker push reg.ch.cn/flannel/flannel:v0.25.5
[root@k8s-master ~]# docker tag flannel/flannel-cni-plugin:v1.5.1-flannel1 reg.ch.cn/flannel/flannel-cni-plugin:v1.5.1-flannel1
[root@k8s-master ~]# docker push reg.ch.cn/flannel/flannel-cni-plugin:v1.5.1-flannel1
Edite el manifiesto kube-flannel.yml para que use el registro privado:
[root@k8s-master ~]# vim kube-flannel.yml
# Modifique las líneas que contienen 'image':
# 146: image: reg.ch.cn/flannel/flannel:v0.25.5
# 173: image: reg.ch.cn/flannel/flannel-cni-plugin:v1.5.1-flannel1
# 184: image: reg.ch.cn/flannel/flannel:v0.25.5
Aplique el manifiesto:
[root@k8s-master ~]# kubectl apply -f kube-flannel.yml
- Unión de nodos workers
Ejecute el comando de unión en cada nodo worker (incluya el flag --cri-socket):
[root@k8s-node1 ~]# kubeadm join 192.168.1.200:6443 --token o18p60.unf02499xuevqn9d \
--discovery-token-ca-cert-hash sha256:26280e8f54f7d82b441a378cfbad93d1cc6ed04226b7867cf8f9f3d8fc9f440b \
--cri-socket=unix:///var/run/cri-dockerd.sock
Si ocurre algún error, limpie con:
[root@k8s-node2 ~]# kubeadm reset --cri-socket=unix:///var/run/cri-dockerd.sock
En el master, verifique que todos los nodos estén Ready:
[root@k8s-master ~]# kubectl get nodes
El clúster Kubernetes está completamente operativo.