Docker-Ressourcen mit Cgroups verwalten

Kürzlich habe ich auf der ApacheCon über Cgroups referiert. Wie es den Anschein hat, sind nur sehr wenige Linux-Nutzer (einschließlich bis vor kurzem Ihre) mit Cgroups und ihrem Potenzial vertraut. Das ist schade, denn Cgroups sind sehr leistungsfähig und ermöglichen Ihnen, Ressourcen auf Ihren Servern weit detaillierter zuzuweisen als jedes andere Tool, das im Linux-Toolkit zur Verfügung steht. Darüber hinaus sind sie direkt in den Kernel integriert und standardmäßig Teil der meisten Linux-Distributionen.

Dieser Beitrag beschäftigt sich mit dem Einsatz von Cgroups mit Docker. Darüber hinaus wird ein Demo vorgestellet, das ich auf dem Docker Meetup in Austin, Texas, gehalten habe.

Um das Folgende zu verstehen, sind zumindest grundlegende Kenntnisse zu Cgroups erforderlich. Wenn Sie noch nie mit dem Thema zu tun hatten, empfehle ich, zunächst einen Blick auf meine Präsentation auf der ApacheCon sowie die Ressourcen am Ende zu werfen. Aber keine Angst, es geht nicht zu sehr in die Tiefe. Nach einem Überfliegen der Präsentation sollten Sie in der Lage sein, die grundlegenden Konzepte zu verstehen.

Docker und Cgroups

Docker verfügt über zwei verschiedene Treiber: LXC und libcontainer. Der LXC-Treiber ist der Legacy-Treiber und libcontainer der neue Standardtreiber. In den meisten Fällen ist libcontainer der bevorzugte Treiber, da er Innovationen ermöglicht (docker exec funktioniert zum Beispiel nicht mit dem LXC-Treiber).

Es ist jedoch wichtig daran zu denken, dass es zwei verschiedene Treiber gibt, da nicht alle Cgroup-Funktionen bereits auf libcontainer portiert wurden (oder zumindest für Docker verfügbar sind). Wenn Sie den LXC-Treiber verwenden, leiten Sie einfach LXC-Argumente direkt weiter. Bei libcontainer, auf der anderen Seite, sind explizite Argumente für Cgroup-Richtlinien für Docker verfügbar. Wenn Sie den Docker-Daemon starten, müssen Sie explizit einen Treiber festlegen, damit Sie nicht beide gleichzeitig ausführen können.

Hier ein Beispiel, wie Sie das prüfen können:

[bash light=”true”] # With the LXC driver
$ docker run -d –name=’lxc_test’ \
–lxc-conf="lxc.cgroup.cpu.shares=50" \
busybox

# With the libcontainer driver
$ docker run -d –name=’libcontainer_test’ \
–cpu-shares=50 \
busybox
[/bash]

Ein Überblick über einige der Cgroup-Funktionalitäten und deren Aufteilung auf die beiden Treiber:

Funktionalität Libcontainer LXC
Relative CPU share -c, –cpu-shares –lxc-conf=”lxc.cgroup.cpu.shares”
Lock to a CPU core –cpuset-cpus –lxc-conf=”lxc.cgroup.cpuset.cpus”
Limit memory -m, –memory –lxc-conf=”lxc.cgroup.cpuset.mems”

LXC

Wenn Sie den LXC-Treiber für Docker verwenden möchten, müssen Sie ihn zunächst aktivieren. Die Methode hierfür unterscheidet sich je nach Linux-Distribution. Das Folgende bezieht sich auf die Aktivierung des LXC-Treibers auf Ubuntu 14.04.

Wie bereits erwähnt, verzichten Sie in diesem Fall auf eine Reihe von Funktionalitäten. Sie sollten das daher nur tun, wenn Sie unbedingt eine Funktionalität benötigen, die mit libcontainer noch nicht in Docker zur Verfügung steht.

