Cilium Cilium

Anuncia las IP de los Services con BGP

¿Sin balanceador de carga en la nube? Cilium puede anunciar las IP de los Services directamente a tu red física mediante BGP.

15 min Avanzado

El tipo de Service LoadBalancer de un proveedor de nube funciona porque la nube tiene una API para aprovisionar un balanceador de carga externo bajo demanda. En bare metal, o en cualquier entorno sin esa API, un Service LoadBalancer se queda en Pending para siempre a menos que otra cosa cumpla ese papel. El plano de control BGP de Cilium es una forma de hacerlo: enruta la IP de un Service directamente hacia tu red física hablando BGP desde los nodos del clúster hacia los routers upstream. Esta guía cubre los cuatro recursos que lo configuran y cómo verificar que una sesión BGP está realmente establecida desde ambos lados.

Cuándo BGP es la herramienta adecuada

Establecer peering BGP desde los nodos del clúster con los routers upstream es una integración de red real: requiere coordinación con quien gestiona la red física (o virtual), configuración en los routers de su lado que coincida con la configuración de peers en el lado de Kubernetes, y una familiaridad operativa genuina con conceptos de BGP como los sistemas autónomos y el anuncio de rutas. Es la herramienta adecuada para un clúster on-premises o bare metal que necesita que las IP de los Services sean realmente enrutables desde el resto de la red, igual que lo haría un LoadBalancer de la nube. Para necesidades más simples, la función de anuncios L2 de Cilium (anunciar la IP de un Service mediante ARP/NDP en el segmento de red local, sin protocolo de enrutamiento) es una alternativa más ligera que vale la pena considerar primero si tu clúster vive en un único segmento de red y no necesita enrutamiento de capa 3 entre segmentos o centros de datos.

Los cuatro recursos

Cuatro recursos personalizados CiliumBGP* trabajan juntos:

  • CiliumLoadBalancerIPPool define un rango de direcciones IP que Cilium puede asignar a los Services LoadBalancer.
  • CiliumBGPAdvertisement define qué se anuncia por BGP, en este caso, las IP de Services tomadas de ese pool.
  • CiliumBGPPeerConfig define cómo hablar BGP: temporizadores, comportamiento de graceful restart, familias de direcciones.
  • CiliumBGPClusterConfig lo une todo: qué nodos participan (mediante un selector de etiquetas), su número de AS local y a qué peers upstream (por IP y número de AS) se conectan.

Define el pool de IP

apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
  name: apps-pool
spec:
  allowFirstLastIPs: "No"
  blocks:
    - cidr: "10.10.211.0/24"

allowFirstLastIPs: "No" excluye las direcciones de red y de broadcast (.0 y .255) del rango asignable, una convención habitual heredada de la asignación tradicional de subredes. Ajusta el CIDR al rango que tu equipo de redes te haya asignado realmente para este fin; debe ser espacio de direcciones real y enrutable desde su perspectiva, no un rango privado arbitrario que elegiste sin coordinar.

Define qué se anuncia

apiVersion: cilium.io/v2alpha1
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: Service
      service:
        addresses:
          - LoadBalancerIP
      selector:
        matchExpressions:
          - key: io.kubernetes.service.namespace
            operator: Exists

Esto anuncia la LoadBalancerIP de los Services que coincidan. El campo labels de aquí (advertise: bgp) es lo que la configuración de peers de abajo referencia para vincular ambos recursos, no una etiqueta en los Services mismos.

Define el comportamiento de los peers

apiVersion: cilium.io/v2alpha1
kind: CiliumBGPPeerConfig
metadata:
  name: bgp-peer-config
spec:
  timers:
    holdTimeSeconds: 9
    keepAliveTimeSeconds: 3
  gracefulRestart:
    enabled: true
    restartTimeSeconds: 15
  families:
    - afi: ipv4
      safi: unicast
      advertisements:
        matchLabels:
          advertise: bgp

El families.advertisements.matchLabels de aquí es lo que conecta esta configuración de peers con el recurso de anuncio definido arriba, al coincidir con su etiqueta.

Únelo todo: configuración del clúster y selección de nodos

apiVersion: cilium.io/v2alpha1
kind: CiliumBGPClusterConfig
metadata:
  name: bgp-cluster-config
spec:
  nodeSelector:
    matchLabels:
      role: bgp-node
  bgpInstances:
    - name: instance-1
      localASN: 65011
      peers:
        - name: leaf-switch-1a
          peerASN: 65002
          peerAddress: "10.10.210.2"
          peerConfigRef:
            name: bgp-peer-config
        - name: leaf-switch-1b
          peerASN: 65002
          peerAddress: "10.10.210.3"
          peerConfigRef:
            name: bgp-peer-config

nodeSelector es lo que limita el peering BGP a un subconjunto deliberado de nodos, los etiquetados como role: bgp-node, en lugar de que todos los nodos del clúster intenten hacer peering con los routers upstream:

kubectl label node worker-4 worker-5 worker-6 role=bgp-node

Un rango razonable es de dos a ocho nodos con peering, suficiente para evitar un punto único de fallo sin obligar a tu equipo de redes a configurar y mantener sesiones BGP contra cada nodo de un clúster que podría tener decenas o cientos. Cuántos tienen sentido depende de la disposición física de tu clúster: si se reparte en varios racks o filas, en general conviene hacer peering desde nodos de cada uno, en lugar de concentrar todas las sesiones BGP en un solo lugar.

Aplica los cuatro recursos y luego comprueba desde el lado de Kubernetes:

kubectl apply -f bgp-pool.yaml -f bgp-advertisement.yaml -f bgp-peer-config.yaml -f bgp-cluster-config.yaml

Verifica que la sesión realmente se estableció

Desde la perspectiva de un nodo, usando la CLI de depuración de Cilium dentro del Pod de Cilium que se ejecuta en un nodo con la etiqueta BGP:

kubectl -n kube-system exec <cilium-pod-on-bgp-node> -- cilium-dbg bgp peers

Busca un estado de sesión established. Cualquier otro (idle, connect, active) significa que la sesión realmente no se ha levantado, y las causas más comunes son una discrepancia de número de AS entre los dos lados, una dirección de peer inalcanzable, o que el router upstream simplemente aún no esté configurado para esperar a este peer; confirma que la configuración del peer en el lado de la red coincide exactamente con lo que has declarado aquí antes de asumir que la configuración del lado de Kubernetes es la incorrecta.

Confirma que una dirección realmente se está anunciando

Crea un Service LoadBalancer que tome su dirección del pool:

kubectl get svc -o wide

Su EXTERNAL-IP debería ser una dirección del CIDR del pool. Desde el router upstream (o desde lo que haya más allá, un firewall, un router core), comprueba que esa dirección aparece como una ruta /32 aprendida por BGP, anunciada desde las direcciones de los nodos con peering. Ver aparecer esa /32 concreta y llegar con éxito al Service a través de ella es la verdadera confirmación de extremo a extremo de que la asignación del pool de IP, el anuncio BGP y el enrutamiento propio de la red física están correctamente conectados entre sí, y no solo que los recursos del lado de Kubernetes se aplicaron sin errores.

Guías populares