Bevezetés
A Compose segítségével létrehozhatunk egy YAML fájlt a szolgáltatások definiálásához, és egyetlen paranccsal mindent elindíthatunk vagy leállíthatunk. A YAML fájlok az emberi szem számára könnyen olvasható módon tárolnak adatokat. Leginkább beállítási (config) fájlok létrehozásához szokták ezeket használni, ahol egy alkalmazás vagy rendszer beállításait lehet megadni kulcs-érték párok segítségével, azonban ez annyiban különbözik egy JSON fájltól, hogy az intendálásnak vagy tabulálásnak is van jelentősége a fájl értelmezése során. (Ha valakit ennél pontosabban is érdekel, mi is a YAML, miért használjuk, hol használjuk, annak érdemes megtekinteni a linkelt Wikipedia weboldalt.)
A Compose használatának nagy előnye, hogy egy fájlban definiálhatod az alkalmazás- vagy szolgáltatáshalmazt, a projekt repójának gyökerében tarthatod (ez már "verziókezelt" – verziókkal ellátott), és könnyen lehetővé teheted, hogy más is hozzájáruljon a projektedhez vagy együttműködjön veled. Valakinek csak klónoznia kell a repódat és elindítani a Compose alkalmazást. Valójában a GitHub/GitLab-on jó néhány projektet találhatsz, amely most pontosan ezt csinálja.
Kezdjük el vele mi is a munkát!
Telepítsük a Docker Compose eszközt!
Az a jó hírem van, hogy ha telepítettük a Docker Desktop-ot, akkor azzal együtt már települt is a Docker Compose eszköz is. Egyéb esetekben így kell telepíteni: https://docs.docker.com/compose/install/
Multi-container alkalmazás elkészítése
Az alkalmazás, mint szolgáltatás definiálása
Kezdjük azzal, hogy leállítjuk a futó konténerjeinket és akár törölhetjük is őket.
Ezután következhet a YAML fájl létrehozása a VSCode-ban. A projektünk gyökerében hozzuk létre ezt a fájlt: docker-compose.yml
1. lépés
Legelőször helyezzük el benne ezt a szöveget:
services:
Ezt a fájlt fogjuk építgetni, bővíteni a demó során. Ismétlem a korábbi megjegyzésemet: a YAML fájlokban fontos szerepe van a tabulálásnak vagy intendálásnak (hasonlóan a Python nyelvhez), úgyhogy erre figyeljünk a szerkesztés során. Én itt a bővítő lépések során mindig kiemelem, hogy melyik sorokat adtam hozzá újonnan, frissen.
2. lépés
Ha emlékszünk arra, hogy hogyan indítottuk el a todo alkalmazást futtató konténert, ami csatlakozott a mysql szerverhez (környezeti változók értékeinek megadásával paraméterezett script), akkor az egy jó kiindulási alap a compose fájl összerakásához. (Megjegyzés: az újonnan hozzáadott sorokat külön kiemelem.)
services:
app:
image: node:18-alpine
Először definiáljuk a szolgáltatás belépési pontját, amelyben meghatározom a konténer image-ét. A szolgáltatásnak bármilyen nevet adhatnánk és az automatikusan egy hálózati alias névvé is válik, amely hasznos lehet majd a MySQL szolgáltatásunk számára.
3. lépés
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
Tipikusan egy shell script paranccsal zárjuk le az image-hez tartozó definíciós részt, habár nincsen elvárás a sorrendben (ez általában csak a megszokás szokott lenni).
4. lépés
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
A korábbi létrehozó parancsban (docker run ...) a "-p 3000:3000" részt így kell definiálni a compose fájlban: így definiáljuk a portokat a szolgáltatás számára. Mi a rövid szintaxist használtuk, de ha valaki hosszabban, vagy jobban paraméterezve szeretné használni a portokat, akkor itt van egy leírás hozzá, hogy hogyan kell ezt megtenni: https://docs.docker.com/compose/compose-file/#long-syntax-2
5. lépés
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
Következik a migrálása két dolognak: a munkakönyvtárnak (working directory) és a forráskódunkat tartalmazó kötegnek (volume). Mi a volume-nak is a rövid szintaxisát használtuk, de van neki egy hosszabb, jobban paraméterezhető is: https://docs.docker.com/compose/compose-file/#long-syntax-4
6. lépés
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
Végül hozzáadtuk a környezeti változókat, amivel az alkalmazás kapcsolódni tud majd a MySQL szerver todos adatbázisához. Az alkalmazással így végeztünk is, most rátérünk a MySQL szolgáltatás definiálására.
A MySQL szolgáltatás definiálása
A MySQL szolgáltatás definiálását tabulálás (intendálás) szempontjából ott kell elkezdeni, ahol az app szolgáltatásét elkezdtük.
1. lépés
services:
app:
# az alkalmazáshoz tartozó részek, itt nem írom le őket újra
mysql:
image: mysql:8.0
Itt is az image meghatározásával kezdünk. Bennhagytam a struktúrát, hogy hogyan kell folytatni a mysql szolgáltatás definiálását, de a további lépésekben már csak az "app"-on kívüli (utáni) részekkel fogok foglalkozni. Az app-on belüli sornál a # a megjegyzés jelölése.
2. lépés
services:
app:
# az alkalmazáshoz tartozó részek, itt nem írom le őket újra
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
Amikor a docker run paranccsal indítottuk a konténerünket, akkor automatikusan létrejött hozzá a "named volume", itt a compose esetében viszont ez nincs így, úgyhogy magunknak kell definiálnunk.
3. lépés
services:
app:
# az alkalmazáshoz tartozó részek, itt nem írom le őket újra
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
volumes:
todo-mysql-data:
A szolgáltatásokkal (services) egy "behúzási oszlopban" pedig definiálnunk kell a compose-ban, hogy a mysql szolgáltatás "named volume" mezőjét használja majd a csomag "mountpoint"-ként, mint fő szolgáltatás beállításaként. Itt már elég csak mysql szolgáltatás volume nevére hivatkozni (todo-mysql-data).
4. lépés
Végül adjuk hozzá a környezeti változókat a mysql szolgáltatáshoz:
services:
app:
# az alkalmazáshoz tartozó részek, itt nem írom le őket újra
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
Ezzel elkészült a Docker Compose eszköznek átadható docker-compose.yml fájlunk. Itt a végső, teljes verziója:
A függőleges, halvány segédvonalak a VSCode-ban jól jelzik, hogy mi mivel van egy szinten tabulálás szempontjából. Két szolgáltatásunk van, az app és a mysql, nekik vannak a paramétereik és magának a csomagnak a volumes része pedig hozzá van kötve a mysql volumes részéhez.
Futtathatjuk az alkalmazás csomagot!
Ismét győződjünk meg róla, hogy nincs olyan konténer, ami ezekhez kapcsolódóan futna, mert nincs rá szükségünk. Megtehetjük ezt a Docker Desktop vezérlőpultján is, vagy egy kilistázás után (docker ps) a docker rm -f <container-id> parancs alkalmazásával.
Ezután indíthatjuk a csomagunkat a terminálunk segítségével.
docker compose up -d
A -d kapcsoló csak arra szolgál, hogy a háttérben történjen meg az indítás és a futtatás.
Mindössze néhány pillanat alatt meg is történt a létrehozás és elindítás. A Docker Compose automatikusan létrehozott egy hálózatot (network) speciálisan ennek az alkalmazás/szolgáltatás csomagnak. Emiatt nem is kellett nekünk ezzel külön foglalkoznunk, amikor az alkalmazás csomagot definiáltuk a docker-compose.yml fájlban.
Ha most meg szeretnénk nézni az alkalmazás csomagunk naplózását, akkor így tehetjük meg a terminálban:
docker compose logs -f
Az eredmény (részleten) látható, hogy minden egyes szolgáltatásnak vannak naplózott jelzései, amelyeket a sor elején jelez nekünk, hogy éppen melyiknél mi történt. (CTRL+C -vel kiléphetünk a naplózás nyomon követéséből.) Ha csak az egyik szolgáltatást akarjuk figyelni, akkor azt is megtehetjük, például így az "app"-ot tudjuk figyelni:
docker compose logs -f app
Ekkor a naplózás kvázi szűrve jelenik meg és csak az app szolgáltatáshoz kapcsolódó részeket fogjuk látni.
A böngészőben a localhost:3000 webcímen ismét hozzá tudok adni az adatbázishoz feladatokat.
A Docker Desktop vezérlőpultjában pedig már látszódik is a konténereknél a csomag (app), és ha lenyitjuk a kis háromszöggel előtte, akkor a részei is:
Alapértelmezetten lett "app" a csomag neve, mivel a mappa, ahol van a docker-compose.yml fájl az "app" (C:\xampp\htdocs\app nálam) mappában helyezkedik el (emiatt ez picit összezavarhat minket, de ne engedjük becsapni magunkat). Az "app-1" nevet kapta a webes alkalmazás, míg "mysql-1" nevet az adatbázis szolgáltatás. Ezek a nevek is automatikusan generálódtak, mivel az app csomagban helyezkednek el, ezért itt már csak a szolgáltatás neve és a másolat (replica) száma szerepel. De ha a "hosszú" nevükön kellene őket szólítani, akkor ez lenne: app-app-1 és app-mysql-1
Ha végeztünk a teszteléssel, akkor le is állíthatjuk az alkalmazást egy paranccsal a terminálban:
docker compose down
Vagy a Docker Desktop vezérlőpultjában az app csomag sorában lévő stop gombbal mindkét belső szolgáltatás futtatása leállításra kerül, továbbá a hálózata (network) is eltávolításra kerül. Viszont bármikor újraindíthatjuk itt a play gombbal, vagy akár egy paranccsal:
docker compose up
Az adataink pedig szépen megmaradnak az adatbázisunkban újraindítás után is.
Befejezés és továbblépés
Ezen a ponton elkezdjük zárni a Docker-es sorozatunkat, viszont megnézünk a következő bejegyzésben még néhány "best practice"-t, legjobb gyakorlatot, tanácsokat, szabályokat, amelyeket érdemes betartani a Docker világában, mert most még a Dockerfile-unk nem annyira megfelelő, vagy legalábbis, nem nevezhető optimálisnak… utána pedig következhetnek majd a felhőben való Docker futtatása és a Laravel projektjeink virtualizálása, "Docker-alapúvá" tétele.
Kövessetek a Facebook-on,
és ha tetszik a munkám, akkor támogassátok néhány euróval a blog és az
oldal fennmaradását a "buymeacoffee" (kávé) ikon útmutatásait követve.