Compartir comentarios
Las respuestas se generan en base a la documentación.

Controlador de red IPvlan

El controlador IPvlan brinda a los usuarios un control total sobre el direccionamiento tanto IPv4 como IPv6. El controlador VLAN se basa en esto para dar a los operadores un control completo del etiquetado VLAN de capa 2 e incluso del enrutamiento L3 de IPvlan para los usuarios interesados en la integración con redes underlay. Para despliegues overlay que abstraen las restricciones físicas, consulta el controlador overlay multi-host.

IPvlan es una nueva variante de la técnica de virtualización de red clásica y probada. Las implementaciones en Linux son extremadamente ligeras porque, en lugar de utilizar el bridge tradicional de Linux para el aislamiento, se asocian a una interfaz o subinterfaz Ethernet de Linux para aplicar la separación entre redes y la conectividad a la red física.

IPvlan ofrece una serie de características únicas y mucho espacio para futuras innovaciones con sus diversos modos. Dos ventajas principales de estos enfoques son las implicaciones positivas en el rendimiento al omitir el bridge de Linux y la simplicidad de tener menos partes móviles. Eliminar el bridge que tradicionalmente reside entre la tarjeta de red (NIC) del host de Docker y la interfaz del contenedor deja una configuración simple que consiste en interfaces de contenedor conectadas directamente a la interfaz del host de Docker. Este resultado es de fácil acceso para servicios expuestos externamente, ya que no es necesario realizar mapeos de puertos en estos escenarios.

Opciones

La siguiente tabla describe las opciones específicas del controlador que puedes pasar a --opt al crear una red utilizando el controlador ipvlan.

OpciónPredeterminadoDescripción
ipvlan_model2Establece el modo de funcionamiento de IPvlan. Puede ser uno de los siguientes: l2, l3, l3s
ipvlan_flagbridgeEstablece el flag de modo de IPvlan. Puede ser uno de los siguientes: bridge, private, vepa
parentEspecifica la interfaz padre (parent) que se utilizará.

Ejemplos

Requisitos previos

  • Los ejemplos de esta página son todos para un solo host.
  • Todos los ejemplos se pueden realizar en un único host que ejecute Docker. Cualquier ejemplo que utilice una subinterfaz como eth0.10 se puede reemplazar por eth0 o cualquier otra interfaz padre válida en el host de Docker. Las subinterfaces con un . se crean sobre la marcha. Las interfaces -o parent también se pueden omitir por completo en el comando docker network create y el controlador creará una interfaz virtual dummy que permitirá la conectividad del host local para realizar los ejemplos.
  • Requisitos del kernel:
    • Kernel de Linux para IPvlan v4.2+ (existe soporte para kernels anteriores, pero presenta fallos). Para comprobar la versión actual de tu kernel, utiliza uname -r.

Ejemplo de uso del modo IPvlan L2

En la siguiente imagen se muestra un ejemplo de la topología del modo IPvlan L2. El controlador se especifica con la opción -d nombre_controlador. En este caso, -d ipvlan.

Ejemplo simple de modo IPvlan L2

La interfaz padre en el siguiente ejemplo -o parent=eth0 se configura de la siguiente manera:

$ ip addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.1.250/24 brd 192.168.1.255 scope global eth0

Utiliza la red de la interfaz del host como --subnet en el comando docker network create. El contenedor se conectará a la misma red que la interfaz del host establecida a través de la opción -o parent=.

Crea la red IPvlan y ejecuta un contenedor conectado a ella:

# IPvlan (si no se especifica, -o ipvlan_mode= tiene como valor predeterminado el modo L2)
$ docker network create -d ipvlan \
    --subnet=192.168.1.0/24 \
    --gateway=192.168.1.1 \
    -o ipvlan_mode=l2 \
    -o parent=eth0 db_net

# Inicia un contenedor en la red db_net
$ docker run --net=db_net -it --rm alpine /bin/sh

# NOTA: los contenedores NO pueden hacer ping a las interfaces del host subyacente,
# ya que Linux las filtra intencionadamente para proporcionar un aislamiento adicional.

El modo predeterminado para IPvlan es l2. Si no se especifica -o ipvlan_mode=, se utilizará el modo predeterminado. Del mismo modo, si la opción --gateway se deja vacía, se establecerá como puerta de enlace la primera dirección utilizable en la red. Por ejemplo, si la subred proporcionada en la creación de la red es --subnet=192.168.1.0/24, la puerta de enlace que recibe el contenedor es 192.168.1.1.

