HTTPD virtuális hosztok Docker konténerben

Internet kép a pixabay.com-ról TheDigitalArtist felhasználótól.

Mutattam már az LXC konténereket, amik nagyon jól használhatók virtuális gépek helyett, de nem ez ami folyamatosan és elkerülhetetlenül szembejön ma már nem csak GitHub-on, de szakmai társalgásokban is. Sokkal inkább a Docker. Nem újdonság már, az I.T. szigeten is több oldalnyi cikket találhatsz a témáról. Ha még mindig nem vetted rá magad, hogy megtanuld, akkor itt a remek alkalom. Talán már megpróbálkoztál vele, de bonyolultnak érezted, nem működött. Könnyebb lehet először a hagyományoshoz hasonló módon elindítani egy programot a konténerben, majd haladni egyre konténerbarátabb megoldások felé, ám ezzel egyre inkább eltávolodni a korábban megszokottól. Ebben a cikkben és a mellékelt videóban azt mutatom be, hogyan konfigurálnánk egy Apache HTTPD webszervert több weboldalhoz konténerben futtatva, mégis egy még ismerősebb megoldással, virtuális hosztokkal.

A telepítést az alábbi videón is követheted

Tartalomjegyzék

Mikor LXD, mikor Docker?

[Tartalom]

Fontos tudni, hogy a Docker nem arra való, mint az LXC/LXD. Az LXD nagyon jó arra, hogy a virtuális gépek alternatívájaként használjuk Linuxon (operációs rendszer konténer) vagy akár virtuális gépeket indítsunk vele, bár utóbbira kicsit komolyabb esetben valószínűleg nem ez lesz az első gondolatunk. De nem arra való, hogy becsomagoljuk az alkalmazásokat és terjesszük, illetve nem is arra, hogy az alkalmazásaink komponenseit elkülönítsük és függetlenítsük egymástól, pláne nem arra, hogy ugyanazt több példányban futtassuk. A Docker erre kiváló, hiszen kizárólag egy adott alkalmazás kerül bele (alkalmazás konténer), de persze vannak olyan programok, amik nehezebben implementálhatók Docker konténerekben, mert például más, adott disztribúción futó service-től függnek. Ilyenek például, amik a systemd-re épülnek, de más ok is lehet. Sok esetben egyszerűen csak arról van szó, hogy a szoftvert kellene módosítani, hogy megfeleljen az új, modern irányelveknek. Akár grafikus felületű, asztali alkalmazásokat is lehet futtatni Docker konténerben, de ez megint olyan, amire valószínűleg vannak jobb megoldások. Ha viszont a cél valamilyen parancssori alkalmazás, háttérben futó szolgáltatás indítása, ráadásul fontos a skálázhatóság, akkor sokkal inkább a Docker, vagy annak mindenkori megfelelője, alternatívája, amire szükséged van.

LXD-vel például valószínűleg vagy manuálisan telepítenél webszervert, vagy például az Ansible és ahhoz hasonló megoldások segítségével, virtuális hosztok beállításával, Dockernél viszont többnyire forráskódból történik a programok telepítése tetszőleges, fix verziót build-elve, a virtuális hosztok helyett pedig minden weblap külön konténerben fut és egy külön proxy segítségével történik a weblapok domain alapján elérése. Ehhez viszont már olyan akadályokon kell átküzdened magad, ami egyelőre meg sem fordult a fejedben, tehát kezdjük az elején a legfontosabbakkal és használjuk ki a konténerek adta izoláció előnyeit, miközben a korábban bevált konfigurációval kis haladékot kapunk a Docker mélyebb megismerésére, megértésére.

[Tartalom]

Továbbra is kell egy szerver, ahonnan letölthetjük az image-eket (konténerek sablonjai) és kereshetünk köztük. Ezeket hívjuk a Docker esetén "registry"-nek, de jellemzően nem parancssorban keresünk, hanem webes felületen, hiszen jóval több információ kell a választáshoz, mint LXD esetén kellett. Az alapértelmezett Docker registry pedig a Docker Hub, aminek a webes felületét a hub.docker.com címen lehet elérni, bár az évek során már több más neve is volt (Docker Store, Docker Cloud), de csak visszatért a kezdetektől végig működő gyökerekhez.

