Contenedores: repaso general y OpenVZ en Debian

¿Que son los contenedores?

Como expliqué en entradas anteriores los contenedores son como entornos chroot con esteroides.

Dicho rápido y mal se trata de meter un sistema entero en un directorio y ejecutar el proceso init del mismo. A este proceso init y todos sus hijos se les aplican unas cuotas y unos permisos.

De esta forma todos los procesos corren dentro del servidor pero con ciertas restricciones de forma que desde dentro del contenedor podrías jurar que estás en una máquina virtual.

Ventajas y desventajas de los contenedores frente a la virtualización con Virtualbox, vmware, xen, kvm, ...

Ventajas:

  • Se puede hacer overbooking de recursos permitiéndonos un ahorro brutal de memoria y disco.
  • La ampliación y disminución de quotas tiene un efecto inmediato> sobre los contenedores arrancados por lo que evitamos perder tiempo de arranque/parada y evitamos buscar ventanas de parada para realizar actuaciones sobre el mismo<.>
  • El sistema de ficheros de los contenedores se accesible directamente desde el anfitrión por lo que su gestión de backup es absolutamente ninguna.
  • Al usar el mismo sistema de archivos para todas las máquinas virtuales el sistema no se sobrecarga con varios sistemas de ficheros.
  • La creación/borrado de máquinas virtuales es cuestión de segundos.
  • La velocidad de las aplicaciones que se ejecutan en los contenedores es practicamente la misma que si se ejecutaran en un servidor físico.

Limitaciones o "features":

  • El acceso a los dispositivos no es transparente para las aplicaciones. Por ejemplo, si usas openvpn que necesita usar /dev/tun no podrás a menos que se le de permiso a ese contenedor para acceder a él con un vzctl set 101 --devnodes net/tun:rw --save.

Instalación y gestión en Debian Squeeze

Lo que queremos

Para crear contenedores hay gente que prefiere hacer un debootstrap pero con eso tenemos un problema: si queremos migrar estas máquinas a Amazon o a Xen o a KVM nos costará bastante.

Queremos poder lanzar contenedores "compatibles" con gestores de virtualización de otros tipos por si nos apetece moverlos.

Instalación del servidor

Instalación de los paquetes necesarios

aptitude install vzctl vzquota linux-image-openvz-amd64 bridge-utils

Tras la instalación de los paquetes será necesario reiniciar con el nuevo núcleo.

Configurar el bridge en las interfaces de red que queramos

Esto no es necesario pero nos permitirá poner una dirección MAC a las interfaces de red que queramos dentro del contenedor así que vamos a hacerlo.

Habría que cambiar donde pone eth0 por br0 y añadir el parámetro bridge_ports eth0.
Pasaríamos de:

auto eth0
iface eth0 inet dhcp

a:

auto br0
iface br0 inet dhcp
    bridge_ports eth0

Le decimos a OpenVZ que use el bridge recién creado

El el archivo de configuración /etc/vz/vz.conf ponemos el parámetro:

VE_ROUTE_SRC_DEV="br0"

Reiniciar el sistema

Importante para que se empiece a usar el bridge y openvz sepa que tiene que salir por br0.

Preparación de las plantillas

Se hace una instalación normal en virtualbox o kvm. A continuación se arranca con un CD y se comprime todo en un archivo .tar.gz . Es importante que el nombre termine en .tar.gz para que la plantilla sea reconocida por el sistema.

Una vez comprimido lo dejamos en /var/lib/vz/template/cache

Preparación de los scripts necesarios para la configuración automática de la red

  • Indicamos el lugar donde estará el script encargado de configurar la red copiando el archivo vznet.conf a /etc/vz/vznet.conf.
  • Copiamos el script vznetcfg.custom al lugar indicado anteriormente(/usr/local/sbin/vznetcfg.custom).
  • Copiamos un script que nos ayudará a configurar la interfaz de red de las máquinas virtuales en función de la IP que le pasemos como parámetro. Deberemos cambiar el valor de gw, mask y br según nuestra red.

Creación de un contenedor

Configuramos las variables para los comandos del contenedor.

Configuramos el número del contenedor, nombre, memoria, swap y disco.

El número de plantilla se conseguirá juntando las dos últimas cifras de su dirección IP. Por ejemplo para 192.168.16.108 tendremos:

epi:~# container="16108" 
epi:~# name="ovz-web-panel" 
epi:~# nameserver="8.8.8.8" 
epi:~# memory="512M" 
epi:~# swap="256M" 
epi:~# disk="5G" 

Despliegue de una plantilla en un contenedor

epi:~# vzctl create $container --ostemplate debian-6.0-x86_64-andago
Creating container private area (debian-6.0-x86_64-andago)
Performing postcreate actions
Container private area was created
epi:~#

Configuramos su hostname

epi:~# vzctl set $container --hostname ${name}.andago.com --save
Saved parameters for CT 16108
epi:~#

Configuramos su nombre

Se usará para referirnos a él en vez de su número:

epi:~# vzctl set $container --name $name --save
Name ovz-web-panel assigned
Saved parameters for CT 16108
epi:~#

