
No hace mucho tiempo, me encontré con una tarea bastante inusual: configurar el enrutamiento para MetalLB. No sería un problema, ya que normalmente no se requiere ninguna acción adicional para MetalLB, pero en nuestro caso, tenemos un clúster bastante grande con una configuración de red bastante sencilla.
En este artículo, explicaré cómo configurar el enrutamiento basado en la fuente y basado en políticas para la red externa de su clúster.
No me detendré en la instalación y configuración de MetalLB, ya que supongo que ya tiene algo de experiencia. Propongo que vayamos directamente al grano, es decir, a la configuración del enrutamiento. Así que tenemos cuatro casos:
Caso 1: Cuando no se requiere configuración
Analicemos un caso simple.

No se requiere configuración adicional de enrutamiento cuando las direcciones proporcionadas por MetalLB están en la misma subred que las direcciones de sus nodos.
Por ejemplo, tiene la subred 192.168.1.0/24, hay un enrutador en ella 192.168.1.1, y sus nodos obtienen direcciones: 192.168.1.10-30, entonces para MetalLB usted puede configurar el rango 192.168.1.100-120 y estar seguro de que funcionarán sin ninguna configuración adicional.
¿Por qué es así? Porque sus nodos ya tienen rutas configuradas:
# ip route
default via 192.168.1.1 dev eth0 onlink
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.10Y las direcciones del mismo rango reutilizarán esas sin ningún movimiento adicional.
Caso 2: Cuando se requiere configuración adicional

Debe configurar rutas adicionales cada vez que sus nodos no tengan configurada una IP o ruta a la subred para la que MetalLB proporciona direcciones.
Permítanme explicar con más detalle. Cada vez que MetalLB proporciona una dirección, esto se puede comparar con una asignación simple como:
ip addr add 10.9.8.7/32 dev loPreste atención a:
- a) La dirección se asigna con un prefijo
/32es decir, la ruta a la subred para ella no se añadirá automáticamente (esto es solo una dirección) - b) La dirección se asigna a cualquier interfaz del nodo (por ejemplo, loopback). Aquí vale la pena mencionar la particularidad de la pila de red de Linux. No importa en qué interfaz agregue la dirección, el núcleo siempre procesará las solicitudes ARP y enviará respuestas ARP a cualquiera de ellas, este comportamiento se considera correcto y, además, se utiliza ampliamente en un entorno dinámico como Kubernetes.
Este comportamiento se puede configurar, por ejemplo, activando el arp estricto:
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announceEn este caso, las respuestas arp se enviarán solo si la interfaz contiene explícitamente una dirección IP específica. Esta configuración es obligatoria si planea utilizar MetalLB y su kube-proxy funciona en modo IPVS.
Sin embargo, MetalLB no utiliza el núcleo para procesar solicitudes arp, sino que lo hace de manera independiente en user-space, por lo que esta opción no afectará el funcionamiento de MetalLB.
Volvamos a nuestra tarea. Si no existe una ruta para las direcciones emitidas en sus nodos, agréguelas de antemano en todos los nodos:
ip route add 10.9.8.0/24 dev eth1Caso 3: Cuando se necesite el enrutamiento basado en la fuente
El enrutamiento basado en la fuente deberá configurarse cuando reciba paquetes a través de una puerta de enlace separada, diferente de la que tiene configurada como predeterminada; en consecuencia, los paquetes de respuesta también deberán salir a través de esta misma puerta de enlace.
Por ejemplo, tiene la misma subred 192.168.1.0/24 asignada a sus nodos, pero desea emitir direcciones externas utilizando MetalLB. Supongamos que tiene varias direcciones de la subred 1.2.3.0/24 ubicadas en la VLAN 100, y desea utilizarlas para acceder a los servicios de Kubernetes desde el exterior.

