Entender cómo las diferentes tecnologías de virtualización se integran en la creación de contenedores.
Crear infraestructuras virtuales completas.
Comprender los pasos necesarios para la configuración automática de las mismas.
Llamar a los contenedores sistemas de virtualización ligera no deja de ser inexacto. Solo desde el punto de vista de un usuario del mismo contenedor aparecería que estás dentro de una máquina virtual.
El aislamiento de grupos de procesos formando una jaula o
contenedor ha sido una característica de ciertos sistemas operativos
descendientes de Unix desde los años 80, en forma del
programa chroot (creado por
Bill Joy, el que más adelante sería uno de los padres de Java). La
restricción de uso de recursos de las jaulas chroot
, que ya hemos
visto, se limitaba a la protección del acceso a ciertos recursos del
sistema de archivos, aunque eran relativamente fáciles de superar;
incluso así, fue durante mucho tiempo la forma principal de configurar
servidores de alojamiento compartidos y sigue siendo una forma simple
de crear virtualizaciones
ligeras. Las
jaulas BSD constituían
un sistema más avanzado, implementando
una
virtualización a nivel de sistema operativo
que
creaba un entorno virtual prácticamente indistinguible de una máquina
real (o máquina virtual real). Estas jaulas no solo impiden el
acceso a ciertas partes del sistema de ficheros, sino que también
restringían lo que los procesos podían hacer en relación con el resto
del sistema. Tiene como limitación, sin embargo, la obligación de
ejecutar la misma versión del núcleo del sistema.
En esta presentación explica como los espacios de nombres son la clave para la creación de contenedores y cuáles son sus ventajas frente a otros métodos de virtualización
El mundo Linux no tendría capacidades similares hasta bien entrados los años 90, con vServers, OpenVZ y finalmente LXC. Este último, LXC, se basa en el concepto de grupos de control o CGROUPS, una capacidad del núcleo de Linux desde la versión 2.6.24 que crea contenedores de procesos unificando diferentes capacidades del sistema operativo que incluyen acceso a recursos, prioridades y control de los procesos. Los procesos dentro de un contenedor están aislados de forma que solo pueden ver los procesos dentro del mismo, creando un entorno mucho más seguro que las anteriores jaulas. Estos CGROUPS han sido ya vistos en otro tema.
Dentro de la familia de sistemas operativos Solaris (cuya última versión libre se denomina Illumos, y tiene también otras versiones como SmartOS, centradas precisamente en el uso de contenedores) la tecnología correspondiente se denomina zonas. La principal diferencia es el bajo overhead que le añaden al sistema operativo y el hecho de que se les puedan asignar recursos específicos; estas diferencias son muy leves al tratarse simplemente de otra implementación de virtualización a nivel de sistema operativo.
Un contenedor es, igual que una jaula, una forma ligera de
virtualización, en el sentido que no requiere un hipervisor para
funcionar ni, en principio, ninguno de los mecanismos hardware
necesarios para llevar a cabo virtualización. Tiene la limitación de
que la máquina invitada debe tener el mismo kernel y misma CPU que
la máquina anfitriona, pero si esto no es un problema, puede resultar
una alternativa útil y ligera a la misma. A diferencia de las jaulas,
combina restricciones en el acceso al sistema de ficheros con otras
restricciones aprovechando espacios de nombres y grupos de
control. lxc
una de las soluciones de creación de contenedores más
fácil de usar hoy en día en Linux, sobre todo si se quiere usar desde
un programa a nivel de librería. Evidentemente, desde que ha salido
Docker no es la más popular, aunque es una solución madura y estable.
Esta virtualización ligera tiene, entre otras ventajas, una huella escasa: un ordenador normal puede admitir 10 veces más contenedores (o tápers) que máquinas virtuales; su tiempo de arranque es de unos segundos y, además, tienes mayor control desde fuera (desde el anfitrión) del que se pueda tener usando máquinas virtuales.
lxc
No todas las versiones de los núcleos del sistema operativo pueden
usar este tipo de container; para empezar, dependerá de cómo esté
compilado, pero también del soporte que tenga el
hardware. lxc-checkconfig
permite comprobar si está preparado para
usar este tipo de tecnología y también si se ha configurado
correctamente. Parte de la configuración se refiere a la instalación
de cgroups
, que hemos visto antes; el resto a los espacios de
nombres y a capacidades misceláneas relacionadas con la red y el
sistema de ficheros.
Hay que tener en cuenta que si no aparece alguno de esas capacidades como activada, LXC no va a funcionar.
La instalación en Linux se hace usando el paquete en los
repositorios. Por las diferencias entre la versión uno y la 2, en
algunos aparecerán paquetes lxc1
y lxc2
. Es mejor instalar este
último, con el nombre que sea. Al menos en Ubuntu y distribuciones
derivadas de esta, como Mint, no debería de tener un gran problema.
Para instalar LXC en una distribución ArchLinux lo que haremos será ejecutar el comando siguiente:
pacaur -S lxc arch-install-scripts
Así instalaremos LXC junto con otro módulo que se recomienda en la
documentación de Arch para este paquete.
Además
hemos de señalar que, por cuestiones de seguridad que también se
comentan en esta documentación, los namespaces de usuario estarán
deshabilitados (como veremos al usar lxc-checkconfig
) ya que no se
puede arrancar servidores sin permisos de superusuario.
Cuando queramos crear nuestro primer contenedor LXC usando las
instrucciones que se detallan en este tema es posible que nos dé un
error diciéndonos que no está disponible el comando debootstrap
,
solamente tendremos que instalarlo con la orden sudo pacman -S
debootstrap
, y ya podremos crear contenedores LXC sin problemas.
Tras instalar LXC en Arch junto con el paquete arch-install-scripts (que sugiere en la documentación de Arch que se instale) con los comandos:
pacaur -S lxc
pacaur -S arch-install-scripts
Lo primero que observamos es que, como dice en la documentación
anteriormente enlazada, los namespaces de usuario no aparecen como
disponibles cuando comprobamos con lxc-checkconfig
, esto es
aparentemente por un motivo de seguridad de Arch lo que nos obliga a
ejecutar los comandos con sudo al parecer.
Una vez hecho esto al intentar crear una máquina con Ubuntu con el
comando sudo lxc-create -t ubuntu -n una-caja
nos daba un error
indicando que no podía ejecutar el comando debootstrap, con lo que lo
hemos instalado por medio del comando sudo pacman -S debootstrap
.
Una vez hecho esto, y tras un tiempo de espera, se ha configurado un
contenedor con Ubuntu que arrancamos son sudo lxc-start -n una-caja
y a la que nos ponemos conectar con sudo lxc-console -n una caja
. Al
hacer esto antes de pulsar ENTER que nos iniciará la consola de dicho
contenedor, hemos de fijarnos que cuando queramos salir de dicha
consola hemos de emplear Ctrl+a q
, si empleamos el comando exit
lo
único que haremos será “salir” de la máquina y aparecerá de nuevo la
petición de usuario y contraseña para volver a entrar en ella.
Para instalar LXC en Debian es necesario contar con una versión 8 (Jessie) o superior. Instalar LXC 2.0 en Debian 8 requiere añadir los Jessie backports un repositorio de paquetes inestables y/o de test, por ello contiene versiones de los paquetes bastante más nuevas que los repositorios oficiales.
Una vez hecho esto podemos instalar LXC usando las instrucciones oficiales de instalación en Debian con los comandos:
sudo apt-get install -t jessie-backports lxc libvirt0 linux-image-amd64
sudo apt-get install libpam-cgroup libpam-cgfs bridge-utils
Podemos comprobar que se ha instalado correctamente ejecutando
lxc-checkconfig
Lo que nos debería de dar todo enabled; también podemos comprobar la versión de LXC instalada con
lxc-info --version
Instala LXC en tu versión de Linux favorita. Normalmente la versión en desarrollo, disponible tanto en GitHub como en el sitio web está bastante más avanzada; para evitar problemas sobre todo con las herramientas que vamos a ver más adelante, conviene que te instales la última versión y si es posible una igual o mayor a la 2.0.
lxc
Si no hay ningún problema y todas están enabled se puede usar lxc con relativa facilidad siempre que tengamos una distro como Ubuntu relativamente moderna:
sudo lxc-create -t ubuntu -n una-caja
crea un contenedor denominado una-caja
e instala Ubuntu en él. La
versión que instala dependerá de la que venga con la instalación de
lxc
, generalmente una de larga duración y en mi caso la 14.04.4; además,
aparte de la instalación mínima, incluirá en el contenedor una serie
de utilidades como vim
o ssh
. Todo esto lo indicará en la consola
según se vaya instalando, lo que tardará un rato.
Alternativamente, se puede usar una imagen similar a la que se usa en EC2 de Amazon, donde se denomina AMI:
sudo lxc-create -t ubuntu-cloud -n nubecilla
que funciona de forma ligeramente diferente, porque se descarga un
fichero .tar.gz
usando wget
(y tarda también un rato). Las
imágenes disponibles las podemos consultar en
esta web, junto con los
nombres que tienen. La opción -t
es para las plantillas existentes
instaladas en el sistema, que podemos consultar en el directorio
/usr/share/lxc/templates
.
Entre ellas, varias de Alpine Linux, una distribución ligera precisamente dirigida a su uso dentro de contenedores. También hay una llamada
plamo
, escrita en algún tipo de letra oriental, posiblemente japonés. Se puede instalar, pero igual no se entiende nada.
Podemos
listar los contenedores que tenemos disponibles con lxc-ls
, aunque
en este momento cualquier contenedor debería estar en estado
STOPPED
.
Para arrancar el contenedor y conectarse a él,
sudo lxc-start -n nubecilla
, donde -n
es la opción para dar el nombre del contenedor que se va
a iniciar. Dependiendo del contenedor que se arranque, habrá una configuración
inicial; en este caso, se configuran una serie de cosas y
eventualmente sale el login, que será para todas las máquinas creadas
de esta forma ubuntu
(también clave). Lo que hace esta orden es
automatizar una serie de tareas tales como asignar los CGROUPS, crear
los namespaces que sean necesarios, y crear un puente de red tal como
hemos visto anteriormente. En general, creará un puente llamado
lxcbr0
y otro con el prefijo veth
.
Te puedes conectar al contenedor desde otro terminal usando
lxc-console
sudo lxc-console -n nubecilla
La salida te dejará “pegado” al terminal.
Instalar una distro tal como Alpine y conectarse a ella usando el nombre de usuario y clave que indicará en su creación
Una vez arrancados los contenedores, si se lista desde fuera aparecerá de esta forma:
$ sudo lxc-ls -f
NAME STATE IPV4 IPV6 AUTOSTART
-----------------------------------------------
nubecilla RUNNING 10.0.3.171 - NO
una-caja STOPPED - - NO
Y, dentro de la misma, tendremos una máquina virtual con esta pinta:
Para el usuario del contenedor aparecerá exactamente igual que cualquier otro ordenador: será una máquina virtual que, salvo error o brecha de seguridad, no tendrá acceso al anfitrión, que sí podrá tener acceso a los mismos y pararlos cuando le resulte conveniente.
sudo lxc-stop -n nubecilla
Las órdenes que incluye el paquete permiten administrar las máquinas virtuales, actualizarlas y explican cómo usar otras plantillas de las suministradas para crear contenedores con otro tipo de sistemas, sean o no debianitas. Se pueden crear sistemas basados en Fedora; también clonar contenedores existentes para que vaya todo rápidamente.
La guía del usuario indica también cómo usarlo como usuario sin privilegios, lo que mayormente te ahorra la molestia de introducir sudo y en su caso la clave cada vez. Si lo vas a usar con cierta frecuencia, sobre todo en desarrollo, puede ser una mejor opción.
Los contenedores son la implementación de una serie de tecnologías que tienen soporte en el sistema operativo: espacios de nombres, CGroups y puentes de red: y como tales pueden ser configurados para usar solo una cuota determinada de recursos, por ejemplo la CPU. Para ello se usan los ficheros de configuración de cada una de las máquinas virtuales. Sin embargo, tanto para controlar como para visualizar los tápers (que así vamos a llamar a los contenedores a partir de ahora) es más fácil usar lxc-webpanel, un centro de control por web que permite iniciar y parar las máquinas virtuales, aparte de controlar los recursos asignados a cada una de ellas y visualizarlos; la página principal te da una visión general de los contenedores instalados y desde ella se pueden arrancar o parar.
Cada solución de virtualización tiene sus ventajas e inconvenientes. La principal ventaja de este tipo de contenedores son el aislamiento de recursos y la posibilidad de manejarlos, lo que hace que se use de forma habitual en proveedores de infraestructuras virtuales. El hecho de que se virtualicen los recursos también implica que haya una diferencia en las prestaciones, que puede ser apreciable en ciertas circunstancias.
Una vez creados los tápers, son en casi todos los aspectos como una instalación normal de un sistema operativo: se puede instalar lo que uno quiera. Sin embargo, una de las ventajas de la infraestructura virtual es precisamente la (aparente) configuración del hardware mediante software: de la misma forma que se crea, inicia y para desde el anfitrión una MV, se puede configurar para que ejecute unos servicios y programas determinados.
A este tipo de aplicaciones y sistemas se les denomina SCM por software configuration management; a pesar de ese nombre, se dedican principalmente a configurar hardware, no software. Un sistema de este estilo permite, por ejemplo, crear un táper (o, para el caso, una máquina virtual, o muchas de ellas) y automáticamente provisionarla con el software necesario para comportarse como un PaaS o simplemente como una máquina de servicio al cliente.
En general, un SCM permite crear métodos para instalar una aplicación o servicio determinado, expresando sus dependencias, los servicios que provee y cómo se puede trabajar con ellos. Por ejemplo, una base de datos ofrece precisamente ese servicio; un sistema de gestión de contenidos dependerá del lenguaje en el que esté escrito; además, se pueden establecer relaciones entre ellos para que el CMS use la BD para almacenar sus tablas.
Hay decenas de sistemas CMS, aunque hoy en día los hay que tienen cierta popularidad, como Salt, Rex, Ansible, Chef, Juju y Puppet. Todos ellos tienen sus ventajas e inconvenientes, pero para la configuración de tápers se puede usar directamente Juju, creado por Canonical especialmente para máquinas virtuales de ubuntu que se ejecuten en la nube de Amazon. En este punto nos interesa también porque se puede usar directamente con contenedores LXC, mientras que no todos lo hacen.
En el caso de lxc
, una forma fácil de gestionar configuraciones es
hacerlo con Vagrant usando
el driver para lxc. Usando
alguna de las
cajas base de Atlas,
pero requiere cierta cantidad de trabajo para construir las plantillas
con Vagrant; eventualmente las cajas se tienen que introducir en el
directorio de plantillas de lxc
para que se puedan usar, o bien usar
las de Atlas tales como esta
vagrant init fgrehm/wheezy64-lxc
e iniciarlas con
sudo vagrant up --provider=lxc
Con esto se puede provisionar o conectarse usando las herramientas habituales,
siempre que la imagen tenga soporte para ello. Por ejemplo, se puede
conectar uno a esta imagen de Debian con vagrant ssh
Provisionar un contenedor LXC usando Ansible o alguna otra herramienta de configuración que ya se haya usado
Lo más conveniente es ir al capítulo sobre Docker.
Si te interesa, puedes consultar cómo se virtualiza el almacenamiento que, en general, es independiente de la generación de una máquina virtual. También puedes ir directamente al tema de uso de sistemas en el que se trabajará con sistemas de virtualización completa.