Vorige maand heb ik gesproken op ApacheCon over Cgroups. Het blijkt dat maar heel weinig Linux-gebruikers (inclusief ondergetekende tot niet zo lang geleden) bekend zijn met Cgroups en hun kracht. Dit is jammer, want Cgroups zijn zeer krachtig, en stellen u in staat om resources op uw servers op een veel fijnmaziger manier toe te wijzen dan met welke andere tool dan ook in de Linux-toolkit. Bovendien is het rechtstreeks in de kernel ingebouwd en wordt het standaard meegeleverd met de meeste Linux-distributies.
In dit artikel zal ik behandelen hoe u Cgroups met Docker kunt gebruiken, als een soort vervolg op een andere presentatie die ik gaf op de Docker Meetup in Austin, Texas.
Dit artikel vereist wel enige basiskennis van Cgroups. Als u volledig nieuw bent met Cgroups, raad ik u aan om mijn slide-deck van ApacheCon te bekijken, evenals de bronnen aan het einde. Maak u echter geen zorgen, we zullen niet te diep gaan. Als u het slide-deck gewoon even snel doorneemt, zou u de basisconcepten moeten kunnen begrijpen.
Docker en Cgroups
Docker wordt geleverd met twee verschillende drivers: LXC en libcontainer. De LXC-driver is de verouderde driver, en libcontainer is de nieuwe en standaarddriver. In de meeste gevallen heeft libcontainer de voorkeur, omdat dat de plek is waar de innovatie plaatsvindt (bijvoorbeeld docker exec werkt niet met de LXC-driver).
Het is echter belangrijk om op te merken dat er twee verschillende drivers zijn, aangezien nog niet alle Cgroup-mogelijkheden naar libcontainer zijn overgezet (of in ieder geval zijn ontsloten voor Docker). Bij het gebruik van de LXC-driver geeft u LXC-argumenten rechtstreeks door, terwijl er bij libcontainer expliciete Cgroup-policy-argumenten aan Docker worden blootgesteld. U moet expliciet een driver instellen wanneer u de Docker-daemon start, dus u kunt de twee drivers niet tegelijkertijd uitvoeren.
Hier is een voorbeeld van hoe u dit kunt controleren:
[bash light=”true”] # Met de LXC-driver$ docker run -d –name=’lxc_test’ \
–lxc-conf="lxc.cgroup.cpu.shares=50" \
busybox
# Met de libcontainer-driver
$ docker run -d –name=’libcontainer_test’ \
–cpu-shares=50 \
busybox
[/bash]
Hier is een overzicht van enkele Cgroup-functies en hoe ze zich verhouden tussen de twee drivers:
| Functie | Libcontainer | LXC |
|---|---|---|
| Relatief CPU-aandeel | -c, –cpu-shares | –lxc-conf=”lxc.cgroup.cpu.shares” |
| Vastzetten op een CPU-core | –cpuset-cpus | –lxc-conf=”lxc.cgroup.cpuset.cpus” |
| Geheugen limiteren | -m, –memory | –lxc-conf=”lxc.cgroup.cpuset.mems” |
LXC
Als u de LXC-driver voor Docker wilt gebruiken, moet u deze eerst inschakelen. De methode hiervoor verschilt per Linux-distributie, maar hier zijn de instructies voor het inschakelen van de LXC-driver op Ubuntu 14.04.
Zoals hierboven vermeld, geeft u hiermee een aantal functies op. Daarom kunt u, tenzij u echt functionaliteit nodig hebt die nog niet in Docker is ontsloten via libcontainer, het beste bij de standaarddriver blijven.
Enkele nuttige Cgroup-policies die nog niet in libcontainer zijn ontsloten, zijn onder meer I/O-throttling (behandeld in de presentatie-slides), wat erg handig kan zijn voor bepaalde toepassingen.
Als u hebt besloten om de LXC-driver te gebruiken, is het toevoegen van argumenten eenvoudig. Het enige wat u hoeft te doen is het argument --lxc-conf toe te voegen en de Cgroup-policy door te geven die u wilt instellen.
Libcontainer
Zoals u in de bovenstaande tabel kunt zien, zijn de basis Cgroup-policies al ontsloten in de huidige versie of Docker (1.6 op het moment van schrijven).
Het gebruik van deze policies is heel eenvoudig. Als u bijvoorbeeld een Docker-container wilt vastzetten op de eerste CPU-core, voegt u --cpuset-cpus=0 toe aan uw docker run-commando.
U kunt ook het argument --cgroup-parent gebruiken met libcontainer en handmatig fijnmazigere resourcebeperkingen instellen. U koppelt het dan aan die groep met behulp van het argument.
Demo: Docker met Cgroups
In de onderstaande screencast gebruiken we twee Docker-containers (‘low_prio’ en ‘high_prio’). We gebruiken de ‘busybox’-basiscontainer en voeren md5sum /dev/urandom uit om een CPU-intensief proces te simuleren. Standaard zou dit alle beschikbare CPU-bronnen verbruiken. We passen echter twee Cgroup-beleidsregels toe om de bronnen te beheren. Eerst gebruiken we ‘cpuset.cpus’ om de containers te vergrendelen op dezelfde CPU-core (core 0).
Vervolgens gebruiken we ‘cpu.shares’ om een relatief CPU-aandeel toe te wijzen. We geven de ‘low_prio’-container een waarde van 20 en ‘high_prio’ een waarde van 80. Dit betekent dat 20% van de CPU wordt toegewezen aan de ‘low_prio’-container en 80% van de CPU aan de ‘high_prio’-container. Let er wel op dat het relatieve aandeel een willekeurige schaal is (we hadden net zo goed 2 en 8 als waarden kunnen gebruiken).
Nadat we hebben aangetoond dat het bronnenbeheer inderdaad werkt, starten we dezelfde set containers zonder Cgroup-beleidsregels om te zien hoe ze zich gedragen.
Ter referentie zijn hier de commando's die zijn gebruikt om de containers te starten.
[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]
Samenvatting
Als je meerdere Docker-containers op dezelfde host beheert, is het heel logisch om Cgroups te gebruiken om de bronnen tussen de containers te beheren. Misschien heb je bijvoorbeeld een aantal achtergrondtaken in de ene container draaien, terwijl een andere container gebruikersinhoud serveert. In dat geval kun je je nieuw verworven kennis gebruiken om ervoor te zorgen dat je prioriteit geeft aan de containers die op de gebruiker zijn gericht, vóór de achtergrondtaken.
Reacties
Nog geen reacties. Wees de eerste.