Configuramos su servidor de nombres

epi:~# vzctl set $container --nameserver ${nameserver} --save
Saved parameters for CT 16108
epi:~#

Se le aumenta la quota del disco

epi:~# vzctl set ${container} --diskspace ${disk}:${disk} --save
Saved parameters for CT 16108
epi:~#

Se aumenta la quota de memoria

La gestión de memoria es un poco especial en los contenedores. No entraré en detalles, solo ejecuta:

blas:~# for memory_type in vmguarpages oomguarpages privvmpages; do vzctl set ${container} --save --${memory_type} ${memory};done
UB limits were set successefully
Saved parameters for VE 1643
UB limits were set successefully
Saved parameters for VE 1643
UB limits were set successefully
Saved parameters for VE 1643
blas:~#

Se le asigna espacio en swap

root@rivendel:~# vzctl set $container --save --swappages 2G:2G
Saved parameters for CT 17223
root@rivendel:~#

Configuramos su dirección IP

epi:~# netconf.py 192.168.16.108 >> /etc/vz/conf/16108.conf
epi:~#

Arranque de un contenedor

Se usa start y el número o el nombre del contenedor:

epi:/etc/vz/conf# vzctl start 6112
Starting VE ...
VE is mounted
Setting CPU units: 1000
Configure meminfo: 65536
Set hostname: dhcp-01.panama.andago.net
File resolv.conf was modified
Configure veth devices: veth6112.0 
ifname=
host_ifname=
Initializing interface veth6112.0 for CT6112.
Adding interface veth6112.0 to the bridge br2.
Adding an IP 192.168.61.12/24 to the eth0 for CT6112.
Adding a route from CT0 to CT6112 using 192.168.61.12.
VE start in progress...
epi:/etc/vz/conf#

Parada de un contenedor

Se usa stop y el nombre o número del contenedor:

epi:/var/lib/vz/template/cache# vzctl stop 62112
Stopping VE ...
VE was stopped
VE is unmounted
epi:/var/lib/vz/template/cache#

Borrado de contenedor
Se usa destroy y el nombre o número del contenedor:

epi:/var/lib/vz/template/cache# vzctl destroy 62112
Destroying VE private area: /var/lib/vz/private/62112
VE private area was destroyed
epi:/var/lib/vz/template/cache#

¡¡¡¡¡Ten cuidado si usas Xen!!!!! Destroy en xen para, en OpenVZ destruye.

Migración de contenedores entre servidores

Configuración de la autenticación por clave pública en el ssh

Necesitamos que funcione la autenticación por rsa en el ssh. La podemos configurar generando las claves pública y privada con un ssh-keygen -t rsa y luego copiándolas al servidor destino con un ssh-copy-id. Por ejemplo, para copiar poder migrar una máquina de orthanc.andago.net a gondor.andago.net creamos las claves y las copiamos con un:

orthanc:~# ssh-copy-id root@gondor.andago.net
root@gondor.andago.net's password:
Now try logging into the machine, with "ssh 'root@gondor.andago.net'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

orthanc:~#

Migración con reinicio

El contenedor se copia de un servidor a otro estando encendida, se apaga, se hace una sincronización final y se arranca en el servidor destino:

gondor:~# vzmigrate orthanc.andago.net 1778
OPT:orthanc.andago.net
[[StartingPreparingInitializingSyncingStoppingSyncingStartingCleanup]]
gondor:~#

Migración en vivo

El contenedor se copia de un servidor a otro estando encendida, se pausa, se hace una sincronización final tanto de los archivos del disco como de las zonas de memoria ocupada y se arranca en el servidor destino:

orthanc:~# vzmigrate --online gondor.andago.net 1778
OPT:--online
OPT:gondor.andago.net
[[StartingPreparingInitializingSyncingLiveSyncingCleanup]]
orthanc:~#

Problemas que pueden surgir el día a día

Quotas sobrepasadas

Si algo falla lo primero que hay que hacer es revisar que no se ha sobrepasado ninguna quota ejecutando cat /proc/user_beancounters. Si en la columna de la derecha hay algo diferente de 0 es que hay procesos que están pidiendo algún recurso y no se le está dando. Por ejemplo:

apt:~# more /proc/user_beancounters 
Version: 2.5
       uid  resource                     held              maxheld              barrier                limit              failcnt
     1641:  kmemsize                  2334950              9377223             14372700             14790164                    0
            lockedpages                     0                    0                  256                  256                    0
            privvmpages                 11061                38406                65536                69632                    0
            shmpages                      641                 3857                21504                21504                    0
            dummy                           0                    0                    0                    0                    0
            numproc                        16                   38                  240                  240                    0
            physpages                    3459                27064                    0  9223372036854775807                    0
            vmguarpages                     0                    0                33792  9223372036854775807                    0
            oomguarpages                 3472                27107                26112  9223372036854775807                    0
            numtcpsock                      6                   18                  360                  360                    0
            numflock                        1                    7                  188                  206                    0
            numpty                          1                    3                   16                   16                    0
            numsiginfo                      0                    3                  256                  256                    0
            tcpsndbuf                  159272              1722464              1720320              2703360                81847
            tcprcvbuf                   98304              1586120              1720320              2703360                    0
            othersockbuf                25432                42592              1126080              2097152                    0
            dgramrcvbuf                     0                 8720               262144               262144                    0
            numothersock                   28                   34                  360                  360                    0
            dcachesize                 169020               224307              3409920              3624960                    0
            numfile                       382                  940                 9312                 9312                    0
            dummy                           0                    0                    0                    0                    0
            dummy                           0                    0                    0                    0                    0
            dummy                           0                    0                    0                    0                    0
            numiptent                      10                   10                  128                  128                    0
