domingo, 26 de noviembre de 2017

Como poner un contenedor LXD en tu misma red local

En esta entrada me gustaría habar de LXD y un problema que considero que es común pero al que no he encontrado una respuesta satisfactoria por ningún lado.
Se trata de como poner un contenedor en la misma red local en la que se encuentra el anfitrión (la máquina sobre la que está montado el LXD).

Antes de nada decir que no explicaré como instalar o configurar LXD, ya que considero que hay literatura de sobras al respecto (y muy buena).
No obstante decir que LXD es una forma "suave" de crear "maquinas virtuales" en linux (dicho pronto y mal).

Al lio.

Método 1: MacVlan

NOTA: Para todos los ejemplos asumiré que existe un contenedor llamado "miContenedor" y que cuenta con una interface llamada "ethContenedor". También asumiré que la máquina anfitriona ("Anfitrión") tiene una interface llamada "ethHost".
NOTA2: También asumiré que el anfitrión es un Debian (o basado en Debian como por ejemplo Ubuntu) sin ningún gestor de redes como "network-manager" que inhabilite el fichero "/etc/network/interfaces".

Cuando queremos poner un contenedor en nuestra misma red local, se nos aconseja añadir una interface de tipo "macvlan". Este sería el comando para hacer dicha tarea:
 lxc network attach ethHost miContenedor ethContenedor

Con eso ya tendríamos el contenedor en la misma red local que el anfitrión utilizando el DHCP que tenga la propia red. Así de simple. El resultado podéis verlo en la imagen siguiente.



Ahora, esto tiene un gran "Pero...".
Si deseas comunicar el anfitrión con el contenedor por esa interface, simplemente no puedes. En el momento en el que creas una macvlan, anfitrión y contenedor quedan incomunicados por esa interface. El resto de dispositivos de la red podrán ver a ambos.
Por tanto según el esquema de antes, "otroEquipo" podría ver a todos los equipos de la red, pero "miContenedor" no podría ver a "Anfitrión" y viceversa.
Si esta limitación no te importa, este es el mejor procedimiento para meter tu contenedor en tu misma red local, así que no necesitas seguir con el post.

Una forma de soslayar el problema es tener 2 interfaces entre anfitrión y contenedor, de tal forma que comuniques por una con la red local y por la otra con el anfitrión. Otra forma, es usando un puente.

Método 2: Puente

Otra forma de conseguir meter al contenedor en la misma red local sin limitaciones, es hacerlo a través de un puente virtual. De tal manera que tendríamos un escenario como el de la siguiente imagen.

Como se aprecia, ambas máquinas, anfitrión y contenedor están conectados al mismo puente virtual, de tal forma que no hay problemas de conectividad.

Para llegar a esto, haremos 2 cosas. La primera quitar la configuración de red a la interface por la que se comunica la maquina anfitriona y pasarla al puente. Supongamos que la maquina tiene la siguiente configuración:
ip -4 addr show
 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
   inet 127.0.0.1/8 scope host lo
     valid_lft forever preferred_lft forever
 3: ethAnfitrion: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
   inet 192.168.1.3/24 brd 192.168.1.255 scope global ethAnfitrion
     valid_lft forever preferred_lft forever
 4: lxdbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
   inet 10.137.142.1/24 scope global lxdbr0
     valid_lft forever preferred_lft forever

Bien, pues tendríamos que configurar nuestro fichero de "/etc/network/interfaces" algo así:
Nota: omitiré la de "lo" y "lxdbr0" (si está) ya que no hay que tocarlas:
auto ethAnfitrion
allow-hotplug ethAnfitrion
iface ethAnfitrion inet manual

auto mibr0
iface mibr0 inet static
    address 192.168.1.3/24
    gateway 192.168.1.1
    bridge_ports ethAnfitrion
    dns-nameservers 8.8.8.8 8.8.4.4

Ahora para hacer los cambios efectivos sin reiniciar, hay dos formas:
Reiniciando los servicios de red:
sudo service networking restart

O la que me parece más correcta. Crear el puente a mano.
Primero eliminamos la ip de la interface anterior:
sudo ip address flush dev ethAnfitrion

Ahora creamos el puente y agregamos la interface:
sudo ip link add name mibr0 type bridge
sudo ip link set mibr0 up
sudo ip link set dev ethAnfitrion master mibr0

Finalmente restablecemos la ip:
sudo ip address add 192.168.1.3/24 dev mibr0

Si por algún motivo no salimos a internet, tal vez sea necesario restablecer la puerta de enlace:
sudo ip route delete default
sudo ip route add default via 192.168.1.1


Si todo ha ido bien, ahora nuestra configuración tendría que quedar algo así:
ip -4 addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
  inet 127.0.0.1/8 scope host lo
    valid_lft forever preferred_lft forever
4: lxdbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
  inet 10.137.142.1/24 scope global lxdbr0
    valid_lft forever preferred_lft forever
5: mibr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
  inet 192.168.1.3/24 brd 192.168.1.255 scope global br0
    valid_lft forever preferred_lft forever

Si os fijáis, "ethAnfitrion" no aparece en la lista. Esto es normal, ya que ahora no tiene dirección IPv4. Si se quiere ver todas las interfaces independientemente de si tienen o no dirección, hay que ejecutar:
ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    valid_lft forever preferred_lft forever
3: ethAnfitrion: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master mibr0 state UP mode DEFAULT group default qlen 1000
    link/ether 00:12:34:56:78:9A brd ff:ff:ff:ff:ff:ff
4: lxdbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 12:51:0d:22:19:6c brd ff:ff:ff:ff:ff:ff
5: mibr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether A0:98:76:54:32:10 brd ff:ff:ff:ff:ff:ff

Meter el contenedor en la red

Con la red ya configurada, solo queda el paso final. Para ello solo hay que ejecutar:
lxc network attach mibr0 miContenedor ethContenedor

Y eso es todo. Espero que si has llegado hasta aquí esto te sea de utilidad.
Si tienes dudas o encuentras errores, te invito a comentar.

Un saludo!