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.