¿Cómo usar cgroups para limitar todos los procesos excepto la lista blanca a una sola CPU?

26

Hay una guía de cgroups de Red Hat que puede ser un poco útil (pero no responde a esta pregunta).

Sé cómo limitar un proceso específico a una CPU específica, durante el comando para iniciar ese proceso, de la siguiente manera:

Primero, poniendo el siguiente * en /etc/cgconfig.conf:

mount {
  cpuset =  /cgroup/cpuset;
  cpu =     /cgroup/cpu;
  cpuacct = /cgroup/cpuacct;
  memory =  /cgroup/memory;
  devices = /cgroup/devices;
  freezer = /cgroup/freezer;
  net_cls = /cgroup/net_cls;
  blkio =   /cgroup/blkio;
}

group cpu0only {
  cpuset {
    cpuset.cpus = 0;
    cpuset.mems = 0;
  }
}

Y luego comience un proceso y asígnelo específicamente a ese cgroup usando:

cgexec -g cpuset:cpu0only myprocessname

Puedo limitar todas las instancias de un nombre de proceso específico automáticamente (creo que esto es correcto) poniendo lo siguiente en /etc/cgrules.conf:

# user:process  controller  destination
*:myprocessname cpuset      cpu0only

Mi pregunta es: ¿Cómo puedo hacer lo contrario ?

En otras palabras, ¿cómo puedo asignar todos los procesos, excepto un conjunto específico de procesos incluidos en la lista blanca y sus hijos a un cgroup restringido?


Basado en lo que he estudiado, pero no he probado, creo que una solución parcial sería:

Agregue un cgroup "sin restricciones":

group anycpu {
  cpuset {
    cpuset.cpus = 0-31;
    cpuset.mems = 0;  # Not sure about this param but it seems to be required
  }
}

Asignar mi proceso explícitamente al grupo sin restricciones, y todo lo demás al grupo restringido:

# user:process  controller  destination
*:myprocessname cpuset      anycpu
*               cpuset      cpu0only

Sin embargo, la advertencia sobre esto parece ser (a partir de la lectura de los documentos, no de las pruebas, por lo que el grano de sal) que los hijos de myprocessnameserán reasignados al cpu0onlycgroup restringido .

Un posible enfoque alternativo sería crear un usuario para ejecutar myprocessnamey tener todos los procesos de ese usuario sin restricciones, y todo lo demás restringido. Sin embargo, en mi caso de uso real, el proceso debe ejecutarse por root, y hay otros procesos que también deben ejecutarse por root que deben restringirse.

¿Cómo puedo lograr esto con cgroups?


Si esto no es posible con cgroups (que ahora sospecho es el caso), ¿ son correctas mis ideas de soluciones parciales y funcionarán como creo?

* Descargo de responsabilidad: este probablemente no sea un ejemplo de código mínimo; no entiendo todas las partes, así que no sé cuáles no son necesarias.

Comodín
fuente

Respuestas:

30

ACTUALIZACIÓN: Tenga en cuenta que la respuesta a continuación se aplica a RHEL 6. En RHEL 7, systemd administra la mayoría de los cgroups, y libcgroup está en desuso.


Desde la publicación de esta pregunta he estudiado toda la guía que he vinculado al anterior, así como la mayoría de la cgroups.txt documentación y cpusets.txt . Ahora sé más de lo que esperaba aprender sobre cgroups, así que responderé mi propia pregunta aquí.

Hay múltiples enfoques que puede tomar. El contacto de nuestra compañía en Red Hat (un Arquitecto Técnico) recomendó una restricción general de todos los procesos con preferencia a un enfoque más declarativo, restringiendo solo los procesos que específicamente queríamos restringir. La razón de esto, de acuerdo con sus declaraciones sobre el tema, es que es posible que las llamadas al sistema dependan del código de espacio del usuario (como los procesos LVM) que, si se restringe, podría ralentizar el sistema, lo contrario del efecto deseado. Así que terminé restringiendo varios procesos con nombres específicos y dejando todo lo demás solo.

Además, quiero mencionar algunos datos básicos de cgroup que me faltaban cuando publiqué mi pregunta.


Los grupos C no dependen de la libcgroupinstalación. Sin embargo, ese es un conjunto de herramientas para manejar automáticamente la configuración de cgroup y asignar tareas a cgroups y puede ser muy útil.

Descubrí que las herramientas de libcgroup también pueden ser engañosas, porque el paquete libcgroup se basa en su propio conjunto de abstracciones y suposiciones sobre su uso de cgroups, que son ligeramente diferentes a la implementación real de cgroups a nivel de kernel. (Puedo poner ejemplos, pero tomaría algo de trabajo; comente si está interesado).