Para ayudar a comprender cómo interactúa este modo con otros hosts, la siguiente figura muestra el mismo segmento de capa 2 entre dos hosts de Docker aplicable al modo IPvlan L2.

Múltiples hosts IPvlan

El siguiente comando creará exactamente la misma red que la red db_net creada anteriormente, con los valores predeterminados del controlador para --gateway=192.168.1.1 and -o ipvlan_mode=l2.

# IPvlan (si no se especifica, -o ipvlan_mode= tiene como valor predeterminado el modo L2)
$ docker network create -d ipvlan \
    --subnet=192.168.1.0/24 \
    -o parent=eth0 db_net_ipv

# Inicia un contenedor con un nombre explícito en modo daemon
$ docker run --net=db_net_ipv --name=ipv1 -itd alpine /bin/sh

# Inicia un segundo contenedor y haz ping utilizando el nombre del contenedor
# para ver la funcionalidad de resolución de nombres incluida en Docker
$ docker run --net=db_net_ipv --name=ipv2 -it --rm alpine /bin/sh
$ ping -c 4 ipv1

# NOTA: los contenedores NO pueden hacer ping a las interfaces del host subyacente,
# ya que Linux las filtra intencionadamente para proporcionar un aislamiento adicional.

Los controladores también admiten el flag --internal, que aislará por completo a los contenedores de una red de cualquier comunicación externa a dicha red. Dado que el aislamiento de la red está estrechamente vinculado a la interfaz padre de la red, omitir la opción -o parent= en un comando docker network create produce el mismo resultado que la opción --internal. Si no se especifica la interfaz padre o si se utiliza el flag --internal, se creará una interfaz padre de tipo netlink dummy y se utilizará como interfaz padre, aislando la red por completo de forma efectiva.

Los siguientes dos ejemplos de docker network create dan como resultado redes idénticas a las que puedes conectar contenedores:

# Un '-o parent=' vacío crea una red aislada
$ docker network create -d ipvlan \
    --subnet=192.168.10.0/24 isolated1

# El flag explícito '--internal' produce el mismo resultado:
$ docker network create -d ipvlan \
    --subnet=192.168.11.0/24 --internal isolated2

# Incluso se puede dejar vacía la opción '--subnet=' y se asignará la subred
# IPAM predeterminada de 172.18.0.0/16
$ docker network create -d ipvlan isolated3

$ docker run --net=isolated1 --name=cid1 -it --rm alpine /bin/sh
$ docker run --net=isolated2 --name=cid2 -it --rm alpine /bin/sh
$ docker run --net=isolated3 --name=cid3 -it --rm alpine /bin/sh

# Para conectarte a cualquiera de ellos, utiliza `docker exec` e inicia una shell
$ docker exec -it cid1 /bin/sh
$ docker exec -it cid2 /bin/sh
$ docker exec -it cid3 /bin/sh

Ejemplo de uso del modo L2 con troncal 802.1Q de IPvlan

Arquitectónicamente, el enlace troncal (trunking) en el modo IPvlan L2 es idéntico a Macvlan en lo que respecta a las puertas de enlace y al aislamiento de rutas L2. Existen matices que pueden resultar ventajosos, como la reducción de la presión sobre la tabla CAM en los conmutadores ToR, una dirección MAC por puerto y la prevención del agotamiento de MAC en la tarjeta de red padre de un host, por nombrar algunos. El escenario del troncal 802.1Q tiene el mismo aspecto. Ambos modos cumplen con los estándares de etiquetado y ofrecen una integración fluida con la red física para la integración de underlay y las integraciones de complementos de proveedores de hardware.

Los hosts de la misma VLAN suelen estar en la misma subred y casi siempre se agrupan en función de su política de seguridad. En la mayoría de los escenarios, una aplicación multinivel se divide en diferentes subredes porque el perfil de seguridad de cada proceso requiere alguna forma de aislamiento. Por ejemplo, alojar el procesamiento de tarjetas de crédito en la misma red virtual que el servidor web frontend representaría un problema de cumplimiento normativo, además de eludir la práctica recomendada de diseñar arquitecturas de defensa en profundidad en capas. Las VLAN, o el equivalente VNI (Virtual Network Identifier) cuando se utiliza el controlador Overlay, son el primer paso para aislar el tráfico de los inquilinos.

