Virtualización de Linux: limitación de recursos mediante cgroups

En el artículo Virtualización de Linux – Chroot Jail , discutimos sobre los espacios de nombres del kernel y el encarcelamiento de procesos. Para comprender este artículo, es posible que no necesite leer el anterior, pero le sugiero encarecidamente que lo lea una vez antes de sumergirse en la limitación de recursos. Debería ayudar enormemente a entender lo que está pasando. 

¿Qué son los grupos c? 

cgroups (abreviado de grupos de control) es una característica del kernel de Linux que limita, contabiliza y aísla el uso de recursos (CPU, memoria, E/S de disco, red, etc.) de una colección de procesos. 
Esta función fue desarrollada originalmente por 2 ingenieros de Google, con el nombre de «contenedores de procesos», pero luego se fusionó en la línea principal del kernel de Linux con el nombre «cgroups». 

¿Por qué se requiere? 

Uno de los objetivos de diseño de cgroups es proporcionar una interfaz unificada para muchos casos de uso diferentes, desde el control de procesos individuales (mediante el uso de nice, por ejemplo) hasta la virtualización de todo el sistema operativo. En palabras simples, cgroups proporciona: 

  • Limitación de recursos: los grupos se pueden configurar para que no excedan un límite de memoria configurado, que también incluye el caché del sistema de archivos.
  • Priorización: algunos grupos pueden obtener una mayor participación en la utilización de la CPU o el rendimiento de E/S del disco.
  • Contabilidad: mide el uso de recursos de un grupo, que se puede utilizar, por ejemplo, con fines de facturación.
  • Control: congelación de grupos de procesos, su verificación y reinicio.

¿Cómo se utilizan, directa o indirectamente? 

Los grupos de control se pueden utilizar de varias maneras:  

  1. Accediendo manualmente al sistema de archivos virtual de cgroup.
  2. Creando y administrando grupos sobre la marcha usando herramientas como cgcreate, cgexec y cgclassify (de libcgroup).
  3. A través del «demonio del motor de reglas» que puede mover automáticamente los procesos de ciertos usuarios, grupos o comandos a cgroups según lo especificado en su configuración.
  4. Indirectamente a través de otro software que usa cgroups, como Docker, virtualización de Linux Containers (LXC), libvirt, systemd, Open Grid Scheduler/Grid Engine y lmctfy de Google.

Es posible que se sorprenda, pero este demonio silencioso constituye una parte sustancial de su experiencia en línea, ya que muchos sitios web usan contenedores/virtualización para alojar múltiples servidores o sitios web, incluidos NetFlix, heruko y reddit. 

Instalación de cgroups: algunas versiones de Linux vienen preinstaladas con cgroups. Para verificar si ya están instalados/montados, verifique la salida de:  

$ mount | grep "^cgroup"

Si ve archivos montados en /sys/fs/cgroup/, puede pasar directamente al siguiente tema para omitir la parte de instalación. 
El segundo comando instala cgroup-tools, lo que facilita el control y la supervisión de los grupos de control. Estaríamos usando los comandos del mismo en este tutorial. Usaremos la utilidad iotop para monitorear las tasas de E/S del disco.  

$ sudo apt-get install cgroup-bin cgroup-lite libcgroup1 cgroup-lite
$ sudo apt-get install cgroup-tools
$ sudo apt-get install iotop

Si instaló cgroups pero no puede verlos montados en /sys/fs/cgroup, use estos comandos,  

$ mount -t tmpfs cgroup_root /sys/fs/cgroup
$ mkdir /sys/fs/cgroup/blkio
$ mount -t cgroup -o blkio none /sys/fs/cgroup/blkio

Ejemplo 1: crearemos un grupo controlado por disco para que podamos ejecutar cualquier proceso con una cantidad finita de lecturas/escrituras de disco disponibles. es decir, queremos limitar las lecturas y escrituras realizadas por un proceso o un grupo de procesos. 

Paso 1: para crear un cgroup, simplemente cree un directorio en /sys/fs/cgroup o, si tiene una configuración de cgroup-tools, podemos usarlas en el directorio apropiado para el subsistema. El núcleo llena automáticamente el directorio de cgroup con los Nodes del archivo de configuración. Sin embargo, se recomienda utilizar la API de cgroup-tools, 

