Implementación de un clúster de Kubernetes v1.27.x de alta disponibilidad con balanceadores de carga

Implementación de un clúster de Kubernetes v1.27.x de alta disponibilidad con balanceadores de carga

Configuración del entorno de pruebas

El entorno incluye nodos maestro, trabajador, etcd, un servidor de balanceo de carga con HAProxy/Keepalived y un repositorio de imágenes Harbor.


# Nodos maestros
k8s-master1-120  192.168.119.120
k8s-master2-121  192.168.119.121  # Para expansión

# Nodos trabajadores
k8s-node1-122  192.168.119.122
k8s-node2-123  192.168.119.123  # Para expansión

# HAProxy + Keepalived + Nodo de despliegue
HAproxy-k8s-apply-124  192.168.119.124
VIP  192.168.119.200/201/202

# Nodos etcd
k8s-etcd1-125  192.168.119.125
k8s-etcd2-126  192.168.119.126

# Repositorio Harbor
192.168.119.113

Sincronización de tiempo y configuración

Antes de comenzar, es crucial asegurar que la zona horaria y la hora estén sincronizadas en todos los nodos.


# Establecer zona horaria común
timedatectl set-timezone Asia/Shanghai
# Sincronización periódica mediante cron
*/5 * * * * /usr/sbin/ntpdate time1.aliyun.com > /dev/null && hwclock -w > /dev/null

1. Configuración del balanceador de carga externo

Se instala y configura HAProxy para redirigir el tráfico de la API de Kubernetes, y Keepalived para gestionar las IP virtuales (VIP).


# Instalación en el nodo de balanceo (192.168.119.124)
apt -y install haproxy keepalived

# Configuración de Keepalived (/etc/keepalived/keepalived.conf)
vrrp_instance INSTANCIA_K8S {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass K8S_HA_2023
    }
    virtual_ipaddress {
        192.168.119.200 dev eth0 label eth0:vip1
        192.168.119.201 dev eth0 label eth0:vip2
        192.168.119.202 dev eth0 label eth0:vip3
    }
}
# Habilitar e iniciar el servicio
systemctl enable --now keepalived

# Configuración de HAProxy (/etc/haproxy/haproxy.cfg)
listen k8s_api_server
    bind 192.168.119.200:6443
    mode tcp
    option tcplog
    server master_node_1 192.168.119.120:6443 check inter 5s fall 3 rise 2
# Reiniciar para aplicar
systemctl restart haproxy
# Verificar que el puerto está a la escucha
ss -ltn | grep 6443

2. Preparación del repositorio Harbor

Se utiliza un repositorio privado de imágenes con acceso HTTPS. La configuración detallada se omite por brevedad, pero implica definir el hostname, los puertos y las rutas a los certificados SSL en el archivo harbor.yml.

3. Implementación del clúster con kubeasz

Se emplea la herramienta kubeasz, que automatiza el despliegue mediante Ansible. Es esencial entender la separación de los balanceadores: uno interno (kube-lb) para los nodos del clúster y el externo (HAProxy) para clientes.

3.1 Acceso SSH sin contraseña

El nodo de despliegue necesita acceso root sin contraseña a todos los demás nodos (maestros, trabajadores y etcd). Se puede lograr generando un par de claves SSH y distribuyendo la clave pública.

3.2 Descarga de componentes y dependencias

En el nodo de despliegue, se instalan Ansible y Git, se descarga el script ezdown de kubeasz y se ejecuta para obtener todos los binarios necesarios de Kubernetes, etcd, Calico, etc. También se preconfigura Docker o Containerd como motor de contenedores.


# Ejemplo de instalación manual de Containerd
wget https://github.com/containerd/containerd/releases/download/v1.6.20/containerd-1.6.20-linux-amd64.tar.gz
tar -C /usr/local -xzvf containerd-1.6.20-linux-amd64.tar.gz
# Crear archivo de servicio systemd para containerd
# Configurar el daemon de Containerd (config.toml)
# Instalar y configurar nerdctl como cliente CLI
3.3 Definición del inventario y configuración del clúster

Se genera un nuevo clúster con ezctl new y se edita el archivo de inventario de Ansible (hosts) para especificar los grupos de nodos (etcd, kube_master, kube_node) y las variables globales como el rango CIDR para Pods y Services, el plugin de red y el modo de kube-proxy.


# Ejemplo de definición en el archivo hosts
[etcd]
192.168.119.125
192.168.119.126

[kube_master]
192.168.119.120 k8s_nodename='kube-master-1'

[kube_node]
192.168.119.122 k8s_nodename='kube-worker-1'

[all:vars]
CONTAINER_RUNTIME="containerd"
CLUSTER_NETWORK="calico"
SERVICE_CIDR="10.96.0.0/12"
CLUSTER_CIDR="10.244.0.0/16"

Además, se ajusta el archivo config.yml del clúster para definir los hosts adicionales en los certificados del maestro, los límites de Pods por nodo y si se instalan addons como CoreDNS o el Dashboard de métricas.

3.4 Despliegue paso a paso del clúster

El proceso se divide en fases ejecutadas con ezctl setup:

  1. Preparación (01): Genera certificados, archivos kubeconfig y prepara los nodos.
  2. etcd (02): Implementa el clúster etcd. Se verifica el estado con etcdctl endpoint health.
  3. Motor de contenedores (03): Instala Containerd en todos los nodos. Se personaliza la configuración, por ejemplo, estableciendo SystemdCgroup = true.
  4. Nodo maestro (04): Instala los componentes de control de Kubernetes (API server, scheduler, controller-manager). Se verifica con kubectl get nodes.
  5. Nodo trabajador (05): Instala kubelet y kube-proxy en los nodos trabajadores.
  6. Red (06): Despliega el plugin de red (Calico). Se aplica el manifiesto YAML y se verifica la conectividad entre Pods y con el exterior.