VLANs de Docker en detalle

La subinterfaz de Linux etiquetada con una VLAN puede existir previamente o se creará cuando ejecutes un comando docker network create. El comando docker network rm eliminará la subinterfaz. Las interfaces padre como eth0 no se eliminan, solo las subinterfaces con un índice de red padre de netlink > 0.

Para que el controlador descuente o elimine las subinterfaces VLAN, el formato debe ser nombre_interfaz.etiqueta_vlan. Se pueden utilizar otros nombres de subinterfaz como el padre especificado, pero el enlace no se eliminará automáticamente al invocar docker network rm.

La opción de utilizar subinterfaces VLAN padre ya existentes o dejar que Docker las gestione te permite administrar por completo las interfaces y redes de Linux, o bien permitir que Docker cree y elimine las subinterfaces VLAN padre (vía netlink ip link) sin esfuerzo por tu parte.

Por ejemplo: utiliza eth0.10 para denotar una subinterfaz de eth0 etiquetada con el ID de VLAN 10. El comando ip link equivalente sería ip link add link eth0 name eth0.10 type vlan id 10.

El ejemplo crea las redes etiquetadas con VLAN y luego inicia dos contenedores para probar la conectividad entre ellos. Contenedores en diferentes VLAN no pueden hacer ping entre sí sin un enrutador que encamine el tráfico entre ambas redes. El espacio de nombres predeterminado no es accesible por diseño en IPvlan con el fin de aislar los espacios de nombres de los contenedores del host subyente.

ID de VLAN 20

En la primera red etiquetada e aislada por el host de Docker, eth0.20 es la interfaz padre etiquetada con el ID de VLAN 20 especificado con -o parent=eth0.20. Se pueden utilizar otros formatos de nombre, pero los enlaces deben añadirse y eliminarse manualmente mediante ip link o archivos de configuración de Linux. Mientras exista el -o parent, se puede utilizar cualquier nombre que cumpla con netlink de Linux.

# Ahora añade redes y hosts de la forma habitual conectándolos a la interfaz (subinterfaz) maestra que está etiquetada
$ docker network create -d ipvlan \
    --subnet=192.168.20.0/24 \
    --gateway=192.168.20.1 \
    -o parent=eth0.20 ipvlan20

# En dos terminales separadas, inicia un contenedor Docker; ahora los contenedores pueden hacer ping entre sí.
$ docker run --net=ipvlan20 -it --name ivlan_test1 --rm alpine /bin/sh
$ docker run --net=ipvlan20 -it --name ivlan_test2 --rm alpine /bin/sh

ID de VLAN 30

En la segunda red, etiquetada e aislada por el host de Docker, eth0.30 es la interfaz padre etiquetada con el ID de VLAN 30 especificado con -o parent=eth0.30. El parámetro ipvlan_mode= tiene como valor predeterminado el modo L2 (ipvlan_mode=l2). También se puede configurar explícitamente con el mismo resultado, como se muestra en el siguiente ejemplo.

# Ahora añade redes y hosts de la forma habitual conectándolos a la interfaz (subinterfaz) maestra que está etiquetada.
$ docker network create -d ipvlan \
    --subnet=192.168.30.0/24 \
    --gateway=192.168.30.1 \
    -o parent=eth0.30 \
    -o ipvlan_mode=l2 ipvlan30

# En dos terminales separadas, inicia un contenedor Docker; ahora los contenedores pueden hacer ping entre sí.
$ docker run --net=ipvlan30 -it --name ivlan_test3 --rm alpine /bin/sh
$ docker run --net=ipvlan30 -it --name ivlan_test4 --rm alpine /bin/sh

La puerta de enlace se establece dentro del contenedor como la puerta de enlace predeterminada. Esa puerta de enlace sería normalmente un enrutador externo en la red.

$$ ip route
  default via 192.168.30.1 dev eth0
  192.168.30.0/24 dev eth0  src 192.168.30.2

Ejemplo: IPvlan en modo L2 multi-subred iniciando dos contenedores en la misma subred y haciendo ping entre sí. Para que la subred 192.168.114.0/24 se comunique con 192.168.116.0/24, se requiere un enrutador externo en el modo L2. El modo L3 puede enrutar entre subredes que comparten un elemento común -o parent=.