# Switch to root for the rest of the commands
$ sudo su                    
$ cgcreate -g blkio:myapp  OR  mkdir /sys/fs/cgroup/blkio/myapp

Este comando creará un subgrupo «myapp» bajo el sistema «blkio». El subsistema Block I/O (blkio) controla y supervisa el acceso a las E/S en los dispositivos de bloques por tareas en cgroups. Escribir valores en estos archivos proporciona acceso controlado a varios recursos. Puede verificar si su grupo está creado ejecutando el comando lscgroup, que enumera todos los grupos de control.  

$ lscgroup | grep blkio:/myapp
blkio:/myapp

Importante: estos archivos no son archivos normales en el disco. Estos son pseudo archivos y son utilizados directamente por el núcleo para leer y modificar la configuración. No los abra en un editor de texto e intente guardarlos. Utilice siempre el comando «echo» para escribirles. 

Antes de sumergirnos en cosas fáciles, veamos la estructura de directorios del grupo recién creado. Estos son algunos de los archivos importantes que necesitaremos en este tutorial para entender cómo funciona cgroup. (Los más importantes están resaltados en la imagen) 

linuxvirtualization

Paso 2: Creamos 2 terminales y los colocamos uno debajo del otro. Conviértase en usuario root en ambos terminales. En la terminal superior, ejecutamos la utilidad iotop para monitorear la E/S del disco,  

$ sudo su
$ iotop -o 

Mientras estamos en la siguiente terminal, creamos un archivo temporal de 512 MB usando el comando «dd»  

$ sudo su
$ dd if=/dev/zero of=~/test_if bs=1M count=512 

En el comando dd, «if» representa el archivo de entrada, «of» es el archivo de salida, «bs» es el tamaño del bloque y «count» es el número de veces que escribe el bloque. Una vez que finaliza el comando, se crea ~/temp_if con un tamaño de 512 MB. Puede ver las velocidades de E/S en tiempo real en la ventana del terminal superior. 

Paso 3: Ahora, para nuestro próximo experimento, debemos asegurarnos de haber vaciado todos los búferes del sistema de archivos en el disco y descartado todos los cachés para que no interfieran con nuestros resultados.  

$ free -m
$ sync
$ echo 3 > /proc/sys/vm/drop_caches
$ free -m 

Ahora, debería ver un aumento en la RAM disponible y un tamaño de caché reducido. 

Paso 3: Ahora, para configurar los límites de aceleración, usamos los siguientes comandos. Digamos que nos gustaría establecer un límite de lectura/escritura de 5 MB para un proceso. En la documentación del kernel, encontrará que blkio.throttle.read_bps_device y blkio.throttle.write_bps_device aceptan entradas del formato, 

<mayor>:<menor> <tarifas_por_segundo> 

donde mayor y menor son los valores para un dispositivo en particular, que queremos limitar la tasa. rates_per_second es la tasa máxima que puede lograr el proceso de ese grupo. 

Obtener los números mayores y menores es fácil. La máquina en la que estoy trabajando solo tiene un disco /dev/sda, por lo que al ejecutar el comando, ls -l /dev/sda* puedo obtener los números mayores y menores. 

linuxvirtualzation2

Los valores resaltados son los números mayor y menor de mi disco /dev/sda. 

Ahora, escribimos los siguientes valores para limitar la velocidad de lectura a 5 Mb/seg.  

$ echo "8:0 5242880" > /sys/fs/cgroup/blkio/myapp/blkio.throttle.read_bps_device
$ cat /sys/fs/cgroup/blkip/myapp/blkio.throttle.read_bps_device 

Antes de ejecutar el proceso controlado, debemos tener una idea de la velocidad de lectura sin estrangulación. Lea el archivo que creamos anteriormente ejecutando este comando en la terminal inferior.  

$ dd if=~/test_if of=/dev/null 

Paso 5: Puede ver las tasas de lectura en tiempo real en la terminal superior. Una vez completada la creación del archivo, también puede ver la tasa promedio, que se muestra con el comando dd. Vacíe los datos en el disco y elimine todas las cachés, como se mostró anteriormente para evitar cualquier ambigüedad en los resultados. 

