Containers shuffelen met een Docker Swarm installatie

In deze blogpost wil ik graag toelichten hoe makkelijk je een setje computers omtovert in een echte Docker Swarm installatie. Docker is al superhandig om toepassingen portable te maken en daarmee makkelijk te kunnen distribueren en (op)schalen. Om het feest compleet te maken is een echte Docker Swarm installatie wel leuk om eenvoudig te kunnen shuffelen met containers binnen de beschikbare resources van een cluster.

Ik heb een tijdje geleden 4 machines op de kop getikt om daarop al mijn nasty hacks te kunnen loslaten. Nu is het tijd om, naast de rol van een “echt” Hadoop-cluster ook de rol van Docker-cluster in te nemen. Ik ben uitgegaan van de officiële Docker Swarm install manual waarvan je in deze blogpost een groot deel terugziet.

Wat hebben we nodig aan software componenten om van n (4 in mijn geval) losse machines een Docker Swarm te maken?

  1. Docker Engine op alle machines (basis om Docker containers te kunnen runnen)
  2. Een service-discovery backend (dingetje dat bijhoudt welke machines welke (Docker) services beschikbaar hebben)
  3. Minimaal 1 Docker Swarm Manager.

Let’s go!

Installatie van Docker Engine op de hosts.

De machines draaien CentOS 7, dus we hebben een yum package manager. Die gaan we eerst even bijwerken op alle machines; een goede gewoonte voor je nieuwe software gaat installeren.
Ik gebruik voor het beheer van de 4 machines vanaf mijn Mac o.a. csshX. Daarmee zijn meerdere machines tegelijk via ssh te bedienen: scheelt veel typewerk. Onderstaande commando’s vuur ik af op alle machines.

sudo yum update

Daarna  kan Docker Engine geïnstalleerd worden.

curl -sSL https://get.docker.com/ | sh

Hierna kunnen we de Docker daemon (service) opstarten. Normaal gesproken luistert de Docker daemon alleen op een unix socket. Om de manager met de verschillende Docker Engines te kunnen laten praten moet de daemon gestart worden met een extra optie om ook te luisteren op een TCP-port.

docker daemon -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock

Nu luisteren de Docker Engines dus zowel via de standaard socket als via port 2375 naar Docker-commando’s. Dit kun je testen door een eerste Docker container te starten (ja ja, daar is de hello-world weer)

docker run hello-world

Dit zou op alle 4 de machines moeten werken. Bij de eerste run wordt het image “hello-world” vanuit de Docker Hub gedownload waarna dit image gerund wordt (een container). Uiteraard doet het niet veel meer dan “Hello world” op het scherm toveren, maar dat is wel genoeg voor nu.

“Installatie” van Consul.

Om de verschillende machines en services van elkaars bestaan op te hoogte te brengen gebruiken we een discovery backend. In dit geval Consul, maar je kan ook Zookeeper gebruiken of een old-school statische config-file. Ik denk dat ik met consul een prima oplossing heb. Want ondanks dat dit cluster ook ingezet kan worden voor Hadoop-related hacks, draaien die services (waaronder dus Zookeeper) niet altijd.

De 4 machines heb ik ooit hnode1 t/m hnode4 genoemd (H van Hadoop) met IPv4 adressen van 192.168.1.121 t/m 124. Ze zijn bij elkaar bekend middels listing in de hosts file. Voor het gemak ga ik Consul draaien op hnode1.

Consul draait in een Docker container op basis van het image progrium/consul en kan zo vanuit de Docker Hub gedownload worden (zie hier de voordelen van Docker!). Eigenlijk hoeft er niet meer te gebeurden dan het runnen van dit image in daemon mode onder de naam consul met een portmapping naar port 8500. De daemon wordt opgestart met de argumenten -server en -bootstrap (wat dat precies doet zal wel ergens op het web te vinden zijn)

docker run -d -p 8500:8500 --name=consul progrium/consul -server -bootstrap

Hiermee hebben we dus een discovery service aangezwengeld. Verderop gaan we de managers en de nodes aanmelden bij Consul. Zie het als inchecken bij de NS…
Om te bewijzen dat er daadwerkelijk een container actief is, gebruiken we het ps commando binnen Docker.

docker ps