Zu den nützlichen Cgroup-Richtlinien, die noch nicht mit libcontainer verfügbar sind, zählt die I/O-Drosselung (siehe Präsentation). Das kann für bestimmte Anwendungen sehr praktisch sein.

Wenn Sie sich für den LXC-Treiber entschieden haben, ist das Hinzufügen von Argumenten einfach. Alles, was Sie tun müssen, besteht darin, das Argument --lxc-conf hinzuzufügen und in die Cgroup-Richtlinie zu übergeben, die Sie festlegen möchten.

Libcontainer

Wie Sie in der obigen Tabelle sehen können, sind die grundlegenden Cgroup-Richtlinien bereits in der aktuellen Version von Docker (zum Zeitpunkt dieser Veröffentlichung 1.6) verfügbar.

Der Einsatz dieser Richtlinien ist sehr einfach. Wenn Sie beispielsweise einen Docker-Container auf dem ersten CPU-Kern sperren möchten, müssen Sie --cpuset-cpus=0 an Ihren Docker-Startbefehl docker run anhängen.

Sie können auch das Argument --cgroup-parent mit libcontainer verwenden und manuell detailliertere Ressourcenbeschränkungen festlegen. Sie müssten dann es zu der Gruppe zuordnen, die das Argument nutzt.

Demo: Docker mit Cgroups

Im folgenden Screencast verwenden wir zwei Docker-Container (‘low_prio’ und ‘high_prio’). Wir verwenden den ‘busybox’-Basiscontainer und führen md5sum /dev/urandom aus, um einen CPU-aufwendigen Prozess zu simulieren. Dies würde standardmäßig alle verfügbaren CPU-Ressourcen beanspruchen. Nun wenden wir allerdings zwei Cgroup-Richtlinien an, um die Ressourcen zu verwalten. Zuerst verwenden wir ‘cpuset.cpus’, um die Container demselben CPU-Kern zuzuweisen (Core 0).

Als nächstes verwenden wir ‘cpu.shares’, um einen relativen CPU-Anteil zuzuweisen. Wir weisen dem Container ‘low_prio’ einen Wert von 20 zu und ‘high_prio’ einen Wert von 80. Dies bedeutet, dass 20 % der CPU dem Container ‘low_prio’ zugeordnet werden und 80 % der CPU dem Container ‘high_prio‘. Bitte beachten Sie jedoch, dass dieser relative Anteil beliebig ist (wir könnten auch 2 und 8 als Werte verwenden).

Nachdem wir gezeigt haben, dass das Ressourcenmanagement tatsächlich funktioniert, starten wir dieselben Container ohne Cgroup-Richtlinien, um zu sehen, wie sie sich verhalten.

Zur Referenz finden Sie hier die Befehle zum Starten der Container:

[bash light=”true”] $ docker run -d \
–name=’low_prio’ \
–cpuset-cpus=0 \
–cpu-shares=20 \
busybox md5sum /dev/urandom
$ docker run -d \
–name=’high_prio’ \
–cpuset-cpus=0 \
–cpu-shares=80 \
busybox md5sum /dev/urandom
[/bash]

Zusammenfassung

Wenn Sie mehrere Docker-Container auf demselben Host verwalten, ist es sehr sinnvoll, die Ressourcen zwischen den Containern mittels Cgroups zu verwalten. Beispielsweise haben Sie möglicherweise einige Hintergrundprozesse, die in einem Container ausgeführt werden, und einen anderen Container mit Anwenderinhalten. In diesem Fall können Sie Ihr neu gewonnenes Wissen verwenden, um sicherzustellen, dass Sie anwenderorientierte Container gegenüber Hintergrundaufgaben priorisieren.

About Viktor Petersson

Former VP of Business Development at CloudSigma. Currently CEO at WireLoad and busy making a dent in the Digital Signage industry with Screenly. Viktor is a proud geek and loves playing with the latest technologies.