Las direcciones secundarias en los enrutadores de red son comunes cuando el espacio de direcciones se agota, para añadir otra dirección secundaria a una interfaz VLAN L3 (comúnmente denominada "interfaz virtual conmutada" o SVI).

$ docker network create -d ipvlan \
    --subnet=192.168.114.0/24 --subnet=192.168.116.0/24 \
    --gateway=192.168.114.254 --gateway=192.168.116.254 \
    -o parent=eth0.114 \
    -o ipvlan_mode=l2 ipvlan114

$ docker run --net=ipvlan114 --ip=192.168.114.10 -it --rm alpine /bin/sh
$ docker run --net=ipvlan114 --ip=192.168.114.11 -it --rm alpine /bin/sh

Un aspecto clave es que los operadores tienen la capacidad de mapear su red física en su red virtual para integrar contenedores en su entorno sin necesidad de realizar cambios operativos significativos. NetOps introduce un troncal 802.1Q en el host de Docker. Ese enlace virtual sería el parámetro -o parent= proporcionado en la creación de la red. Para enlaces sin etiquetar (sin VLAN), es tan sencillo como utilizar -o parent=eth0 o para troncales 802.1Q con identificadores de VLAN, cada red se mapea a la VLAN/Subred correspondiente de la red.

Como ejemplo, NetOps proporciona el ID de VLAN y las subredes asociadas para las VLAN que se transmiten en el enlace Ethernet hacia el servidor del host de Docker. Esos valores se especifican en los comandos docker network create al aprovisionar las redes de Docker. Estas son configuraciones persistentes que se aplican cada vez que se inicia el motor de Docker, lo que evita tener que gestionar archivos de configuración complejos. Las interfaces de red también se pueden gestionar manualmente creándolas previamente, y el sistema de red de Docker nunca las modificará, utilizándolas simplemente como interfaces padre. Los mapeos de ejemplo de NetOps a comandos de red de Docker son los siguientes:

  • VLAN: 10, Subred: 172.16.80.0/24, Puerta de enlace: 172.16.80.1
    • --subnet=172.16.80.0/24 --gateway=172.16.80.1 -o parent=eth0.10
  • VLAN: 20, Subred IP: 172.16.50.0/22, Puerta de enlace: 172.16.50.1
    • --subnet=172.16.50.0/22 --gateway=172.16.50.1 -o parent=eth0.20
  • VLAN: 30, Subred: 10.1.100.0/16, Puerta de enlace: 10.1.100.1
    • --subnet=10.1.100.0/16 --gateway=10.1.100.1 -o parent=eth0.30

Ejemplo del modo IPvlan L3

IPvlan requerirá que las rutas se distribuyan a cada extremo. El controlador solo compila el puerto del modo IPvlan L3 y conecta el contenedor a la interfaz. La distribución de rutas en un clúster está fuera del alcance de la implementación inicial de este controlador acotado a un único host. En el modo L3, el host de Docker actúa de manera muy similar a un enrutador que inicia nuevas redes en el contenedor. Estas se encuentran en redes que la red ascendente no conocerá sin una distribución de rutas. Para quienes tengan curiosidad sobre cómo encajará IPvlan L3 en la red de contenedores, consulten los siguientes ejemplos.

Modo IPvlan L2 de Docker

El modo IPvlan L3 descarta todo el tráfico de difusión (broadcast) y multidifusión (multicast). Solo por esta razón, el modo IPvlan L3 es un candidato ideal para quienes buscan una integración de red a gran escala y predecible. Es predecible y, a su vez, conducirá a un mayor tiempo de actividad porque no implica bridging. Los bucles de bridging han sido responsables de interrupciones importantes que pueden ser difíciles de localizar según el tamaño del dominio de fallo. Esto se debe a la naturaleza en cascada de las BPDU (Bridge Port Data Units) que se inundan en un dominio de difusión (VLAN) para encontrar y bloquear bucles de topología. Eliminar los dominios de bridging o, como mínimo, mantenerlos aislados en un par de ToR (conmutadores en la parte superior del rack) reducirá las inestabilidades de bridging difíciles de depurar. El modo IPvlan L2 es adecuado para VLAN aisladas conectadas solo a un par de ToR que puedan proporcionar una estructura sin bucles y sin bloqueos. El paso siguiente es enrutar en el extremo a través del modo IPvlan L3, lo que reduce el dominio de fallos a un host local únicamente.

  • El modo L3 debe estar en una subred diferente a la del espacio de nombres predeterminado, ya que requiere una ruta netlink en el espacio de nombres predeterminado que apunte a la interfaz padre de IPvlan.
  • La interfaz padre utilizada en este ejemplo es eth0 y está en la subred 192.168.1.0/24. Observa que la red de Docker (docker network) no está en la misma subred que eth0.
  • A diferencia de los modos IPvlan L2, diferentes subredes/redes pueden hacer ping entre sí siempre que compartan la misma interfaz padre -o parent=.