De container-id van de Consul-container blijk 36e3489ce070 te zijn. Daar maken we

“Installatie” van Docker Swarm manager(s).

Ok. Die Consul hebben we nodig, maar die kan geen containers voor ons beheren. Dat is manager werk. Managers zijn altijd heel druk, dus daar heb je er wel meer dan 1 van nodig om de boel een beetje veilig in het gareel te houden. Docker managers zijn van het type: “wie het hardst schreeuwt, krijgt de klus”. Dat ik hier heel fijn, want met meerdere managers (bekend in het cluster via Consul) wordt de status van het cluster gerepliceerd (MT-overleg) en vindt er automatisch overdacht plaats wanneer de primaire manager het begeeft; dan gaan ze allemaal schreeuwen en krijgt de hardst schreeuwende de status primary manager.

Ook de managers runnen in Docker containers. Ik ga ze onderbrengen op hnode1 en hnode2 met het verzoek vooral te luisteren op poort 4000. Dit mag uiteraard ook een ander poort nummer zijn als deze niet meer vrij is (zie hiervoor de documentatie van docker run aangaande de -p optie)

Voor hnode1 met IPv4 192.168.1.121:

docker run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise 192.168.1.121:4000 consul://192.168.1.121:8500

en voor  hnode2 met IPv4 192.168.1.122:

docker run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise 192.168.1.122:4000 consul://192.168.1.121:8500

Tijd voor de werknemers

We hebben nu al een mooie Docker-toko: Een Consul die iedereen kent en een setje managers die beloven de boel in het gareel te houden. We hebben officieel alleen nog niemand die daadwerkelijk het werk wil uitvoeren (ze zijn nog een beetje onzichtbaar helaas). Daar gaan we even verandering in brengen door elke machine te koppelen aan de Swarm.

Dus op elke node starten we een daemon die de werknemer in beeld houdt bij de manager via Consul.

Voor hnode[n] met IPv4 192.168.1.12[n]:

docker run -d swarm join --advertise=192.168.1.12[n]:2375 consul://192.168.1.121:8500

Op dit moment is onze Docker Swarm installatie gereed voor gebruik. Een overzicht kunnen we (bijvoorbeeld vanaf hnode4) via een manager (of de replica in dit voorbeeld) gemakkelijk opvragen:

[root@hnode4 ~]# docker -H hnode2:4000 info

De output lijkt dan hierop:

Containers: 29
Running: 7
Paused: 0
Stopped: 22
Images: 11
Server Version: swarm/1.2.3
Role: replica
Primary: 192.168.1.121:4000
Strategy: spread
Filters: health, port, containerslots, dependency, affinity, constraint
Nodes: 4
hnode1.dbiq.nl: 192.168.1.121:2375
└ ID: BDIZ:FUL2:5CI6:FCJ7:F4A5:PO64:EPPO:USNO:XWF6:YWLO:MXZ6:EUDL
└ Status: Healthy
└ Containers: 9
└ Reserved CPUs: 0 / 2
└ Reserved Memory: 0 B / 7.891 GiB
└ Labels: executiondriver=, kernelversion=3.10.0-327.22.2.el7.x86_64, operatingsystem=CentOS Linux 7 (Core), storagedriver=devicemapper
└ UpdatedAt: 2016-07-13T13:46:26Z
└ ServerVersion: 1.11.2
hnode2.dbiq.nl: 192.168.1.122:2375
└ ID: JISA:XFC5:WZBZ:E2DI:4WMC:PUXC:4FE4:XNWG:3SI4:LPAI:6NA4:BA5E
└ Status: Healthy
└ Containers: 7
└ Reserved CPUs: 0 / 2
└ Reserved Memory: 0 B / 7.891 GiB
└ Labels: executiondriver=, kernelversion=3.10.0-327.22.2.el7.x86_64, operatingsystem=CentOS Linux 7 (Core), storagedriver=devicemapper
└ UpdatedAt: 2016-07-13T13:46:29Z
└ ServerVersion: 1.11.2
hnode3.dbiq.nl: 192.168.1.123:2375
└ ID: LJIA:MWLN:KKLP:CYUY:O5AO:WUYD:JY45:A24M:R6HJ:PG7J:D7AI:Q65E
└ Status: Healthy
└ Containers: 6
└ Reserved CPUs: 0 / 2
└ Reserved Memory: 0 B / 7.891 GiB
└ Labels: executiondriver=, kernelversion=3.10.0-327.22.2.el7.x86_64, operatingsystem=CentOS Linux 7 (Core), storagedriver=devicemapper
└ UpdatedAt: 2016-07-13T13:46:30Z
└ ServerVersion: 1.11.2
hnode4.dbiq.nl: 192.168.1.124:2375
└ ID: 66P4:EBJV:QIAD:CURG:QM7L:SFCQ:LC7G:I6FD:N2ND:MGUE:4H5U:V6L4
└ Status: Healthy
└ Containers: 7
└ Reserved CPUs: 0 / 2
└ Reserved Memory: 0 B / 7.891 GiB
└ Labels: executiondriver=, kernelversion=3.10.0-327.22.2.el7.x86_64, operatingsystem=CentOS Linux 7 (Core), storagedriver=devicemapper
└ UpdatedAt: 2016-07-13T13:46:18Z
└ ServerVersion: 1.11.2
Plugins:
Volume:
Network:
Kernel Version: 3.10.0-327.22.2.el7.x86_64
Operating System: linux
Architecture: amd64
CPUs: 8
Total Memory: 31.56 GiB
Name: c65ce86fcf07
Docker Root Dir:
Debug mode (client): false
Debug mode (server): false

