Docker - 5. rész: Együttműködő konténerek Docker Compose használatával

Attila | 2023. 01. 04. 15:44 | Olvasási idő: 4 perc

Címkék: #Container #Docker #git #Image #Virtualizáció (Virtualization) #Volume

Továbbra is az együttműködő konténerek létrehozására koncentrálhatunk. Használjuk ehhez a Docker Compose-t! Ez egy olyan eszköz, amely segít nekünk a fejlesztés során abban, hogy több konténert (multi-container) együttesen létrehozzunk és kezeljünk.
docker-compose

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.