# Ejemplo de despliegue de la red Calico
kubectl apply -f calico-v3.26.1.yaml
# Verificar el estado de los demonios de red
calicoctl node status

# Prueba de conectividad entre Pods
kubectl run test-pod --image=busybox -- sleep 3600
kubectl exec test-pod -- ping -c 2 <IP_DE_OTRO_POD>
kubectl exec test-pod -- ping -c 2 8.8.8.8
3.5 Gestión de nodos del clúster

Se pueden añadir o eliminar nodos maestros y trabajadores dinámicamente.


# Añadir un nuevo nodo maestro
./ezctl add-master <nombre_clúster> <ip_nuevo_maestro>

# Añadir un nuevo nodo trabajador
./ezctl add-node <nombre_clúster> <ip_nuevo_worker>

# Ver el estado tras el escalado
kubectl get nodes

Al añadir un nodo, kube-lb (el balanceador interno) actualiza automáticamente su configuración.

3.6 Actualización de versión del clúster

Existen dos métodos para actualizar los binarios de Kubernetes:

  • Masiva con kubeasz: Se descargan los nuevos binarios, se colocan en el directorio de kubeasz y se ejecuta ./ezctl upgrade <clúster>.
  • Manual: Se detienen los servicios en un nodo (maestro o trabajador), se reemplazan los binarios en /usr/local/bin y se reinician los servicios. Se repite para cada nodo.

# Ejemplo de actualización manual en un nodo maestro
systemctl stop kube-apiserver kube-controller-manager kube-scheduler kubelet kube-proxy
scp /ruta/nuevos_binarios/{kube-apiserver,kubelet,...} usuario@ip_nodo:/usr/local/bin/
systemctl start kube-apiserver kube-controller-manager kube-scheduler kubelet kube-proxy

4. Implementación de CoreDNS para resolución interna

CoreDNS es el servicio DNS interno por defecto de Kubernetes. Se despliega mediante su manifiesto YAML. Es crucial configurarlo para que el dominio DNS del clúster coincida con el definido en el archivo de inventario (CLUSTER_DNS_DOMAIN) y que apunte a los DNS externos para la resolución fuera del clúster.


# Configuración esencial en el ConfigMap de CoreDNS
Corefile: |
    .:53 {
        errors
        health
        kubernetes cluster.local in-addr.arpa ip6.arpa {
           pods insecure
           fallthrough in-addr.arpa ip6.arpa
        }
        forward . 223.6.6.6 8.8.8.8
        cache 30
        loop
        reload
        loadbalance
    }

Se verifica la funcionalidad desde dentro de un Pod:


kubectl exec -it mi-pod -- nslookup kubernetes.default
kubectl exec -it mi-pod -- ping www.google.com

5. Uso esencial de kubectl

Algunos comandos frecuentes para interactuar con el clúster:


# Configurar autocompletado para bash
source <(kubectl completion bash)

# Obtener información de recursos
kubectl get nodes -o wide
kubectl get pods --all-namespaces
kubectl describe pod <nombre_pod>
kubectl logs <nombre_pod>

# Gestionar el ciclo de vida de recursos
kubectl apply -f manifiesto.yaml
kubectl delete pod <nombre_pod>
kubectl exec -it <nombre_pod> -- /bin/sh

# Operaciones en el clúster
kubectl cordon <nombre_nodo>    # Marcar como no programable
kubectl uncordon <nombre_nodo>  # Desmarcar
kubectl drain <nombre_nodo>     # Drenar pods para mantenimiento

# Ver información del clúster
kubectl cluster-info
kubectl api-resources

6. Implementación de un Dashboard (Kuboard)

Para una gestión gráfica, se puede desplegar un dashboard como Kuboard. El proceso implica crear un Persistent Volume (usando NFS en este ejemplo) para el almacenamiento y aplicar el manifiesto de despliegue que incluye un Namespace, un Deployment y un Service expuesto mediante NodePort.


# Fragmento del Service de Kubiard (NodePort)
spec:
  type: NodePort
  ports:
    - name: http
      port: 80
      targetPort: 80
      nodePort: 30080

Una vez desplegado, se accede vía http://<IP_NODO>:30080 y se añade el clúster proporcionadno el contenido del archivo ~/.kube/config del administrador.

7. Mecanismo de elección de líder en etcd

etcd utiliza el algoritmo Raft para el consneso:

  • Elección inicial: Los nodos comienzan como seguidores (followers). Si no reciben latidos de un líder, se convierten en candidatos, se votan a sí mismos y solicitan votos a otros. El candidato con la mayoría de votos y el log más actualizado se convierte en líder.
  • Elecciones posteriores: Si un seguidor no recibe latidos del líder dentro de un tiempo de elección (election timeout), inicia una nueva elección incrementando su término (term ID). El líder antiguo, al recuperarse, se sincronizará con el nuevo líder.

Se puede observar el estado del clúster etcd con:


etcdctl --endpoints=https://192.168.119.125:2379,https://192.168.119.126:2379 \
  --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/server.pem --key=/etc/kubernetes/ssl/server-key.pem \
  endpoint status --write-out=table

etcdctl --endpoints=https://192.168.119.125:2379,https://192.168.119.126:2379 \
  --cacert=/etc/kubernetes/ssl/ca.pem --cert=/etc/kubernetes/ssl/server.pem --key=/etc/kubernetes/ssl/server-key.pem \
  member list --write-out=table

Etiquetas: Kubernetes Alta Disponibilidad HAProxy Keepalived calico

Publicado el 6-17 20:33