Docker Hub kereső mező

A kereső mezőben a "httpd" -re keresve az első találat nagy valószínűséggel a hivatalos httpd image.

Első két találat a httpd szóra keresve a Docker Hub-on

A "httpd"-re kattintva pedig annak bővebb leírását is meg lehet találni néhány használati utasítással, de amit elsőként megnézünk, az a használható tag-ek listája, amik többnyire verziószámokat tartalmaznak, vagy olyan speciális kifejezéseket, mint a "latest", ami mindig a legfrissebb verzióra mutat. Ez viszont nem garantált, hogy stabil verzió, ráadásul akaratlanul is lefrissülhetne egy alkalmazás olyan verzióra, ami visszaállíthatatlan hibát is okozhatna az alkalmazás adataiban. Érdemes ezt tehát elkerülni és pontos verziót választani. Én most a "2.4"-et választom, mert a hibajavítások letöltődhetnek, de volt már példa arra is, hogy az alapértelmezett konfigurációkban történt változás, ami sokaknak rontotta el az élesben működő programját, akik nem futtattak frissítés előtt megfelelő teszteket, mint akkoriban én sem.

Tag-ek listája

Webszerver indítása

[Tartalom]

A következő paranccsal elindítható az Apache HTTPD webszerver.

docker run --name httpd-vhosts -d httpd:2.4

A --name paraméter után a konténer nevét kell írni, míg a -d önmagban felelős azért, hogy a konténer a háttérben induljon el. Én régen mindig úgy jegyeztem meg a rövidítést, hogy démonként fut, de valójában a "--detach" rövid írásmódja, csak ezt ugye ezen a ponton még nem kell tudni, mit jelent.

Egyedi konfiguráció

[Tartalom]

Már így is lehetne használni a konténert, ha tudnánk az IP címét, amit meg lehet tudni a "docker inspect httpd-vhosts parancsot futtatva, csak ugye a webszerver nem sokat ér tartalom nélkül, tehát jöhet a konfiguráció. Azt viszont nem kell a nulláról elkészíteni. A image-ben és így a "httpd-vhosts" konténerben minden benne van, csak ki kell másolni. Az alábbi parancsokat egy üres projektmappában futtasd. Én ezt is "httpd-vhosts"-nak neveztem el.

docker cp httpd-vhosts:/usr/local/apache2/conf/httpd.conf .
docker cp httpd-vhosts:/usr/local/apache2/conf/extra/httpd-vhosts.conf .

A docker cp után a konténer neve jön, majd kettőspontot követően a konténerben levő fájl útvonala. Végül pedig a cél útvonala, ahova a fájlt ki kell menteni. Jelen esetben mindkét sor végén fontos a pont, így átnevezés nélkül kimentjük az aktuális mappába. Szükség lesz még a weblapokra, amiket most egy-egy index.html fog reprezentálni. A "httpd-vhosts" nevű projekt könyvtáram tehát a konfigurációs fájlokkal együtt most így néz ki:

  • vhosts
    • blog
      • index.html
    • www
      • index.html
  • httpd.conf
  • httpd-vhosts.conf

A html fájlokba az egyszerűség kedvért csak a mappájuk nevét írtam, ami egyben az aldomain is lesz majd. Most a httpd.conf fájlban az alábbi sort kell megkeresni és kivenni a sor elejéről a kettőskeresztet.

#Include conf/extra/httpd-vhosts.conf

Ezután a httpd-vhosts.conf fájl tartalmát az alábbira kell cserélni:

<VirtualHost *:80>
    ServerAdmin webmaster@127.0.0.1.xip.io
    DocumentRoot "/var/vhosts/blog"
    ServerName blog.127.0.0.1.xip.io
    ServerAlias www.blog.127.0.0.1.xip.io
    ErrorLog "logs/blog-error_log"
    CustomLog "logs/blog-access_log" common

    <Directory "/var/vhosts/blog">
    Require all granted
    </Directory>
</VirtualHost>

