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
- Supervisor Dockerfile
- HTTPD szerver konfigurálása
- Python HTTP szerver konfigurálása
- Image build és konténer indítás
- Supervisorctl használata
- Végszó
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:
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:
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
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
&& 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
Felmásolom az etc és a bin mappát is a konténerbe a konfigurációs fájlokkal és indító szkriptekkel
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.
&& 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.
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.
A Dockerfile egyben pedig?
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ó:
Az etc/conf.d/httpd.ini
fájl tartalma a [program:PROGRAMNEVE]
sorral kezdődik, majd jönnek a paraméterek:
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.
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
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.
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:
Majd pedig a konténer indításár:
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
Az alábbi parancsokat érdemes kipróbálni:
Elérhető programok és állapotuk lekérdezése:
Logok lekérdezése (csak stdout):
supervisorctl tail pythonserver
Processz leállítása, indítása, újraindítása
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
A kimenetnek pedig valami hasonlónak kell lennie:
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.