Om de werknemers aan het werk te zetten, kunnen we op elke host via de manager het werk verdelen. Bijvoorbeeld een “Hello world”

docker swarm -H 192.168.1.121:4000 run hello-world

De configuratie reboot-proof maken.

Het belangrijkste bij de Docker Swarm installatie komt nu. Gek genoeg vind je daar weinig van terug in de Docker documentatie; mogelijk omdat Docker op vele verschillende OS-en kan draaien en daarmee de config sterk afwijkt.
In CentOS worden systeemservices beheert door systemd. Commando’s geven aan systemd doen we o.a. via systemctl. Dat klinkt velen al bekender in de oren.
Wat we willen is het volgende:

  • bij start van systeem Docker Engine aanzwengelen als een service
  • onder Docker Engine “Service” een Consul-container draaien,
  • onder Docker Engine “Service” onze managers draaien (ook in containers, zoals hierboven beschreven)
  • onder Docker Engine “Service” onze nodes “aanmelden” bij Consul

Laten we daarom bij het begin (en gelijk het makkelijkste) beginnen.

Docker Engine als systeemservice.

Als Docker engine goed werkt (en dat doet het als een docker run hello-world “Hello world” roept), dan kunnen we Docker Engine met een gerust hart opstarten bij een reboot.

systemctl enable docker

Het volgende commando laat vervolgens de service definitie zien

systemctl cat docker

Daarin zien we de volgende regel:

ExecStart=/usr/bin/docker daemon -H fd://

Helaas wordt de Docker Engine hiermee niet gestart met de tcp://0.0.0.0:2375 optie zoals die hierboven is gebruikt om de Docker Swarm installatie te laten werken. Gelukkig kunnen we gemakkelijk een aanpassing maken op de servicedefinitie.

systemctl edit docker

Dit geeft ons een scherm van de default editor (VI bij mij).
We willen een aantal elementen van de service overrulen. Voor de ExecStart geldt dat deze eerst leeg gedefinieerd moet worden (een soort reset). En we gaan meteen gebruik maken van de ExecStartPost functionaliteit om na het starten van de Docker Engine een aantal containers te starten. Onderstaande start na de Docker Engine service de Consul, de manager en de Swarm advertise op hnode1 middels hun container-id.

[Service]
ExecStart=
ExecStart=/usr/bin/docker daemon -H fd:// -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
ExecStartPost=/usr/bin/docker start 36e3489ce070
ExecStartPost=/usr/bin/docker start de27fc6d907b
ExecStartPost=/usr/bin/docker start 89dcd3830e5d

Om het af te maken doen we dit dus ook op hnode2 t/m hnode4. We zullen daar echter voorlopig geen Consul draaien en de container-id zijn uiteraard anders.

Nu kan het systeem met een gerust hart een rebootje ondergaan.

Submit a Comment

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *