Información de contexto
Tengo un servidor con dos interfaces de red que ejecuta Docker. Docker, como algunas herramientas de virtualización, crea una interfaz de puente de Linux llamada docker0
. Esta interfaz está configurada de manera predeterminada con una IP 172.17.42.1
y todos los contenedores Docker se comunican con esta interfaz como su puerta de enlace y se les asignan direcciones IP en el mismo /16
rango. Según tengo entendido, todo el tráfico de red hacia / desde los contenedores pasa a través de un NAT, por lo que parece que proviene de salida 172.17.42.1
y de entrada se envía 172.17.42.1
.
Mi configuración se ve así:
+------------+ /
| | |
+-------------+ Gateway 1 +-------
| | 10.1.1.1 | /
+------+-------+ +------------+ |
| eth0 | /
| 10.1.1.2 | |
| | |
| DOCKER HOST | |
| | | Internet
| docker0 | |
| (bridge) | |
| 172.17.42.1 | |
| | |
| eth1 | |
| 192.168.1.2 | \
+------+-------+ +------------+ |
| | | \
+-------------+ Gateway 2 +-------
| 192.168.1.1| |
+------------+
El problema
Quiero enrutar todo el tráfico desde / hacia cualquier contenedor Docker desde la segunda eth1
192.168.1.2
interfaz a una puerta de enlace predeterminada 192.168.1.1
, mientras que todo el tráfico desde / hacia la máquina host sale de la eth0
10.1.1.2
interfaz a una puerta de enlace predeterminada 10.1.1.1
. He intentado una variedad de cosas hasta ahora en vano, pero creo que lo más parecido a corregir es usar iproute2 así:
# Create a new routing table just for docker
echo "1 docker" >> /etc/iproute2/rt_tables
# Add a rule stating any traffic from the docker0 bridge interface should use
# the newly added docker routing table
ip rule add from 172.17.42.1 table docker
# Add a route to the newly added docker routing table that dictates all traffic
# go out the 192.168.1.2 interface on eth1
ip route add default via 192.168.1.2 dev eth1 table docker
# Flush the route cache
ip route flush cache
# Restart the Docker daemon so it uses the correct network settings
# Note, I do this as I found Docker containers often won't be able
# to connect out if any changes to the network are made while it's
# running
/etc/init.d/docker restart
Cuando saco un contenedor, no puedo hacer ping fuera de él después de hacer esto. No estoy seguro de si las interfaces de puente se manejan de la misma manera que las interfaces físicas para este tipo de enrutamiento, y solo quiero una verificación de la cordura, así como algún consejo sobre cómo podría llevar a cabo esta tarea aparentemente simple.
Respuestas:
Es posible que también tenga que buscar más en la configuración de iptables. Docker enmascara todo el tráfico que se origina en la subred del contenedor, digamos 172.17.0.0/16, a 0.0.0.0. Si ejecuta
iptables -L -n -t nat
, puede ver la cadena POSTROUTING en la tabla nat que hace esto:Ahora, puede eliminar esta regla y reemplazarla con una regla que enmascara todo el tráfico que se origina desde la subred de los contenedores a la IP de su segunda interfaz - 192.168.1.2, ya que eso es lo que desea. La regla de eliminación será, suponiendo que es la primera regla en la cadena POSTROUTING:
Luego agrega esta regla personalizada:
fuente
ip rule add from 172.17.0.0/16 table docker
ip route add default via 192.168.1.2 dev eth1 table docker
ip route flush cache
iptables -t nat -D POSTROUTING 1
iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT --to-source 192.168.1.2
/etc/init.d/docker restart
. Luego intenté ejecutar un ping y un trazado de ruta desde un contenedor, y no pude alcanzar nada.Un amigo y yo nos encontramos con este problema exacto en el que queríamos que Docker admitiera múltiples solicitudes de servicio de interfaces de red. Estábamos trabajando específicamente con el servicio AWS EC2 donde también estábamos conectando / configurando / sacando a la luz las interfaces adicionales. En este proyecto , hay más de lo que necesita, por lo que trataré de incluir solo lo que necesita aquí.
Primero, lo que hicimos fue crear una tabla de ruta separada para
eth1
:A continuación, configuramos la tabla de cambios para establecer algunas marcas de conexión que provienen de
eth1
:Finalmente, agregamos esta regla para que todos los
fwmark
s utilicen la nueva tabla que creamos.El siguiente
iptables
comando restaurará la marca de conexión y luego permitirá que la regla de enrutamiento use la tabla de enrutamiento correcta.Creo que esto es todo lo que se necesita de nuestro ejemplo más complejo donde (como dije) nuestro proyecto fue adjuntar / configurar / abrir la
eth1
interfaz en el momento del arranque.Ahora, este ejemplo no impedirá que las conexiones
eth0
atiendan las solicitudes,docker0
pero creo que podría agregar una regla de enrutamiento para evitar eso.fuente
La mascarada no es de 172.17.42.1 sino más bien
Lo que significa que esta regla no funcionará bien.
Intenta en su lugar
fuente
ip rule add from 172.17.0.0/16 table docker
ip route add default via 192.168.1.2 dev eth1 table docker
ip route flush cache
/etc/init.d/docker restart
desde el contenedor ejecuté un traceroute y el primer salto fue 10.1.1.1 cuando debería haber sido 192.168.1.1