$$ ip a show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:50:56:39:45:2e brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.250/24 brd 192.168.1.255 scope global eth0
  • Una puerta de enlace tradicional no significa mucho para una interfaz IPvlan en modo L3, ya que no se permite el tráfico de difusión. Debido a esto, la puerta de enlace predeterminada del contenedor apunta al dispositivo eth0 del contenedor. Consulta a continuación la salida de CLI de ip route o ip -6 route desde el interior de un contenedor L3 para obtener más detalles.

El modo -o ipvlan_mode=l3 debe especificarse explícitamente, ya que el modo predeterminado de IPvlan es l2.

El siguiente ejemplo no especifica una interfaz padre. Los controladores de red crearán un enlace de tipo dummy para el usuario en lugar de rechazar la creación de la red y limitar a los contenedores a comunicarse únicamente entre sí.

# Crea la red IPvlan L3
$ docker network create -d ipvlan \
    --subnet=192.168.214.0/24 \
    --subnet=10.1.214.0/24 \
    -o ipvlan_mode=l3 ipnet210

# Prueba la conectividad de 192.168.214.0/24
$ docker run --net=ipnet210 --ip=192.168.214.10 -itd alpine /bin/sh
$ docker run --net=ipnet210 --ip=10.1.214.10 -itd alpine /bin/sh

# Prueba la conectividad L3 de 10.1.214.0/24 a 192.168.214.0/24
$ docker run --net=ipnet210 --ip=192.168.214.9 -it --rm alpine ping -c 2 10.1.214.10

# Prueba la conectividad L3 de 192.168.214.0/24 a 10.1.214.0/24
$ docker run --net=ipnet210 --ip=10.1.214.9 -it --rm alpine ping -c 2 192.168.214.10
Note

Observa que no hay ninguna opción --gateway= en la creación de la red. El campo se ignora si se especifica en el modo l3. Echa un vistazo a la tabla de enrutamiento del contenedor desde el interior del contenedor:

# Dentro de un contenedor en modo L3
$$ ip route
 default dev eth0
  192.168.214.0/24 dev eth0  src 192.168.214.10

Para poder hacer ping a los contenedores desde un host de Docker remoto o para que el contenedor pueda hacer ping a un host remoto, el host remoto o la red física intermedia deben tener una ruta que apunte a la dirección IP de la interfaz Ethernet del host de Docker del contenedor.

Modo IPvlan L2 con doble pila IPv4/IPv6

  • Libnetwork no solo te ofrece un control completo sobre el direccionamiento IPv4, sino que también te brinda un control total sobre el direccionamiento IPv6, así como paridad de características entre ambas familias de direcciones.

  • El siguiente ejemplo comenzará únicamente con IPv6. Inicia dos contenedores en la misma VLAN 139 y haz ping entre ellos. Dado que no se especifica la subred IPv4, el IPAM predeterminado aprovisionará una subred IPv4 predeterminada. Esa subred estará aislada a menos que la red ascendente la enrute explícitamente en la VLAN 139.

# Crea una red v6
$ docker network create -d ipvlan \
    --ipv6 --subnet=2001:db8:abc2::/64 --gateway=2001:db8:abc2::22 \
    -o parent=eth0.139 v6ipvlan139

# Inicia un contenedor en la red
$ docker run --net=v6ipvlan139 -it --rm alpine /bin/sh

Visualiza la interfaz eth0 del contenedor y la tabla de enrutamiento v6:

# Dentro del contenedor IPv6
$$ ip a show eth0
75: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc2::1/64 scope link nodad
       valid_lft forever preferred_lft forever

