Ressourcen-Verwaltung mit Control Groups (cgroups)
libcgroup
Da es sich bei dem Dateisystem cgroup
um ein Pseudo-Dateisystem handelt, werden vorgenommene Einstellungen nicht persistent auf ein Speichermedium geschrieben. Bei einem Neustart des Systems gehen sowohl alle erstellten Gruppen sowie deren Subsystem-Konfigurationen als auch die Liste der PIDs verloren, Wobei letztere nach einem Neustart mit Sicherheit nicht wiederverwendbar wären.
Abhilfe wäre, (Init-) Skripte zu schreiben, welche die Control Groups erstellen und die Subsysteme konfigurieren. Das Zuweisen der Prozesse/Dienste zu einer bestimmten Gruppe ist allerdings etwas schwieriger. Eine Möglichkeit wäre, sämtliche Init-Skripte zu modifizieren, um direkt nach dem Start des Prozesses die PID herauszufinden und einer bestimmten cgroup zuzuweisen. Dabei handelte es sich allerdings um einen sehr tiefen Eingriff in die jeweilige Distribution und könnte bei einem Maintenance-Update oder dergleichen eventuell zu Problemen führen. Der Verwaltungsaufwand solcher versteckter Modifikationen ist ein weiteres Problem.
All dieser Probleme hat sich das Projekt libcgroup
gewidmet. Wie der Name vermuten lässt, handelt es sich hierbei um eine Bibliothek für Control Groups, welche eine Schnittstelle anbietet, um Control Groups einheitlich einzurichten und zu konfigurieren. Diese Bibliothek basiert für sämtliche Vorgänge vollständig auf dem virtuellen cgroup-Dateisystem. Neben einer Control Group API beinhaltet dieses Projekt ein PAM-Modul pam_cgroup.so
, einige Kommandozeilen-Werkzeuge und einen Daemon.
Zentraler Bestandteil von libcgroup
ist das Laden der eigenen Konfigurationen, geläufig als /etc/cgconfig.conf, welche anschließend Gruppen erstellen und entsprechende Subsystem-Einstellungen in diesen vornehmen.
group profs { perm { task { gid = professors; } admin { uid = root; gid = root; } } cpu { cpu.shares = 512; } } group students { [... analog zu profs group ...] } mount { cpu = /cgroup; }
Mit dieser Konfiguration wird an der Stelle /cgroup das cgroup-Dateisystem eingehängt mit dem Subsystem cpu
. Anschließend werden in dieser Hierarchie zwei cgroups erstellt: profs
und students
. Das Group Scheduler Subsystem cpu
bekommt für cpu.shares
den Wert 512 gesetzt. Die Datei /cgroup/profs/tasks wird der Gruppe professors
zugeordnet, damit Nutzer in der Gruppe professors
Prozesse zuweisen können. Dazu sind Schreibrechte auf die tasks
-Datei notwendig. Subsystem-Konfigurationen in der profs
Control Group können nach wie vor nur von root
durchgeführt werden, da nur dieser Schreibrechte für diesen Ordner und dessen Optionen, mit Ausnahme von tasks
, bekommen hat. Ein analoges Setup erfolgt für die Gruppe students
. Als Skript wären folgende Befehle nötig:
# mkdir /cgroup # mount -t cgroup -o cpu nodev /cgroup # mkdir /cgroup/profs # /bin/echo 512 > /cgroup/profs/cpu.shares # chown -R root.root /cgroup/profs/ # chgrp professors /cgroup/profs/tasks # mkdir /cgroup/students [...]
Diese Konfiguration wird meist durch das Werkzeug cgconfigparser
geparst. Möglich ist auch das Parsen durch andere Applikationen, welche die libcgroup-API implementiert haben.
In den meisten Distributionen wird dem libcgroup-Software-Paket ein
Init-Skript beigefügt, welches cgconfigparser
aufruft. So werden bei einem Neustart direkt Control Groups anhand der Konfiguration in /etc/cgconfig.conf eingerichtet. Dies erleichtert die Pflege und Wartung der Control Groups um ein Vielfaches, da keine individuellen Skripte gepflegt werden müssen.
Die Datei cgrules.conf (bzw. /etc/cgrules.conf) ist für die Regeln vorgesehen, welche Prozesse im System den entsprechenden cgroups zugewiesen werden sollen. pam_cgroup.so
und libcgroup-Werkzeuge wie cglassify
und cgexec
sowie der Daemon cgrulesengd
nutzen diese Regeln und weisen die Prozesse ihrer entsprechenden Gruppe zu. Die Einträge in cgrules.conf
haben drei Spalten:
#<user> <subsystem> <destination> tux cpu,cpuset profs/tux/ @profs cpu,cpuset profs
Die user
-Spalte erwartet eine ähnliche Notation wie die Einträge in limits.conf. Ein anführendes @ steht für eine Gruppe, ein Eintrag ohne @ für einen Benutzer. Möglich ist auch die Verwendung von * als Wildcard. In der Spalte subsystem
steht das cgroups-Subsystem, destination
bezeichnet die cgroups-Gruppe.
Aktuelle Versionen (> 0.32) unterstützen auch Regeln auf Basis des Prozess-Namens:
#<user>:<process name> <subsystem> <destination>
Mit dem Aufruf cgexec
können Prozesse beim Start anhand der vordefinierten Regel ihrer entsprechenden Gruppe zugewiesen werden. Optional ist es möglich, die Regeln mit dem Parameter -g <subsystem>:<path>
zu übergehen und so Prozesse einer anderen Hierarchie zuzuführen, als in cgrules.conf definiert ist.
Wenn der Daemon cgrulesengd
gestartet wird, übernimmt er diese Aufgaben automatisch und verschiebt Prozesse in die vorgesehene Control Group. Hierbei werden auch Änderungen der UID oder GID laufender Prozesse ständig beobachtet und entsprechend reagiert.