# Controlador de red Macvlan


Algunas aplicaciones, en especial las heredadas o aquellas que monitorizan el tráfico de red, esperan estar conectadas directamente a la red física. En este tipo de situaciones, puedes utilizar el controlador de red `macvlan` para asignar una dirección MAC a la interfaz de red virtual de cada contenedor, haciendo que parezca una interfaz de red física conectada directamente a la red física. En este caso, debes designar una interfaz física en tu host de Docker para utilizarla con Macvlan, así como la subred y la puerta de enlace de la red. Incluso puedes aislar tus redes Macvlan utilizando diferentes interfaces de red físicas.

## Compatibilidad de plataformas y requisitos

- El controlador macvlan solo funciona en hosts Linux. No es compatible con Docker Desktop para Mac o Windows, ni con Docker Engine en Windows.
- La mayoría de los proveedores de la nube bloquean las redes macvlan. Es posible que necesites acceso físico a tus equipos de red.
- Requiere al menos la versión 3.9 del kernel de Linux (se recomienda la versión 4.0 o posterior).
- El controlador macvlan no es compatible con el modo rootless (sin privilegios de root).

## Consideraciones

- Podrías degradar involuntariamente tu red debido al agotamiento de direcciones IP o a la "propagación de VLAN" (VLAN spread), una situación que ocurre cuando tienes una cantidad excesivamente alta de direcciones MAC únicas en tu red.
- Tus equipos de red deben ser capaces de admitir el "modo promiscuo", donde a una sola interfaz física se le pueden asignar múltiples direcciones MAC.
- Si tu aplicación puede funcionar mediante un bridge (en un solo host de Docker) o una red overlay (para comunicarse a través de múltiples hosts de Docker), estas soluciones podrían ser mejores a largo plazo.
- Los contenedores conectados a una red macvlan no pueden comunicarse directamente con el host, esto es una restricción del kernel de Linux. Si necesitas comunicación entre el host y los contenedores, puedes conectar los contenedores a una red bridge además de a la red macvlan. También es posible crear una interfaz macvlan en el host con la misma interfaz padre y asignarle una dirección IP en la subred de la red de Docker.

## Opciones

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

| Opción | Predeterminado | Descripción |
| :--- | :--- | :--- |
| `macvlan_mode` | `bridge` | Establece el modo Macvlan. Puede ser uno de los siguientes: `bridge`, `vepa`, `passthru`, `private` |
| `parent` | | Especifica la interfaz padre (parent) que se utilizará. |

## Crear una red Macvlan

Al crear una red Macvlan, esta puede estar en modo bridge o en modo bridge troncal 802.1Q.

- En el modo bridge, el tráfico de Macvlan pasa a través de un dispositivo físico en el host.
- En el modo bridge troncal 802.1Q, el tráfico pasa a través de una subinterfaz 802.1Q que Docker crea sobre la marcha. Esto te permite controlar el enrutamiento y el filtrado a un nivel más granular.

### Modo bridge

Para crear una red `macvlan` que se conecte mediante un puente con una interfaz de red física determinada, utiliza `--driver macvlan` con el comando `docker network create`. También debes especificar la interfaz padre (`parent`), que es la interfaz por la que pasará físicamente el tráfico en el host de Docker.

```console
$ docker network create -d macvlan \
  --subnet=172.16.86.0/24 \
  --gateway=172.16.86.1 \
  -o parent=eth0 pub_net
```

Si necesitas excluir direcciones IP para que no se utilicen en la red `macvlan`, como cuando una dirección IP determinada ya está en uso, utiliza `--aux-addresses`:

```console
$ docker network create -d macvlan \
  --subnet=192.168.32.0/24 \
  --ip-range=192.168.32.128/25 \
  --gateway=192.168.32.254 \
  --aux-address="mi-router=192.168.32.129" \
  -o parent=eth0 macnet32
```

### Modo bridge troncal 802.1Q

Si especificas un nombre de interfaz `parent` que incluya un punto, como `eth0.50`, Docker lo interpretará como una subinterfaz de `eth0` y creará la subinterfaz automáticamente.

```console
$ docker network create -d macvlan \
    --subnet=192.168.50.0/24 \
    --gateway=192.168.50.1 \
    -o parent=eth0.50 macvlan50
```

### Utilizar IPvlan en lugar de Macvlan

Una red `ipvlan` creada con la opción `-o ipvlan_mode=l2` es similar a una red macvlan. La diferencia principal es que el controlador `ipvlan` no asigna una dirección MAC a cada contenedor; la pila de red de capa 2 es compartida por los dispositivos en la red ipvlan. Por lo tanto, los contenedores utilizan la dirección MAC de la interfaz padre.

La red verá menos direcciones MAC y la dirección MAC del host se asociará con la dirección IP de cada contenedor.

La elección del tipo de red depende de tu entorno y tus requisitos. Existen algunas notas sobre las ventajas y desventajas en la [documentación del kernel de Linux](https://docs.kernel.org/networking/ipvlan.html#what-to-choose-macvlan-vs-ipvlan).

```console
$ docker network create -d ipvlan \
    --subnet=192.168.210.0/24 \
    --gateway=192.168.210.254 \
     -o ipvlan_mode=l2 -o parent=eth0 ipvlan210
```

## Utilizar IPv6

Si has [configurado el daemon de Docker para permitir IPv6](/engine/daemon/ipv6/), puedes utilizar redes `macvlan` de doble pila IPv4/IPv6.

```console
$ docker network create -d macvlan \
    --subnet=192.168.216.0/24 --subnet=192.168.218.0/24 \
    --gateway=192.168.216.1 --gateway=192.168.218.1 \
    --subnet=2001:db8:abc8::/64 --gateway=2001:db8:abc8::10 \
     -o parent=eth0.218 \
     -o macvlan_mode=bridge macvlan216
```

## Ejemplos de uso

Esta sección proporciona ejemplos prácticos para trabajar con redes macvlan, incluyendo el modo bridge y el modo bridge troncal 802.1Q.

> [!NOTE]
> Estos ejemplos asumen que tu interfaz Ethernet es `eth0`. Si tu dispositivo tiene un nombre diferente, utiliza ese en su lugar.

### Ejemplo de modo bridge

En el modo bridge, tu tráfico fluye a través de `eth0` y Docker enruta el tráfico a tu contenedor utilizando su dirección MAC. Para los dispositivos en tu red, tu contenedor parecerá estar físicamente conectado a la red.

1. Crea una red macvlan llamada `mi-macvlan-net`. Modifica los valores de `subnet`, `gateway` y `parent` para que coincidan con tu entorno:

   ```console
   $ docker network create -d macvlan \
     --subnet=172.16.86.0/24 \
     --gateway=172.16.86.1 \
     -o parent=eth0 \
     mi-macvlan-net
   ```

   Verifica que la red se haya creado:

   ```console
   $ docker network ls
   $ docker network inspect mi-macvlan-net
   ```

2. Inicia un contenedor `alpine` y conéctalo a la red `mi-macvlan-net`. Los flags `-dit` inician el contenedor en segundo plano. El flag `--rm` elimina el contenedor cuando este se detiene:

   ```console
   $ docker run --rm -dit \
     --network my-macvlan-net \
     --name my-macvlan-alpine \
     alpine:latest \
     ash
   ```

3. Inspecciona el contenedor y observa la clave `MacAddress` dentro de la sección `Networks`:

   ```console
   $ docker container inspect my-macvlan-alpine
   ```

   Busca una salida similar a:

   ```json
   "Networks": {
     "my-macvlan-net": {
       "Gateway": "172.16.86.1",
       "IPAddress": "172.16.86.2",
       "IPPrefixLen": 24,
       "MacAddress": "02:42:ac:10:56:02",
       ...
     }
   }
   ```

4. Comprueba cómo ve el contenedor sus propias interfaces de red:

   ```console
   $ docker exec my-macvlan-alpine ip addr show eth0

   9: eth0@tunl0: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
   link/ether 02:42:ac:10:56:02 brd ff:ff:ff:ff:ff:ff
   inet 172.16.86.2/24 brd 172.16.86.255 scope global eth0
      valid_lft forever preferred_lft forever
   ```

   Comprueba la tabla de enrutamiento:

   ```console
   $ docker exec my-macvlan-alpine ip route

   default via 172.16.86.1 dev eth0
   172.16.86.0/24 dev eth0 scope link  src 172.16.86.2
   ```

5. Detén el contenedor (Docker lo eliminará automáticamente) y elimina la red:

   ```console
   $ docker container stop my-macvlan-alpine
   $ docker network rm mi-macvlan-net
   ```

### Ejemplo de modo bridge troncal 802.1Q

En el modo bridge troncal 802.1Q, tu tráfico fluye a través de una subinterfaz de `eth0` (llamada `eth0.10`) y Docker enruta el tráfico a tu contenedor utilizando su dirección MAC. Para los dispositivos de red de tu red, el contenedor parecerá estar físicamente conectado a la red.

1. Crea una red macvlan llamada `mi-8021q-macvlan-net`. Modifica los valores de `subnet`, `gateway` y `parent` para que coincidan con tu entorno:

   ```console
   $ docker network create -d macvlan \
     --subnet=172.16.86.0/24 \
     --gateway=172.16.86.1 \
     -o parent=eth0.10 \
     mi-8021q-macvlan-net
   ```

   Verifica que la red se haya creado y tenga como padre `eth0.10`. Puedes usar `ip addr show` en el host de Docker para verificar que la interfaz `eth0.10` existe:

   ```console
   $ docker network ls
   $ docker network inspect mi-8021q-macvlan-net
   ```

2. Inicia un contenedor `alpine` y conéctalo a la red `mi-8021q-macvlan-net`:

   ```console
   $ docker run --rm -itd \
     --network mi-8021q-macvlan-net \
     --name my-second-macvlan-alpine \
     alpine:latest \
     ash
   ```

3. Inspecciona el contenedor y observa la clave `MacAddress`:

   ```console
   $ docker container inspect my-second-macvlan-alpine
   ```

   Busca la sección `Networks` con la dirección MAC.

4. Comprueba cómo ve el contenedor sus propias interfaces de red:

   ```console
   $ docker exec my-second-macvlan-alpine ip addr show eth0

   11: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
   link/ether 02:42:ac:10:56:02 brd ff:ff:ff:ff:ff:ff
   inet 172.16.86.2/24 brd 172.16.86.255 scope global eth0
      valid_lft forever preferred_lft forever
   ```

   Comprueba la tabla de enrutamiento:

   ```console
   $ docker exec my-second-macvlan-alpine ip route

   default via 172.16.86.1 dev eth0
   172.16.86.0/24 dev eth0 scope link  src 172.16.86.2
   ```

5. Detén el contenedor y elimina la red:

   ```console
   $ docker container stop my-second-macvlan-alpine
   $ docker network rm mi-8021q-macvlan-net
   ```