$$ ip -6 route
2001:db8:abc4::/64 dev eth0  proto kernel  metric 256
2001:db8:abc2::/64 dev eth0  proto kernel  metric 256
default via 2001:db8:abc2::22 dev eth0  metric 1024

Inicia un segundo contenedor y haz ping a la dirección v6 del primer contenedor.

# Prueba la conectividad L2 sobre IPv6
$ docker run --net=v6ipvlan139 -it --rm alpine /bin/sh

# Dentro del segundo contenedor IPv6
$$ ip a show eth0
75: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.3/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link tentative dadfailed
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc2::2/64 scope link nodad
       valid_lft forever preferred_lft forever

$$ ping6 2001:db8:abc2::1
PING 2001:db8:abc2::1 (2001:db8:abc2::1): 56 data bytes
64 bytes from 2001:db8:abc2::1%eth0: icmp_seq=0 ttl=64 time=0.044 ms
64 bytes from 2001:db8:abc2::1%eth0: icmp_seq=1 ttl=64 time=0.058 ms

2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.044/0.051/0.058/0.000 ms

El siguiente ejemplo configurará una red de doble pila IPv4/IPv6 con un ID de VLAN de ejemplo de 140.

A continuación, crea una red con dos subredes IPv4 y una subred IPv6, todas las cuales tienen puertas de enlace explícitas:

$ docker network create -d ipvlan \
    --subnet=192.168.140.0/24 --subnet=192.168.142.0/24 \
    --gateway=192.168.140.1 --gateway=192.168.142.1 \
    --subnet=2001:db8:abc9::/64 --gateway=2001:db8:abc9::22 \
    -o parent=eth0.140 \
    -o ipvlan_mode=l2 ipvlan140

Inicia un contenedor y visualiza eth0 y las tablas de enrutamiento tanto v4 como v6:

$ docker run --net=ipvlan140 --ip6=2001:db8:abc2::51 -it --rm alpine /bin/sh

$ ip a show eth0
78: eth0@if77: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 192.168.140.2/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc9::1/64 scope link nodad
       valid_lft forever preferred_lft forever

$$ ip route
default via 192.168.140.1 dev eth0
192.168.140.0/24 dev eth0  proto kernel  scope link  src 192.168.140.2

$$ ip -6 route
2001:db8:abc4::/64 dev eth0  proto kernel  metric 256
2001:db8:abc9::/64 dev eth0  proto kernel  metric 256
default via 2001:db8:abc9::22 dev eth0  metric 1024

Inicia un segundo contenedor con una dirección --ip específica y haz ping al primer host utilizando paquetes IPv4:

$ docker run --net=ipvlan140 --ip=192.168.140.10 -it --rm alpine /bin/sh
Note

Las diferentes subredes en la misma interfaz padre en el modo L2 de IPvlan no pueden hacer ping entre sí. Eso requiere un enrutador para responder con ARP proxy a las solicitudes con una subred secundaria. Sin embargo, IPvlan en modo L3 enrutará el tráfico de unidifusión entre subredes dispares siempre que compartan el mismo enlace padre -o parent.

Modo IPvlan L3 con doble pila IPv4/IPv6

Ejemplo: modo IPvlan L3 de doble pila IPv4/IPv6, multi-subred con etiqueta VLAN 802.1Q: 118

Como en todos los ejemplos, no es obligatorio utilizar una interfaz VLAN etiquetada. Las subinterfaces se pueden intercambiar por eth0, eth1, bond0 o cualquier otra interfaz válida en el host que no sea el bucle de retorno lo.

La diferencia principal que observarás es que el modo L3 no crea una ruta predeterminada con un siguiente salto (next-hop), sino que establece una ruta predeterminada que apunta únicamente a dev eth, ya que ARP, las difusiones y las multidifusiones son filtradas por Linux según el diseño. Dado que la interfaz padre actúa esencialmente como un enrutador, la IP y la subred de la interfaz padre deben ser diferentes de las redes de los contenedores. Esto es lo opuesto a los modos bridge y L2, que deben estar en la misma subred (dominio de difusión) para poder reenviar paquetes de difusión y multidifusión.

