Több processz indítása Docker konténerben

Borító kép powerpointtal szerkesztve

Hogy mi a jelentősége annak, hogy a Docker konténerekben megfelelően állítsuk össze a futtatandó parancsot és a "docker stop" parancs ne vezessen adatvesztéshez, arról már volt szó. Minden eddigi megoldás viszont leginkább egyetlen program esetén volt jó, ráadásul megfelelő gyakorlat nélkül nagyobb az esélye annak, hogy valamit elhibázunk. Ha ráadásul több, a háttérben futó programot kellene kezelni egyetlen konténerben, annak leprogramozása shell szkriptben még nagyobb odafigyelést igényelne. Bár általában elkerüljük ezt a utat és minden program külön konténert kap, vannak olyan esetek, amikor ezt nem tudjuk megtenni. Ilyenkor kell keresnünk egy olyan eszközt, ami kezeli a háttérben futó szolgáltatások processzeit, beleértve a standard inputot és az error streamet is. Docker konténereknél talán a legelterjedtebb megoldás a Supervisor. A következőkben a korábban használt Python HTTP servert és az Apache HTTPD szervert fogom egy konténerben indítani.

Forráskód: https://github.com/itsziget/tutorial-linux-signals/tree/step-04

Tartalomjegyzék

Supervisor telepítése és indítása

[Tartalom]

A supervisor egy Pythonban írt program, így szükség lesz Pythonra a konténerben is. A dokumentációban többféle telepítési mód is megtalálható, amik közül a legegyszerűbb a pip csomagkezelővel telepítés, ezért a példában is ezt fogom használni. Amint a Python telepítve van a pip csomagkezelővel és a setuptools modullal, Python 3 esetén ennyi a telepítés:

pip3 install supervisor==4.2.2
echo_supervisord_conf > /etc/supervisord.conf

Ezután pedig tetszés szerint módosítani lehet a generált konfigurációs fájlt, majd az alábbi módon elindítani a supervisord szervert:

supervisord -c /etc/supervisord.conf

Bár automatikusan is képes lenne a supervisord betölteni a konfigurációs fájlt, ha olyan helyre mentettük, mégis érdemes megadni egy konkrét fájlt, hogy ne érjenek meglepetések például ottfelejtett, régi fájlok miatt. Amikor konténerben indítjuk a supervisord-t, fontos, hogy az előtérben induljon, különben azonnal leáll a konténer, hacsak nincs egy másik processzkezelő, ami a supervisord-t is indította, aminek nem sok értelme lenne. Az előtérben futtatáshoz még a "nodaemon" paraméterre is szükségünk lesz vagy a konfigurációs fájlban, vagy parancssorban átadva.

Supervisor Dockerfile

[Tartalom]

Az image-et a "httpd:2.4"-es image-re építjük

FROM httpd:2.4

A korábban említett python modulok mellett a a "procps" APT csomagot is telepítem, hogy szükség esetén listázhassam a konténerben a processzeket. A telepítés után pedig kitakarítom a felesleges fájlokat