<VirtualHost *:80>
    ServerAdmin webmaster@127.0.0.1.xip.io
    DocumentRoot "/var/vhosts/www"
    ServerName 127.0.0.1.xip.io
    ServerAlias www.127.0.0.1.xip.io
    ErrorLog "logs/www-error_log"
    CustomLog "logs/www-access_log" common

    <Directory "/var/vhosts/www">
    Require all granted
    </Directory>
</VirtualHost>

Megfigyelheted, hogy a lényegi különbség gyakorlatilag a DocumentRoot és ServerName módosítása és emiatt a "Directory" blokk használatával a mappákra a hozzáférési jogosultság megadása. Domainként a 127.0.0.1.xip.io-t használtam.

Megjegyzés: Ha WSL gépben futtatod a Dockert, akkor a 127.0.0.1 IP cím csak akkor működik, ha a böngészőt is a WSL gépben futtatod, de ez egy későbbi téma lehet. Addig is a lokális IP címet átírhatod a WSL gép IP címére vagy a WSL gépen belül használhatsz "curl" vagy "wget" parancsot a weboldalak elérésére.

Az xip.io egy publikus névszerver, amivel olyan domainek adhatók meg, amik az IP címet is tartalmazzák a nevükben, így használhatók virtuális hosztok tesztelésére. A ServerAlias opcionális. Gyakran csak a "www" aldomain megadására használva.

Az ezután futtatandó parancs már hosszabb lesz, így érdemes kimenteni egy "run.sh" nevű fájlba, amire futtatási jogot is kell adni:

chmod +x run.sh

A tartalom pedig tehát:

docker run \
  --name "httpd-vhosts" \
  --network host \
  -d \
  -v "$PWD/vhosts:/var/vhosts" \
  -v "$PWD/httpd.conf:/usr/local/apache2/conf/httpd.conf" \
  -v "$PWD/httpd-vhosts.conf:/usr/local/apache2/conf/extra/httpd-vhosts.conf" \
  httpd:2.4

Újdonság --network paraméter host értékkel. Ismét az LXD-re visszautalva ez a net névtér kikapcsolása, tehát a konténer nem kap saját IP címet, így nem is kell azt tudni. A szerver konténerben lesz, mégis minden induló szolgáltatás a hoszt rendszer hálózatán jelenik meg. A másik újdonság a "-v paraméter, ami után kettősponttal elválasztva először a hoszton levő fájl vagy mappa útvonalát kell megadni abszolút módon, majd a konténerben levő útvonalat, ahova fel kell csatolni és ezzel az ott levő mappát, fájlt felülírni, illetve létrehozni, ha eredetileg nem volt.

Futtatás előtt viszont az egyező nevű előző konténert törölni kell:

docker rm -f httpd-vhosts
./run.sh

A futtatása után a virtuális hosztok már élnek a 127.0.0.1.xip.io és blog.127.0.0.1.xip.io címeken, viszont eltűnt az redeti "It works" feliratú weboldal, amit IP címmel akár el is érhetnénk, hiszen a virtuális hosztok a domainekhez kötődnek. Nincs rá szükség persze, de vissza lehet állítani az alábbi sorok beszúrásával a "httpd-vhosts.conf" fájl elejére, így nem a "blog" lesz az alapértelmezett domain, hanem az eredeti demo oldal.

<VirtualHost *:80>
    DocumentRoot "/usr/local/apache2/htdocs"
</VirtualHost>

Mivel viszont a már futó webszerver konfigurációs fájlját módosítva az új konfiguráció nem lesz aktív, amíg újra nem töltjük a konfigurációt, vagy újra nem töltjük a szervert. Mutatom mindkettőt:

Konfiguráció újratöltése:

docker kill -s HUP httpd-vhosts

Ha ez nem működne, akkor újraindítás:

docker restart httpd-vhosts

Bizonyos esetekben előfordulhat, hogy az újraindítás sem segít, ha a fájlszerkesztő úgy módosítja a fájlt, hogy egy másolaton dolgozik, majd cseréli az eredetit a másolatra. Ilyenkor sajnos törölni kell a konténert teljesen és újra lefuttatni a run.sh szkriptet.