apt:~

En este caso aumentamos la cuota con un:

orthanc:/etc/vz/conf# vzctl set apt --tcpsndbuf 4M:5M --save

Y la cuota se ve aumentada:

apt:/# more /proc/user_beancounters | grep tcpsndbuf
            tcpsndbuf                   87200              1722464              4194304              5242880                81847
apt:/#

Por desgracia la única forma de poner a cero la columna de la derecha es reiniciando el contenedor.

df miente acerca del disco usado dentro del contenedor

A veces puede ocurrir que desde dentro del contenedor obtengamos un espacio ocupado

helm:~# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda2              10G  711M  9.4G   7% /
tmpfs                 128M     0  128M   0% /lib/init/rw
tmpfs                 128M  4.0K  128M   1% /dev/shm
helm:~#

pero desde fuera veamos que estamos ocupando bastante más:

epi:~# du -hs /var/lib/vz/private/1626
4.0G    /var/lib/vz/private/1626
epi:~#

El motivo más probable es que hayamos escrito algo en el espacio de ese contenedor desde fuera del contenedor y no se haya actualizado la quota.

Se arregla parando el contenedor, borrando las cuotas y arrancando el contenedor para que las rehaga:

epi:~# vzctl stop 1626
Stopping container ...
Container was stopped
Remove a route from CT0 to CT1626 using 192.168.16.26.
Container is unmounted
epi:~# vzquota drop 1626
epi:~# vzctl start 1626
Starting container ...
Initializing quota ...
Container is mounted
Setting CPU units: 1000
Set hostname: helm.andago.net
File resolv.conf was modified
Configure veth devices: veth1626.0 
ifname=
host_ifname=
Initializing interface veth1626.0 for CT1626.
Adding interface veth1626.0 to the bridge br0.
Adding an IP 192.168.16.26/23 to the eth0 for CT1626.
Adding a route from CT0 to CT1626 using 192.168.16.26.
Setting 192.168.17.1 as a default gateway for CT1626.
Container start in progress...
epi:~# ssh helm
Linux helm 2.6.32-5-openvz-amd64 #2894 SMP Wed Jan 12 04:22:50 UTC 2011 x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Apr  8 11:42:47 2011 from epi.andago.net
helm:~# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda2              10G  4.0G  6.1G  40% /
tmpfs                 128M     0  128M   0% /lib/init/rw
tmpfs                 128M  4.0K  128M   1% /dev/shm
helm:~# 

Aumentar el número de inodos que puede usar el contenedor

En ocasiones nos podemos encontrar con que no se puede escribir en disco pero tiene espacio:

root@builder:/# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda2             300G   18G  283G   6% /
tmpfs                 2.0G     0  2.0G   0% /lib/init/rw
tmpfs                 2.0G     0  2.0G   0% /dev/shm
root@builder:/#

En esas ocasiones probablemente haya superado la cueta de inodos que puede usar:

root@builder:/# df -i
Filesystem            Inodes   IUsed   IFree IUse% Mounted on
/dev/sda2             200000  199544     456  100% /
tmpfs                 506855       5  506850    1% /lib/init/rw
tmpfs                 506855       1  506854    1% /dev/shm
root@builder:/#

Se le pueden dar más así:

root@moria:~# vzctl set 1762 --diskinodes 2000000:2000000 --save
Saved parameters for CT 1762
root@moria:~# vzctl enter 1762
entered into CT 1762
dircolors: no SHELL environment variable, and no shell type option given
root@builder:/# df -i
Filesystem            Inodes   IUsed   IFree IUse% Mounted on
/dev/sda2            2000000  199548 1800452   10% /
tmpfs                 506855       5  506850    1% /lib/init/rw
tmpfs                 506855       1  506854    1% /dev/shm
root@builder:/#

No es necesario reiniciar el contenedor para que se apliquen los cambios.

Comentarios

Sobre Openvz, Bridge y VETH

Hola Manytas. Te felicito por el post!

En mi caso tengo un Server OpenVZ con Debian Squeeze funcionando perfecto. Además tengo un CT en modo "venet" que también funciona bien. Ahora, tengo la necesidad de agregar un nuevo CT pero que trabaje en modo VETH.

Te consulto, debo configurar lo que decías del "bridge" en el Host Anfitrión?

Desde dentro del CT (el cual ya está en modo VETH) puedo pingear a la misma IP del CT pero no puedo "salir" al Host anfitrión ni mucho menos a los distintos host de la red.

Muchas Gracias.

Saludos.