RUN DEBIAN_FRONTEND=noninteractive \
 && apt-get update \
 && apt-get install --no-install-recommends -y \
      python3 \
      python3-pip \
      python3-setuptools \
      procps \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/* \
 && rm -rf /usr/share/doc \
 && rm -rf /usr/share/man

Ezután telepítem a supervisor 4.2.2-t a pip csomagkezelővel

RUN pip3 install supervisor==4.2.2

Felmásolom az etc és a bin mappát is a konténerbe a konfigurációs fájlokkal és indító szkriptekkel

COPY etc /etc/supervisor
COPY bin /usr/local/bin

Ezután pedig sorban adok futtatási jogot a szkriptekre, generálok egy alap konfigurációs fájlt a beépített echo_supervisord_conf paranccsal, majd hozzáadom az egyedi konfigurációs fájljaimat betöltő "include" szekciót. A supervisord.conf fájlhoz képest relatívan nézve a conf.d mappában minden "ini" kiterjesztésű fájlt is be fog tölteni a supervisor.

RUN chmod +x /usr/local/bin/*.sh \
 && echo_supervisord_conf > /etc/supervisor/supervisord.conf \
 && echo "[include]" >> /etc/supervisor/supervisord.conf \
 && echo "files = conf.d/*.ini" >> /etc/supervisor/supervisord.conf

Szükségünk lesz a stop signal beállítására is, mivel a HTTPD eredeti signalja a WINCH, a supervisord viszont nem azt igényli.

STOPSIGNAL SIGTERM

Végül pedig megadható a konténer indulásakor lefutó supervisord parancs a már említett --nodaemon paraméterrel és a konfigurációs fájl elérésével.

CMD ["supervisord", "--nodaemon", "-c", "/etc/supervisor/supervisord.conf"]

A Dockerfile egyben pedig?

FROM httpd:2.4

RUN DEBIAN_FRONTEND=noninteractive \
 && apt-get update \
 && apt-get install --no-install-recommends -y \
   python3 \
   python3-pip \
   python3-setuptools \
   procps \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/* \
 && rm -rf /usr/share/doc \
 && rm -rf /usr/share/man

RUN pip3 install supervisor==4.2.2

COPY etc /etc/supervisor
COPY bin /usr/local/bin

RUN chmod +x /usr/local/bin/*.sh \
 && echo_supervisord_conf > /etc/supervisor/supervisord.conf \
 && echo "[include]" >> /etc/supervisor/supervisord.conf \
 && echo "files = conf.d/*.ini" >> /etc/supervisor/supervisord.conf

STOPSIGNAL SIGTERM

CMD ["supervisord", "--nodaemon", "-c", "/etc/supervisor/supervisord.conf"]

HTTPD szerver konfigurálása

[Tartalom]

Létrehozzuk a megfelelő mappastruktúrát, ami az etc/conf.d és a bin mappát jelenti. Bash-ben ez egy paranccsal létrehozható:

mkdir -p {etc/conf.d,bin}

Az etc/conf.d/httpd.ini fájl tartalma a [program:PROGRAMNEVE] sorral kezdődik, majd jönnek a paraméterek:

[program:httpd]
command=/usr/local/bin/%(program_name)s.sh
stopsignal=WINCH
stopwaitsecs=10

A "command" paraméterben adható meg értelemszerűen, hogy mivel indítsa a programot a Supervisor. Itt viszont használhatjuk akár a "%(program_name)s" változót is, aminek a helyére ebben az esetben a "httpd" kerül, tehát egy "httpd.sh" nevű indító szkript fog kelleni később.

A "stopsignal" már ismerős lehet a Dockerfile-ból, itt viszont a supervisor-nak mondjuk meg, hogy a "httpd" program milyen signalra áll le szabályosan. Ebben az esetben nem kell kiírni a "SIG" prefixet.

A "stopwaitsecs" pedig megfelel a "docker run" parancsnak megadható --stop-timeout paraméternek. Hasonlóan a szabályos leállításra hagyott másodpercek számát kell megadni

Az indító szkript a bin/httpd.sh fájlban egy az egyben az, amit a korábbi cikkben írt "start-exec.sh"-ban is használtam, tehát egy egyszerű index.html generálása után a httpd szerver indítása az előtérben. Itt is fontos tehát, hogy a Supervisor és az előtérben futtatva kapja meg a programokat, ami ettől függetlenül a mi számunkra a háttérben fog futni.

#!/bin/bash

echo "HELLO" > "/usr/local/apache2/htdocs/index.html"
exec httpd -D FOREGROUND

Python HTTP szerver konfigurálása

[Tartalom]

A python HTTPD szerver konfigurációs fájlja már csak a command paramétert fogja tartalmazni és az etc/conf.d/pythonserver.ini útvonalon lesz a helye

[program:pythonserver]
command=/usr/local/bin/%(program_name)s.sh

A bin/pythonserver.sh fájlban pedig az alábbi szkript segítségével a "/var/www" mappában generálok egy index fájlt a Python szervernek, amit a 8080-as porton indítok.

#!/bin/bash

mkdir -p /var/www

echo "Hello Python server" > /var/www/index.html
python3 -u -m http.server --directory /var/www 8080

Ami feltűnhet, hogy használom a python3 paramétereként a -u paramétert, ami nélkül sajnos semmilyen kimenete nem volt a supervisor mögött a Python szervernek. Itt azért megjegyezném, hogy ez a szerver nem is éles használatra való és ezen kívül más problémák is adódhatnak. Nekem például csak a konténer újraindításával sikerült a Python szervert újraindítani, a supervisorctl segítségével - amiről később lesz szó - nem.

Image build és konténer indítás

[Tartalom]

Ezek után készen állunk az image elkészítésére:

docker build -t localhost/supervisor .

Majd pedig a konténer indításár:

docker run -d --name supervisor -p 1080:80 -p 8080:8080 localhost/supervisor

A HTTPD szerver tehát kívülről az 1080-as porton érhető majd el, míg a Python HTTP szerver a 8080-ason. Érdemes megnézni mindegyik oldalt néhányszor, hogy a logokban is megjelenjen tartalom. Itt ugyanis fájlokba kerülnek a logok, csak a Supervisord saját logjai kerülnek a standard outputra. Egy éles helyzetben érdemes a logokat olyan mappába tenni, ami aztán kihelyezhető volume-ra. Most pedig

Supervisorctl használata

[Tartalom]

A supervisorctl a kliens, amivel többek között a logokat is le lehet kérdezni, de akár a szervereket is újra lehet indítani. Először is be kell lépni a konténerbe

docker exec -it supervisor bash

Az alábbi parancsokat érdemes kipróbálni:

Elérhető programok és állapotuk lekérdezése:

supervisorctl status

Logok lekérdezése (csak stdout):

supervisorctl tail httpd
supervisorctl tail pythonserver

Processz leállítása, indítása, újraindítása

supervisorctl stop httpd
supervisorctl start httpd
supervisorctl restart httpd

Végül pedig a konténer leállítása következik. 10 másodperces timeout érvényes mindenhol, tehát ennél előbb nem áll le a konténer, akkor a signalok nem jól működnek. Ezt könnyen lehet tesztelni az alábbi paranccsal

time docker stop supervisor

A kimenetnek pedig valami hasonlónak kell lennie:

supervisor

real    0m2.751s
user    0m0.015s
sys     0m0.027s

Végszó

[Tartalom]

Ebben a bemutatóban a legalapabb konfigurációt alkalmaztam, tehát ezen még bőven lehet mit optimalizálni. Ha valaki szeretné látni a teljes konfigurációs fájlt, amit az echo_supervisord_conf is generált, a GitHub-ról letölthető: sample.conf

Az egyes paraméterek mellett rövid magyarázat is van, Docker konténerben pedig bátran lehet játszani a paraméterekkel. A supervisor egy egyszerű processzkezelő, ezért nem is kell tőle sokat várni, ha viszont mindenképpen szükséges a konténerben több programot is futtatni, akkor egy jó választás lehet.

Kategóriák: 
Megosztás/Mentés