Introducción a LinuX Containers (LXC)
LinuX Containers, también conocido por el acrónimo LXC, es una tecnología de virtualización ligera o por contenedores, que es un método de virtualización en el que, sobre el núcleo del sistema operativo se ejecuta una capa de virtualización que permite que existan múltiples instancias aisladas de espacios de usuario, en lugar de solo uno. A estas instancias la llamamos contenedores.
Todo esto ha sido posible por el desarrollo de dos componentes del nucleo de Linux:
- Los Grupos de Control cgroups, en concreto en Debian 11 se utiliza cgroupsv2: que limita el uso de recursos (límite de memoria, cpu, I/O o red) para un proceso y sus hijos.
- Los Espacios de Nombres namespaces: que proporcionan un punto de vista diferente a un proceso (interfaces de red, procesos, usuarios, etc.).
LXC pertenece a los denominados contenedores de sistemas, su gestión y ciclo de vida es similar al de una máquina virtual tradicional. Está mantenido por Canonical y la página oficial es linuxcontainers.org
Instalación de LXC
Vamos a trabajar sobre una distribución GNU/Linux Debian 11. Para la instalación de LXC ejecutamos:
$ apt install lxc
Podemos crear contenedores LXC privilegiados (ejecutados como root) y no privilegiados (ejecutados por un usuario normal). En este articulo vamos a trabajar con contenedores privilegiados.
Creación de un contenedor LXC
Al crear un contenedor se bajará el sistema de archivos que formará parte de él. La primera vez que bajamos con debootstrap
una versión de un sistema operativo se descargará un sistema de archivo mínimo del sistema (que llamamos plantilla) que servirá para crear todos los contenedores que creemos de la misma versión del sistema.
La creación de un contenedor con la última versión de debian, se realiza con la instrucción (ejecutada como root
):
$ lxc-create -n contenedor1 -t debian -- -r bullseye
-n
: Nombre del contenedor.-t
: Nombre de la plantilla.-r
: Es una opción de la plantilla. Es el nombre de la versión del sistema operativo. Para ver más opciones de una plantilla ejecutamos:lxc-create -t debian -h
.
Podemos comprobar que se ha creado un contenedor, ejecutando:
$ lxc-ls
contenedor1
La plantilla que hemos descargado se guarda en /var/cache/lxc/debian/rootfs-bullseye-amd64/
. Esta copia del sistema de archivo se utilizará cuando creemos otro contenedor con el mismo sistema operativo. El sistema de archivo del contenedor1
se guarda en /var/lib/lxc/contenedor1/rootfs/
.
Ahora podemos iniciar la ejecución del contenedor, comprobar que está funcionando y acceder a él:
$ lxc-start contenedor1
$ lxc-ls -f
NAME STATE AUTOSTART GROUPS IPV4 IPV6 UNPRIVILEGED
contenedor1 RUNNING 0 - 10.0.3.180 - false
$ lxc-attach contenedor1
root@contenedor1:~#
Iniciamos el contenedor con lxc-start
, comprobamos los contenedores que tenemos creados con lxc-ls
con la opción -f
nos da más información (vemos que está ejecutándose, que no se ejecuta al inicio, que ha tomado una dirección ip y que es privilegiado). Por último nos hemos conectado al contenedor con lxc-attach
.
Podemos parar el contenedor con lxc-stop
y eliminar el contenedor con lxc-destroy
.
Para visualizar todas las plantillas que podemos descargar, ejecutamos:
$ ls /usr/share/lxc/templates/
lxc-alpine lxc-archlinux lxc-centos lxc-debian lxc-fedora lxc-gentoo lxc-oci lxc-opensuse lxc-plamo lxc-sabayon lxc-sparclinux lxc-ubuntu lxc-voidlinux
lxc-altlinux lxc-busybox lxc-cirros lxc-download lxc-fedora-legacy lxc-local lxc-openmandriva lxc-oracle lxc-pld lxc-slackware lxc-sshd lxc-ubuntu-cloud
También puedes obtener la lista de plantillas en la página Image server for LXC and LXD.
Configuración de los contenedores LXC
El fichero /etc/lxc/default.conf
contiene la configuración general que van a tener los contenedores que creemos. Su contenido es el siguiente:
lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up
lxc.apparmor.profile = generated
lxc.apparmor.allow_nesting = 1
Como vemos se indica a que red se va a conectar (lxc.net.
) (lo veremos en otra entrada del blog). Una vez creado un contenedor, el contenido de este fichero se copia a su fichero de configuración (al que se añaden otras configuraciones por defecto). Por ejemplo el fichero de configuración del contenedor contenedor1
lo encontramos en el fichero /var/lib/lxc/contenedor1/config
. en este caso, su contenido es:
lxc.net.0.type = veth
lxc.net.0.hwaddr = 00:16:3e:cf:8f:c3
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up
lxc.apparmor.profile = generated
lxc.apparmor.allow_nesting = 1
lxc.rootfs.path = dir:/var/lib/lxc/contenedor1/rootfs
# Common configuration
lxc.include = /usr/share/lxc/config/debian.common.conf
# Container specific configuration
lxc.tty.max = 4
lxc.uts.name = contenedor1
lxc.arch = amd64
lxc.pty.max = 1024
Vemos que se han copiado los parámetros de la configuración general (/etc/lxc/default.conf
) y se han añadido nuevos parámetros: número máximo de terminales (lxc.tty.max
,lxc.pty.max
), nombre del contenedor (lxc.uts.name
), arquitectura (lxc.pty.max
), ubicación del sistema de fichero (lxc.rootfs.path
), …
Puedes ver los distintos parámetros que podemos incluir en la documentación oficial. Por ejemplo si queremos que los contenedores se inicien automáticamente al iniciar el host pondríamos:
lxc.start.auto = 1
Recuerda que tenemos dos opciones:
- Si escribimos el parámetro en la configuración general, en el fichero
/etc/lxc/default.conf
, afectará a los contenedores que se creen nuevos. - Si queremos modificar la configuración de un contenedor ya creado, tenemos que incluir el parámetro en su fichero de configuración, por ejemplo para el
contenedor1
en/var/lib/lxc/contenedor1/config
.
Obteniendo información de un contenedor
Para obtener información de un contenedor podemos ejecutar:
$ lxc-info contenedor1
Name: contenedor1
State: RUNNING
PID: 12587
IP: 10.0.3.180
Link: vethuLaHzY
TX bytes: 1.70 KiB
RX bytes: 3.80 KiB
Total bytes: 5.50 KiB
Con la opción -i
sólo nos da la dirección ip, con la opción -S
nos da la estadística de información enviada y recibida por la interfaz de red y con la opción -s
nos da información del estado.
Ejecución de comandos en un contenedor
Podemos ejecutar un comando en un contenedor que se esté ejecutando de la siguiente manera:
$ lxc-attach contenedor1 -- ls -al
si el contenedor está apagado, lo haríamos de a siguiente forma:
$ lxc-stop contenedor1
$ lxc-execute contenedor1 -- ls -al
Limitando los recursos para los contenedores LXC
Por defectos los contenedores LXC pueden usar todos los recursos de CPU, RAM, disco del host. Podemos limitar estos recursos. El componente del nucleo que posibilita limitar los recursos para cada contenedor son los Grupos de control cgroups, en concreto en Debian 11 se utiliza cgroupsv2.
Vamos a limitar el uso de memoria RAM (512Mb) y de número de procesadores (1 CPU: la CPU 0) (en la máquina donde estoy corriendo los contenedores tenemos “gb de RAM y 2 CPUs), para ello en el fichero de configuración del contenedor1
indicamos los siguientes parámetros:
lxc.cgroup2.memory.max = 512M
lxc.cgroup2.cpuset.cpus = 0
Reiniciamos el contenedor y comprobamos que se ha llevado a efecto el cambio:
$ lxc-stop contenedor1
$ lxc-start contenedor1
$ lxc-attach contenedor1 -- free -h
total used free shared buff/cache available
Mem: 512Mi 6.0Mi 505Mi 0.0Ki 0.0Ki 505Mi
$ lxc-attach contenedor1 -- cat /proc/cpuinfo
processor : 0
...
Aparece un sólo procesador.
Conclusiones
Actualmente el trabajo con contenedores es muy beneficioso para la administración de un sistema informático, ya que podemos aislar espacios separados (procesos, usuarios, servicios, sistemas de ficheros, redes,…) de manera muy sencillo y no un nivel de aislamiento aceptable. En la próxima entrada vamos a hacer una introducción a las redes y al almacenamiento en los contenedores linux: Introducción a las redes y almacenamiento en LXC.
Leave a Comment
Your email address will not be published. Required fields are marked *