Al hacer una solicitud a 1.2.3.4 realizará solicitudes desde una subred diferente a 1.2.3.0/24 y esperará una respuesta. El nodo que actualmente es el maestro para la dirección emitida por MetalLB 1.2.3.4, recibirá el paquete del enrutador 1.2.3.1, pero la respuesta debe salir por el mismo camino, a través de 1.2.3.1.
Dado que nuestro nodo ya tiene configurada una puerta de enlace predeterminada 192.168.1.1, por defecto la respuesta irá a ella, y no a 1.2.3.1, a través de la cual recibimos el paquete.
¿Cómo lidiar con esta situación?
En este caso, deberá preparar todos sus nodos para que estén listos para servir direcciones externas sin configuración adicional. Es decir, para el ejemplo anterior, debe crear un interfaz VLAN de antemano en el nodo:
ip link add link eth0 name eth0.100 type vlan id 100
ip link set eth0.100 upY luego agregar rutas:
ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100Tenga en cuenta que las rutas se agregan en una tabla de enrutamiento separada 100 que solo contendrá las dos rutas necesarias para enviar el paquete de respuesta a través de la puerta de enlace 1.2.3.1, que está detrás de la interfaz eth0.100.
Ahora necesitamos agregar una regla simple:
ip rule add from 1.2.3.0/24 lookup 100que indica explícitamente: si la dirección de origen del paquete se encuentra en 1.2.3.0/24, se debe utilizar la tabla de enrutamiento 100. Ya hemos descrito la ruta que lo enviará a través de 1.2.3.1
Caso 4: Cuándo se necesitará el enrutamiento basado en políticas
La topología de la red es como en el ejemplo anterior, pero supongamos que también desea tener la posibilidad de acceder a direcciones externas del pool 1.2.3.0/24 desde sus pods:

La particularidad es que al acceder a cualquier dirección en 1.2.3.0/24, el paquete de respuesta, al llegar al nodo y tener la dirección de origen en el rango 1.2.3.0/24 será enviado obedientemente a eth0.100, pero queremos que Kubernetes lo redirija a nuestro primer pod, que generó la solicitud original.
Resolver este problema resultó complicado, pero fue posible gracias al enrutamiento basado en políticas:
Para una mejor comprensión del proceso, presentaré un diagrama de bloques de netfilter:

Primero, como en el ejemplo anterior, crearemos una tabla de enrutamiento adicional:
ip route add 1.2.3.0/24 dev eth0.100 table 100
ip route add default via 1.2.3.1 table 100Ahora agregaremos algunas reglas en iptables:
iptables -t mangle -A PREROUTING -i eth0.100 -j CONNMARK --set-mark 0x100
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j RETURN
iptables -t mangle -A POSTROUTING -j CONNMARK --save-markEstas reglas marcarán las conexiones entrantes en la interfaz eth0.100, marcando todos los paquetes con la etiqueta 0x100, esta misma etiqueta también marcará las respuestas en el marco de una conexión.
Ahora podemos agregar una regla de enrutamiento:
ip rule add from 1.2.3.0/24 fwmark 0x100 lookup 100Es decir, todos los paquetes con la dirección de origen 1.2.3.0/24 y la etiqueta 0x100 deben ser enrutados utilizando la tabla 100.
De este modo, otros paquetes recibidos en otra interfaz no caerán bajo esta regla, lo que les permitirá ser enrutados con los medios estándar de Kubernetes.
Hay un pero: en Linux existe lo que se llama filtro de ruta inversa, que estropea todo ya que realiza una simple verificación: para todos los paquetes entrantes cambia la dirección de origen del paquete con la dirección del remitente y verifica si el paquete puede salir por la misma interfaz por la que fue recibido; si no, lo filtra.
El problema es que en nuestro caso funcionará incorrectamente, pero podemos desactivarlo:
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth0.100/rp_filterNota: el primer comando controla el comportamiento global del rp_filter; si no se desactiva, el segundo comando no tendrá ningún efecto. Sin embargo, las otras interfaces permanecerán con el rp_filter activado.
Para no limitar completamente el funcionamiento del filtro, podemos utilizar la implementación de rp_filter para netfilter. Al usar rpfilter como un módulo de iptables, se pueden configurar reglas bastante flexibles, por ejemplo:
iptables -t raw -A PREROUTING -i eth0.100 -d 1.2.3.0/24 -j RETURN
iptables -t raw -A PREROUTING -i eth0.100 -m rpfilter --invert -j DROPactivar rp_filter en la interfaz eth0.100 para todas las direcciones excepto 1.2.3.0/24.
Fuente: habr.com