Ennyi. Ezek után pedig lehet valami értelmesebb weblapot is betenni az egyszerű index.html-ek helyett. Ez most csak egy statikus weblap példája volt, de a dinamikus weblapokkal is el lehet ezt játszani. A lényeg, hogy a konfigurációs fájlokat soha nem a konténerben módosítjuk, legfeljebb csak ha kipróbálunk valamit. Egyébként kimásoljuk és felcsatoljuk, így a konténer szabadon letörölthető és újra elindítható, mert minden a hoszt operciós rendszer olyan területén van, ami független a konténertől.

Docker Compose használata

[Tartalom]

Oké, tehát a szkript is működött, de érdemes utánanézni a Docker Compose-nak, ami nagyban leegyszerűsíti a dolgunkat, főleg, ha nem csak egy konténert kell indítani, hanem később majd többet is. Ennek a cikknek viszont az a célja, hogy kis lépésekben, a Dockert ismerjük meg, ezért most semmi mást nem csinálunk utolsó lépésként, mint ugyanazt futtatjuk Docker Compose segítségével, amit az előbb a "docker" paranccsal. Ehhez pedig le kell tölteni a Docker Compose-t. A legegyszerűbb vagy a GitHub-ról letölteni a binárist vagy python-nal feltenni a megfelelő verziót. Én utóbbit teszem, ráadásul az úgynevezett "virtuális environment"-ben, Python3 -mal, Ubuntu 20.04-ben.

sudo apt install python3-venv
python3 -m venv httpd-vhosts-env
source httpd-vhosts-env/bin/activate
pip install --upgrade pip
pip install docker-compose==1.28.5

A Docker Compose egy "docker-compose.yml" nevű fájlt keres alapértelmezetten, így egy ilyen nevű fájlba az alábbi tartalmat kell írni:

version: "3.9"

services
:
  httpd
:
    image
: httpd:2.4
    network_mode
: host
    volumes
:
      - type
: bind
        source
: ./vhosts
        target
: /var/vhosts
      - type
: bind
        source
: ./httpd.conf
        target
: /usr/local/apache2/conf/httpd.conf
      - type
: bind
        source
: ./httpd-vhosts.conf
        target
: /usr/local/apache2/conf/extra/httpd-vhosts.conf

Ami különbség, az gyakorlatilag a network_mode, amire a parancsosrban csak --network-ként hivatkoztunk, valamint a fájlok felcsatolásának definíciója, ami kicsit bőbeszédűbb, de ezáltal egyértelműbb. Most először is megint törölni kell az előző konténert, hiszen ugyanazon a porton, a hoszt hálózatán fog elindulni az új szerver is. Törlés után pedig az alábbi paranccsal indul az összes konténer, ami a fájlban definiálva van. Ez persze jelenleg csak egy konténer.

docker-compose up -d

Ha már nincs szükség a konténerre, illetve konténerekre, akkor az alábbi paranccsal törölhető a szerver:

docker-compose down

Végszó

[Tartalom]

El lehet tehát kezdeni egyszerűbben is a Dockert, nem kell rögtön kidobni a korábbi megoldásokat, de érdemes azokkal is folyamatosan ismerkedni. Határozottan kifizetődő. A Docker parancsokat is érdemes ismerni és vannak olyan parancsok, amik túl kevés figyelmet kapnak, mert ritkán van szükség rájuk, vagy csak nem értjük, mire valók. Ezeken is igyekszem segíteni. A Docker Compose pedig párhuzamosan használható, hasznos eszköz még mielőtt igazán komoly feladatokba vágnád a fejszéd.

Nyilván ennél sokkal, sokkal többet tud a Docker és a Docker Compose is és meg is tudhatsz róla többet, amennyiben követed az oldalt Facebookon. YouTube-ra is érdemes feliratkozni, hogy értesülj az új videókról, még ha a Facebook nem is érzi úgy, hogy meg kellene mutatnia az új bejegyzést, ráadásul sokat számít az ingyenes tartalmak gyártása közben az ilyen támogatás is.

Ahogy mindig, várom kérdéseitek, észrevételeitek. Néhány utalást már kaptam is új tartalmi igényre, amik épp megfontolás és beütemezés alatt vannak.

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