Usar Linux Containers (LXC) en Debian – Parte 2

En el post anterior creamos un contenedor LXC con privilegios y configuramos una conexión de red básica entre nuestra PC y el contenedor. Sin embargo, el contenedor aún no cuenta con acceso a internet por lo que no podemos instalarle nuevos paquetes. Aquí es donde nos enfrentamos a un nuevo problema ya que, al menos en Debian, compartir internet con el contenedor puede ser de lo más fácil o puede ser tu peor pesadilla.

El problema radica en la forma en que la PC está conectada a internet. Si es por cable ethernet, compartir el internet con el contenedor es tan simple como crear una conexión de puente entre el adaptador de red de la PC y el adaptador de red virtual creado al iniciar el contenedor.

Por otro lado, si tu PC está conectada a internet usando un adaptador Wi-Fi, las cosas se pueden poner feas. El problema es que en Linux no se puede crear una conexión de puente con un adaptador Wi-Fi. Algunas fuentes sugieren sí que es posible crear una conexión de puente si el adaptador Wi-Fi lo soporta (y hay quienes sugieren que la mayoría de los adaptadores Wi-Fi modernos lo soportan), así que esa debería ser la primera opción a probar; si eso funciona, estás de suerte.

Otras alternativas sugieren usar el modo 4addr del adaptador inalámbrico pero aún si esto funciona, no está garantizado que el router de internet (o punto de acceso) soporte esta opción :(.

Aquí se terminan las opciones sencillas. Si todo lo anterior falla, aún es posible compartir internet con el contenedor usando iptables para realizar una configuración avanzada de la red. Sólo para tener una idea de lo que hace iptables, podemos ver el siguiente gráfico:

iptables

Es fácil imaginarse que usar iptables no es una tarea trivial, así que compartir internet con el contenedor LXC requiere tener conocimientos del uso de iptables o bien copiar alguno de los ejemplos en línea y cruzar los dedos para que funcione :(.

Entonces, si todo lo anterior ha fallado, ¿no hay forma de contar con internet en el contenedor LXC sin tener que ser un mago lvl99 😦 ?. Bueno, hay una última alternativa y es la que analizaremos en este post.

LXC incluye el comando lxc-device que permite transferir un dispositivo de nuestra PC a un contenedor en ejecución. Al usar lxc-device, el dispositivo aparecerá como si estuviera conectado de forma nativa al contenedor, aunque al mismo tiempo será removido del sistema anfitrión en nuestra PC. Esta tal vez no sea la solución más elegante pero nos permite configurar un dispositivo como si estuviera conectado directamente al contenedor. En este caso hablamos de transferir nuestro dispositivo de red inalámbrico al contenedor para poder usarlo por lo menos para descargar e instalar los paquetes que necesitamos en el contenedor.


Nota: Este post contiene una gran cantidad de salida de texto de la consola de Linux con fines demostrativos. La cantidad de comandos utilizados es relativamente pequeña pero requiere que el usuario sepa lo que está haciendo ya que no repetiré comandos básicos como lxc-start o lxc-stop. La salida de la consola ha sido truncada para hacerla menos extensa pero conservando la información necesaria para que quede claro cada ejemplo. Por último, el usuario debe saber lo que cada comando hace y cambiar los nombres usados aquí, así como direcciones IP, etc. para adaptarlos de forma correspondiente.


Antes de continuar, hay que tener en cuenta que si ejecutamos el comando lxc-attach para conectarnos al contenedor podemos ver que no cuenta con los comandos para configurar una conexión de red inalámbrica :(. Ya que aún no contamos con acceso a internet en el contenedor, debemos instalar el paquete iw y sus dependencias de forma manual. Por suerte, esto no es tan difícil. Para instalar manualmente los paquetes necesarios, podemos ejecutar el comando apt-get dentro del contenedor para ver una lista de los paquetes requeridos:

monstruosoft@PC:~$ sudo lxc-start -n privileged
monstruosoft@PC:~$ sudo lxc-attach -n privileged
root@privileged:/# apt-get install iw
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  crda libnl-3-200 libnl-genl-3-200 wireless-regdb
The following NEW packages will be installed:
  crda iw libnl-3-200 libnl-genl-3-200 wireless-regdb
0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 213 kB of archives.
After this operation, 727 kB of additional disk space will be used.
Do you want to continue? [Y/n] n
Abort.
root@privileged:/# exit
exit
monstruosoft@PC:~$ sudo lxc-stop -n privileged

El comando apt-get nos informa que se necesitan instalar los paquetes crda, iw, libnl-3-200, libnl-genl-3-200 y wireless-regdb. Para instalar manualmente estos paquetes es necesario descargarlos desde la página del repositorio de paquetes correspondiente; en este caso, para Debian Sid, podemos descargar el paquete iw desde https://packages.debian.org/sid/net/iw y desde esa misma página podemos seguir los links a cada uno de los paquetes requeridos y descargar el archivo para la arquitectura correspondiente, en este caso amd64. El tamaño total de los archivos requeridos es de apenas unos cuantos KBs y una vez descargados debemos ponerlos en la ruta del caché de instalación del contenedor para que desde ahí el comando apt-get los pueda instalar:

monstruosoft@PC:~$ ls *.deb
crda_3.13-1+b1_amd64.deb        libnl-genl-3-200_3.2.27-1_amd64.deb
iw_4.9-0.1_amd64.deb            wireless-regdb_2015.07.20-1_all.deb
libnl-3-200_3.2.27-1_amd64.deb
monstruosoft@PC:~$ sudo mv *.deb /var/lib/lxc/privileged/rootfs/var/cache/apt/archives/

Una vez que los archivos están en la ruta del caché de apt-get del contenedor, podemos iniciar nuevamente el contenedor e instalar los paquetes:

monstruosoft@PC:~$ sudo lxc-start -n privileged
monstruosoft@PC:~$ sudo lxc-attach -n privileged
root@privileged:/# apt-get install iw
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  crda libnl-3-200 libnl-genl-3-200 wireless-regdb
0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/213 kB of archives.
After this operation, 727 kB of additional disk space will be used.
Setting up wireless-regdb (2015.07.20-1) ...
Setting up libnl-3-200:amd64 (3.2.27-1) ...
Setting up libnl-genl-3-200:amd64 (3.2.27-1) ...
Setting up iw (3.17-1) ...
Setting up crda (3.13-1+b1) ...
root@privileged:/# exit
exit

Ahora los paquetes necesarios para usar una conexión inalámbrica están instalados en el contenedor pero aún no hemos “conectado” el dispositivo de red. Para hacerlo, usaremos el comando lxc-device para “desconectar” el adaptador de red inalámbrico del sistema anfitrión y “conectarlo” al contenedor. Hay que tener en cuenta que si sólo tenemos un adaptador de red inalámbrico, conectarlo al contenedor dejará al sistema anfitrión sin conexión de red hasta que el contenedor sea detenido pero al menos de esta forma podemos usar la red inalámbrica para instalar paquetes en el contenedor en lugar de hacerlo manualmente. Si tenemos dos adaptadores de red inalámbricos, podemos conectar uno de ellos al contenedor sin que el anfitrión se quede sin red.

Ahora podemos “conectar” el adaptador de red inalámbrico a un contenedor en ejecución y configurarlo dentro del contenedor para tener acceso a internet:

monstruosoft@PC:~$ sudo lxc-device -n privileged add wlan0
monstruosoft@PC:~$ sudo ifconfig 
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
monstruosoft@PC:~$ sudo lxc-attach -n privileged
root@privileged:/# ifconfig -a
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
wlan0: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        TX packets 4928290  bytes 864850730 (824.7 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
root@privileged:/# ifconfig wlan0 up
root@privileged:/# iw wlan0 scan
BSS d5:63:fe:61:f9:d6(on wlan0)
	SSID: MONSTRUORED
	Supported rates: 1.0* 2.0* 5.5* 11.0* 18.0 24.0* 36.0 54.0 
root@privileged:/# iw wlan0 connect -w MONSTRUORED key 0:0123ABCDEF
wlan0 (phy #0): connected
root@privileged:/# dhclient -v wlan0
Internet Systems Consortium DHCP Client 4.3.5b1
bound to 192.168.1.69 -- renewal in 47 seconds.

Ahora el contenedor está conectado a internet. A continuación instalaremos algunos paquetes de prueba y configuraremos la contraseña de root del contenedor. Sugiero instalar como mínimo ssh después de actualizar la lista de paquetes ya que tener ssh instalado nos permitirá interactuar con el contenedor como veremos más adelante:

root@privileged:/# apt-get update
Get:1 http://dist1.800hosting.com/debian sid InRelease [219 kB]
Get:4 http://dist1.800hosting.com/debian sid/main amd64 Packages [7339 kB]     
Reading package lists... Done                                                  
root@privileged:/# apt-get install ssh
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  dbus libdbus-1-3 libexpat1 libpam-systemd libsystemd0 libx11-6 libx11-data
  libxau6 libxcb1 libxdmcp6 libxext6 libxmuu1 ncurses-term openssh-client
  openssh-server openssh-sftp-server systemd xauth
4 upgraded, 15 newly installed, 0 to remove and 41 not upgraded.
Need to get 4198 kB/6304 kB of archives.
After this operation, 11.1 MB of additional disk space will be used.
Setting up libxdmcp6:amd64 (1:1.1.2-1.1) ...
Setting up openssh-client (1:7.3p1-3+b1) ...
Setting up libx11-data (2:1.6.3-1) ...
Setting up libxmuu1:amd64 (2:1.1.2-2) ...
Setting up openssh-server (1:7.3p1-3+b1) ...
root@privileged:/# apt-get install iputils-ping
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  libcap2-bin libnettle6 libpam-cap
0 upgraded, 4 newly installed, 0 to remove and 41 not upgraded.
Need to get 289 kB of archives.
After this operation, 607 kB of additional disk space will be used.
Setting up libnettle6:amd64 (3.3-1) ...
Setting up libpam-cap:amd64 (1:2.25-1) ...
Setting up libcap2-bin (1:2.25-1) ...
Setting up iputils-ping (3:20161105-1) …
root@privileged:/# apt-get install x11-apps    
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
  bsdmainutils fontconfig-config fonts-dejavu-core groff-base libfontconfig1
  libfreetype6 libice6 libpipeline1 libpng16-16 libsm6 libxaw7 libxcursor1
  libxfixes3 libxft2 libxkbfile1 libxmu6 libxpm4 libxrender1 libxt6 man-db ucf
  x11-common xbitmaps
0 upgraded, 24 newly installed, 0 to remove and 41 not upgraded.
Need to get 6556 kB of archives.
After this operation, 16.4 MB of additional disk space will be used.
Setting up libxkbfile1:amd64 (1:1.0.9-2) ...
Setting up libxfixes3:amd64 (1:5.0.2-1) ...
Setting up libpng16-16:amd64 (1.6.26-1) ...
Setting up man-db (2.7.5-1) ...
Building database of manual pages ...
Setting up x11-apps (7.7+6) ...
Processing triggers for libc-bin (2.24-5) ...
Processing triggers for systemd (232-3) ...
root@privileged:/# passwd
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully

Ahora que podemos instalar paquetes, tenemos un contenedor más o menos funcional. En teoría, deberíamos ser capaces de instalar y ejecutar cualquier paquete y programa que se ejecute desde la consola, por ejemplo, GCC 5 ó GCC 6 que no están disponibles en la distro estable de Debian pero sí en la distro del contenedor. ¿Qué hay de los programas con una interfaz de usuario gráfica (GUI)?. Bueno, hay al menos 2 formas de ejecutar programas que requieran interfaz gráfica; la primera consiste en configurar el contenedor para que tenga acceso al hardware de audio y video del sistema anfitrión, mientras que la segunda consiste en usar ssh con X forwarding.


Nota: Si recibes un error de Permission denied (publickey,password) al intentar conectarte por ssh al contenedor, una forma rápida y sencilla de solucionarlo es asignando el valor yes a los siguientes campos en el archivo /etc/ssh/sshd_config del contenedor:

PasswordAuthentication yes
PermitRootLogin yes

Cuando ssh está configurado y es posible conectarse al contenedor, podemos ejecutar una aplicación en el contenedor usando X forwarding:

monstruosoft@PC:~$ ssh root@10.0.0.3
root@10.0.0.3's password: 
root@privileged:~# xeyes 
Error: Can't open display: 
root@privileged:~# exit
logout
Connection to 10.0.0.3 closed.
monstruosoft@PC:~$ ssh -X root@10.0.0.3
root@10.0.0.3's password: 
Last login: Sat Nov 12 04:00:50 2016 from 10.0.0.2
/usr/bin/xauth:  file /root/.Xauthority does not exist
root@privileged:~# xeyes 
root@privileged:~# xgc

Usar X forwarding nos permite ejecutar aplicaciones gráficas en el contenedor y funciona para las aplicaciones sencillas incluidas en el paquete x11-apps que usamos en este ejemplo. ¿Qué hay de aplicaciones más complejas?. Bueno, sólo hay una forma de averiguarlo 😉 pero por ahora este post ya ha sido muy extenso así que ya hablaremos de otro post :P.

Como hemos visto, LXC tal vez aún no sea de lo más amigable para usuarios comunes y corrientes pero una vez que lo has configurado ofrece una interesante y poderosa alternativa para instalar paquetes que no están disponibles en tu distro o bien para ejecutar programas en un contenedor que sirva como sandbox.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s