Por lo tanto, antes de usar herramientas libcgroup (como /etc/cgconfig.conf, /etc/cgrules.conf, cgexec, cgcreate, cgclassify, etc.) Me altamente recomiendo conseguir muy familiarizado con el /cgroupmismo sistema de ficheros virtual, y la creación manual de cgroups, jerarquías cgroup (incluyendo jerarquías con múltiples subsistemas adjuntos, que libcgroup escondidas y resúmenes leakily lejos), reasignando procesos a diferentes grupos de c mediante la ejecución echo $the_pid > /cgroup/some_cgroup_hierarchy/a_cgroup_within_that_hierarchy/tasks, y otras tareas aparentemente mágicas que se libcgrouprealizan bajo el capó.


Otro concepto básico que me faltaba era que si el /cgroupsistema de archivos virtual está montado en su sistema (o más exactamente, si alguno de los subsistemas cgroup, también conocidos como "controladores", está montado), entonces todos los procesos en todo su sistema están en un cgroup. No existe tal cosa como "algunos procesos están en un cgroup y otros no".

Existe lo que se llama el cgroup raíz para una jerarquía dada, que posee todos los recursos del sistema para los subsistemas adjuntos. Por ejemplo, una jerarquía de cgroup que tiene los subsistemas cpuset y blkio conectados, tendría un cgroup raíz que sería el propietario de todos los cpus en el sistema y todos los blkio en el sistema, y ​​podría compartir algunos de esos recursos con cgroups secundarios . No puede restringir el cgroup raíz porque posee todos los recursos de su sistema, por lo que restringirlo ni siquiera tendría sentido.


Algunos otros datos simples que me faltaban sobre libcgroup:

Si lo usa /etc/cgconfig.conf, debe asegurarse de que chkconfig --list cgconfigmuestra que cgconfigestá configurado para ejecutarse en el arranque del sistema.

Si cambia /etc/cgconfig.conf, debe ejecutar service cgconfig restartpara cargar los cambios. (Y los problemas con la detención del servicio o la ejecución cgclearson muy comunes al perder el tiempo con las pruebas. Para la depuración, recomiendo, por ejemplo lsof /cgroup/cpuset, si cpusetes el nombre de la jerarquía de cgroup que está utilizando).

Si desea usar /etc/cgrules.conf, debe asegurarse de que el "demonio del motor de reglas de cgroup" ( cgrulesengd) se esté ejecutando: service cgred starty chkconfig cgred on. (Y debe tener en cuenta una posible pero improbable condición de carrera con respecto a este servicio, como se describe en la Guía de administración de recursos de Red Hat en la sección 2.8.1 al final de la página).

Si desea perder el tiempo manualmente y configurar sus cgroups usando el sistema de archivos virtual (que recomiendo para el primer uso), puede hacerlo y luego crear un cgconfig.confarchivo para reflejar su configuración usando cgsnapshotsus diversas opciones.


Y finalmente, la información clave que me faltaba cuando escribí lo siguiente:

Sin embargo, la advertencia sobre esto parece ser ... que los hijos de myprocessname serán reasignados al grupo cpu0only restringido.

Estaba en lo correcto, pero hay una opción que desconocía.

cgexec es el comando para iniciar un proceso / ejecutar un comando y asignarlo a un cgroup.

cgclassify es el comando para asignar un proceso que ya se está ejecutando a un cgroup.

Ambos también evitarán que cgred( cgrulesengd) reasigne el proceso especificado a un cgroup diferente en función de /etc/cgrules.conf.

Ambos cgexecy cgclassifyadmiten la --stickybandera, que además evita la cgredreasignación de procesos secundarios basados ​​en /etc/cgrules.conf.


Entonces, la respuesta a la pregunta tal como la escribí (aunque no la configuración que terminé implementando, debido al consejo de nuestro Arquitecto Técnico de Red Hat mencionado anteriormente) es:

Haga el grupo cpu0onlyy anycpuc como se describe en mi pregunta. (Asegúrese de que cgconfigesté configurado para ejecutarse en el arranque).

Haga la * cpuset cpu0onlyregla como se describe en mi pregunta. (Y asegúrese de que cgredesté configurado para ejecutarse en el arranque).

Iniciar cualquier proceso que quiero sin restricciones con: cgexec -g cpuset:anycpu --sticky myprocessname.

Esos procesos no tendrán restricciones, y todos sus procesos hijos tampoco tendrán restricciones. Todo lo demás en el sistema estará restringido a la CPU 0 (una vez que reinicie, ya cgredque no aplica cgrules a los procesos que ya se están ejecutando a menos que cambien su EUID). Esto no es completamente recomendable, pero eso fue lo que solicité inicialmente y se puede hacer con cgroups.

Comodín
fuente
Guau. guay. ¿Cómo tuvo esto 0 votos?
mikeserv
@mikeserv, gracias. :) Responda a su pregunta: verifique las fechas; Acabo de escribir esta respuesta ayer.
Comodín el
1
Vi eso. Pero fue hace 24 horas. probablemente su causa es larga. las cosas buenas a veces pueden pasarse por alto de esa manera. y de todos modos, las respuestas con muchos votos muy pronto rara vez son buenas: la información no puede ser tan útil si tanta gente ya lo sabe. Sin embargo, este es uno de los buenos. Los cgroups son jodidamente misteriosos.
mikeserv