# Crea una red IPvlan L3 de doble pila IPv6+IPv4
# Las puertas de enlace para v4 y v6 se configuran en un dispositivo, por ejemplo, 'default dev eth0'
$ docker network create -d ipvlan \
    --subnet=192.168.110.0/24 \
    --subnet=192.168.112.0/24 \
    --ipv6 --subnet=2001:db8:abc6::/64 \
    -o parent=eth0 \
    -o ipvlan_mode=l3 ipnet110

# Inicia algunos contenedores en la red (ipnet110) en terminales separadas y verifica la conectividad
$ docker run --net=ipnet110 -it --rm alpine /bin/sh
# Inicia un segundo contenedor especificando la dirección v6
$ docker run --net=ipnet110 --ip6=2001:db8:abc6::10 -it --rm alpine /bin/sh
# Inicia un tercero especificando la dirección IPv4
$ docker run --net=ipnet110 --ip=192.168.112.30 -it --rm alpine /bin/sh
# Inicia un cuarto especificando tanto la dirección IPv4 como la IPv6
$ docker run --net=ipnet110 --ip6=2001:db8:abc6::50 --ip=192.168.112.50 -it --rm alpine /bin/sh

Las salidas de la interfaz y de la tabla de enrutamiento son las siguientes:

$$ ip a show eth0
63: eth0@if59: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 192.168.112.2/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc6::10/64 scope link nodad
       valid_lft forever preferred_lft forever

# Ten en cuenta que la ruta predeterminada es el dispositivo eth porque los ARP están filtrados.
$$ ip route
  default dev eth0  scope link
  192.168.112.0/24 dev eth0  proto kernel  scope link  src 192.168.112.2

$$ ip -6 route
2001:db8:abc4::/64 dev eth0  proto kernel  metric 256
2001:db8:abc6::/64 dev eth0  proto kernel  metric 256
default dev eth0  metric 1024
Note

Puede haber un error al especificar direcciones --ip6=: cuando eliminas un contenedor con una dirección v6 especificada y luego inicias un nuevo contenedor con la misma dirección v6, se produce un error que indica que la dirección no se está liberando correctamente en el grupo de v6. Esto causará un fallo al desmontar el contenedor y este quedará en un estado inactivo.

docker: Error response from daemon: Address already in use.

Crear enlaces 802.1Q manualmente

ID de VLAN 40

Si un usuario no desea que el controlador cree la subinterfaz VLAN, esta debe existir antes de ejecutar docker network create. Si tienes una nomenclatura de subinterfaz que no es interfaz.id_vlan, se respetará en la opción -o parent= siempre que la interfaz exista y esté activa.

Los enlaces, cuando se crean manualmente, pueden nombrarse de cualquier forma siempre que existan cuando se cree la red. Los enlaces creados manualmente no se eliminan al suprimir la red con docker network rm, independientemente de su nombre.

# Crea una nueva subinterfaz vinculada a dot1q vlan 40
$ ip link add link eth0 name eth0.40 type vlan id 40

# Activa la nueva subinterfaz
$ ip link set eth0.40 up

# Ahora añade redes y hosts de la forma habitual conectándolos a la interfaz (subinterfaz) maestra que está etiquetada
$ docker network create -d ipvlan \
    --subnet=192.168.40.0/24 \
    --gateway=192.168.40.1 \
    -o parent=eth0.40 ipvlan40

# En dos terminales separadas, inicia un contenedor Docker; ahora los contenedores pueden hacer ping entre sí.
$ docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
$ docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh

Ejemplo: subinterfaz VLAN creada manualmente con cualquier nombre:

# Crea una nueva subinterfaz vinculada a dot1q vlan 40
$ ip link add link eth0 name foo type vlan id 40

# Activa la nueva subinterfaz
$ ip link set foo up

# Ahora añade redes y hosts de la forma habitual conectándolos a la interfaz (subinterfaz) maestra que está etiquetada
$ docker network create -d ipvlan \
    --subnet=192.168.40.0/24 --gateway=192.168.40.1 \
    -o parent=foo ipvlan40

# En dos terminales separadas, inicia un contenedor Docker; ahora los contenedores pueden hacer ping entre sí.
$ docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
$ docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh

Los enlaces creados manualmente se pueden limpiar con:

$ ip link del foo

Al igual que con todos los controladores de Libnetwork, se pueden mezclar y combinar, incluso ejecutando controladores del ecosistema de terceros en paralelo para obtener la máxima flexibilidad para el usuario de Docker.