Para ejecutar este comando bajo la limitación, usamos cgexec  

$ cgexec -g blkio:/myapp dd if=~/test_if of=/dev/null 

donde proporcionamos el nombre : al argumento -g, en este caso es «blkio:myapp». Las tarifas en la terminal superior deberían verse similares a esto. 

linuxvirtualzation3

La parte interesante de esto es que podemos tomar cualquier aplicación que no tenga un límite de velocidad incorporado, podemos acelerarla según sea necesario.  

linuxvirtualzation4

El gráfico anterior se traza mientras se leen 2 archivos, cuyos procesos pertenecen al mismo cgroup, con un límite de aceleración de lectura de 50 Mb/seg. Como puede ver inicialmente, la velocidad de lectura salta al máximo, pero tan pronto como comienza la segunda lectura, se equilibra y alcanza un total de 50 MB/s, como se esperaba. Una vez que finaliza la lectura de «file-abc», la tasa salta para alcanzar los máximos nuevamente. 

Puede cambiar la velocidad en tiempo real haciendo eco de los nuevos valores en los archivos blkio.throttle . Kernel actualizará las configuraciones automáticamente. 

Ejemplo 2: Seguimos pasos similares para crear una aplicación limitada por la memoria. Omitiré la explicación ya que la mayor parte es la misma y pasaré directamente a los comandos. 

Paso 1: he creado un programa c simple que asigna 1 MB en cada iteración y se ejecuta para un total de 50 iteraciones, asignando un total de 50 MB. 

// a simple c-program that allocates 1MB in each
// iteration and run for a total of 50 iterations,
// allocating a total of 50 MB
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    int i;
    char *p;
    for (i = 0; i < 50; ++i)
    {
        // Allocate 1 MB each time.
        if ((p = malloc(1<<20)) == NULL)
        {
            printf("Malloc failed at %d MB\n", i);
            return 0;
        }
        memset(p, 0, (1<<20));
        printf("Allocated %d to %d MB\n", i, i+1);
    }

    printf("Done!\n");
    return 0;
}
$ sudo su         # Switch to root for the rest of the commands
$ cgcreate -g memory:myapp_mem  OR  mkdir /sys/fs/cgroup/memory/myapp_mem
$ cd /sys/fs/cgroup/memory/myapp_mem
$ lscgroup        # To check if the group was created successfully. 

Ahora, el formato para la configuración de aceleración de la memoria se puede obtener de la documentación del kernel. (Enlace en las referencias)  

$ echo "5242880" > memory.limit_in_bytes 

Antes de ejecutar el código, debemos deshabilitar el intercambio. Si el programa no puede obtener memoria de la RAM (ya que la tenemos limitada), intentará asignar memoria en el intercambio, lo que no es deseable en nuestro caso.  

$ sudo swapoff -a # Disable swap 

linuxvirtualzation5

El estado de intercambio debe ser similar al que se muestra arriba. 

$ gcc mem_limit.c -o mem_limit 

Primero, ejecute el código sin límites de memoria, 

$ ./mem_limit 

Ahora, compare su salida cuando se ejecuta desde dentro del cgroup controlado, 

$ cgexec -g memory:myapp_mem /root/mem_limit 

Puede verificar información de contabilidad de varios recursos, como el uso actual de la memoria, la memoria máxima utilizada, el límite de memoria, etc. 

$ cat memory.usage_in_bytes
$ cat memory.max_usage_in_bytes
$ cat memory.limit_in_bytes 

Hay más parámetros que puede explorar, como memory.failcnt, memory.kmem.* y memory.kmem.tcp.* 
Cuanto más lea la documentación, mejor será su comprensión. 

Podemos ampliar este método y crear aplicaciones limitadas. Este método fue creado hace mucho tiempo, pero es recientemente que ha sido ampliamente utilizado en numerosas aplicaciones. Las máquinas virtuales, los contenedores, etc. usan esto para hacer cumplir los límites de recursos. 
El propósito de entender cgroups era comprender cómo se realiza realmente la limitación de recursos en los contenedores. El siguiente tema a explorar son los contenedores. Hablaremos de ello en detalle en el próximo artículo. 

Referencias:  

Sobre el Autor: 

 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *