Eddig már két alkalommal is a Docker előnyeiről írtam, de ebben a cikkben a gyakorlatibb oldaláról közelítem meg a témát. Dockerrel elindítani egy már eleve arra készített programot gyerekjáték és így öröm dolgozni. Ezt lehet bonyolítani, de egyelőre bőven elég lesz a vidámabb része. Ehhez azért pár fogalmat tisztázni kell, mert bár a gyerek kreatívan eljátszik bármivel, a Docker esetén jobb, ha tudod, mi, mire való. Mindeközben használhatod a teszteléshez a Play with Docker szolgáltatást, hogy telepíteni se kelljen semmit. És ami a legszebb, legegyszerűbb esetben ennyi egy program indítása: docker run hello-world
Amit tudni kell
Ez inkább csak emlékeztető, hiszen korábban is szó volt róluk.
- Konténer
- Az a minimális virtuális környezet, amiben a programot futtatod. Ezért a Linux kernel felel. Lásd a korábbi cikkben.
- image
- Ez az a csomag, ami tartalmazza a konténer Read-Only fájlrendszerét, tehát a futtatandó programot és annak minden függőségét. Egy sablon, amiből a konténer elindítható.
- Docker Registry
- Ez egy adatbázis, ami tárolja az image-eket. A hub.docker.com az alapértelmezett és nyilvános. Sajátot is lehet telepíteni, de az majd egy későbbi téma lesz.
Teszt környezet
Play With Docker
(Ajánlott)
A címben szereplő szolgáltatással egyelőre nincs szükség telepítésre. Igaz, hogy egy még nem stabil, RC verzió érhető el rajta a Dockerből, de ez a tesztelésnél nem fog zavarni.
- Kattints a Play with Docker linkre
- Kattints a "Nem vagyok robot" jelölőnégyzetbe
- Megjelent a visszaszámláló 4 órától, ami alatt lesz egy "ADD NEW INSTANCE" link. Kattints rá és elindul egy tesztkörnyezet. Ha valamiért gyanúsan nem jelenne meg a terminálban semmi, üss egy entert, attól nálam magához tért.
Telepítés
Ha mindenképp saját szerverre szeretnéd telepíteni a Docker Engine-t, szerintem egy kifogástalan leírása van a hivatalos dokumentációban: Install Docker, ami viszont operációs rendszertől függően más. Azt tudni kell, hogy a Docker EE az enterprise verzió és fizetős. A Docker CE (Community Edition) ingyen használható, de több dolgot kell magadnak megoldani vele.
Egyszerű "Hello world" példa
Legprimitívebb példa az a hello-world image, ami nem csinál semmit azon kívül, hogy kiírja, köszöni szépen, elindult és pontokba szedve közli, ezt milyen módon tette.
docker run hello-world
Hogy mi történt?
- Valaki elkészített egy image-et, amit megtaláltál. Felismerted, hogy ez kell neked és el akarod indítani.
- A "run" utasítás miatt a Docker Engine megnézte, hogy elérhető-e már a választott image letöltve.
- Ha még nem volt letöltve, akkor a Docker Engine most letöltötte.
- A Docker Engine létrehozott egy konténert, ami már tartalmazta mindazt, ami az image-ben benne volt.
- És természetesen, még mindig a Docker Engine ebben a konténerben elindította azt a programot, amit az image készítője futtatandónak jelölt.
- A program ebben a jó kis "magánzárkában" elvégezte a dolgát, mit sem tudva a gépről, amin valójában fut.
- Mivel a program csak kiírt valamit a képernyőre, majd be is fejezte a futását, a konténer is leállt, de továbbra is megmaradt, hogy újból el lehessen indítani.
A run utasítás tehát több feladatot is elvégez, ám ezek külön parancsokkal is megoldhatók, de arra ritkán van szükség. Most tehát képzeld el, hogy te magad is tudsz egy ilyen image-et készíteni és a macerás telepítési folyamat (felmásolás, jogosultságok beállítása, még ha szkriptekkel is) egyetlen parancs futtatására redukálódott, aminek következtében még egy chroot jail-t is kaptál ajándékba.
Kicsit közelebbről
Image-ek szerkezete
Ha figyeltél, miközben elindult a világ köszöntése, feltűnhetett az első két sor:
Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world
Valójában A hello-world csak egy amolyan beceneve volt az index.docker.io/library/hello-world:latest image-nek. Ebből az index.docker.io a szerver címe, ahonnan letöltődik az image. A library az alapértelmezett névtér, ami a hivatalos image-eket jelöli. Ha regisztrálsz a Docker Hub-ra és feltöltesz egy saját image-et, a saját felhasználóneved lesz a névtér. A "library" viszont elhagyható, ahogy a szerver címe is, ami még portszámot is tartalmazhatna. Végül pedig a "latest" a verziót jelzi. Ez szintén elhagyható. Így tehát egy image valódi, teljes neve az alábbi szerint alakul:
myregistry.mydomain.tld:5000/namespace/image:version
Meg is lehet nézni a letöltött image-eket: docker images
Előtérben vagy háttérben (daemon) futás
Ezzel a példával csak elindult a hello-world alkalmazás egy konténerben. Az viszont amint kiírta a képernyőre, amit akart, be is fejezte a futását. A konténer ettől még továbbra is létezik, de mielőtt megmutatom, ismét egy kis mesedélután.
Egy konténer indítható az előtérben, de a háttérben is. Első esetben látod, mi történik a konténerben. Minden, ami a terminálban kiírásra kerül, az megjelenik. A háttérben futtatott konténer indítása után viszont visszakapod a promptot a hoszt rendszer termináljában. Konténer nélkül egy háttérben futtatás valahogy így működhetne:
nohup program &
Ekkor minden, a program által kiírt üzenet a nohup.out nevű fájlba kerül. Ki lehet próbálni konténerrel is:
cat nohup.out
Ez a megoldás hasonló a Docker "detached" (-d) módjához. A kimenet ilyenkor egy json fájlba kerül alapértelmezetten, amibe a docker logs
utasítással lehet belenézni. Az "attached" (-a) módban viszont minden megjelenik a képernyőn, amíg a konténer le nem áll. Ez a run alapértelmezett módja.
docker run rimelek/phar-examples
A fenti utasítással el is indult egy teszt php program a beépített webszerverével, de nem adja vissza a terminált a CTRL+C billentyűkombinációig. Most nyomd is meg és futtasd az alábbi sort is:
docker run -d rimelek/phar-examples
Ki fog írni valami hasonlót, miközben a háttérben elindul a program:
9e42d66fb03f880d9bb527fcba23aa58f5110aa4b4bd19699b761d10a7a8204e
Ez az elindult konténer azonosítója. Persze, hiszem, ha látom, hiszen semmi bizonyíték nincs rá, hogy elindult, igaz? Ahogy a korábbi cikkekben utaltam rá, még a böngészőből sem érhető el egy webszerver, amíg nem nyitom meg rajta a megfelelő portokat.
Most a következő sorral listázhatod az összes futó konténert: docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9e42d66fb03f rimelek/phar-examples "php -d phar.reado..." 17 seconds ago Up 16 seconds 80/tcp unruffled_leakey
Igen, itt ugyan látszik port is, de ez csak a konténeren belül létezik, a külvilág felé nem. A másik, ami feltűnhet, hogy sehol a hello-world, pedig azt mondtam, hogy nem tűnt el az sem. El nem tűnt, de már nem fut, ezért a következő utasítással listázhatod a leállt konténereket is: docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9e42d66fb03f rimelek/phar-examples "php -d phar.reado..." 4 minutes ago Up 4 minutes 80/tcp unruffled_leakey 1e9c0c36ebe8 rimelek/phar-examples "php -d phar.reado..." 5 minutes ago Exited (0) 4 minutes ago competent_blackwell 27818c2ca670 hello-world "/hello" 5 minutes ago Exited (0) 5 minutes ago peaceful_kowalevski
A futó konténerek mellett az "Up" szó áll. A leállítottak mellett az "Exited" szerepel hibakóddal, ha van. Ezeket viszont el lehet indítani újra a start-tal, ami után a konténer fantázianevét kell írni.
FONTOS: A következő utasításoknál figyelj rá, hogy nálad mások lesznek a konténerek nevei!
docker start competent_blackwell
# hello world elindítása
docker start peaceful_kowalevski
# konténerek listája
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9e42d66fb03f rimelek/phar-examples "php -d phar.reado..." 9 minutes ago Up 9 minutes 80/tcp unruffled_leakey 1e9c0c36ebe8 rimelek/phar-examples "php -d phar.reado..." 9 minutes ago Up 17 seconds 80/tcp competent_blackwell 27818c2ca670 hello-world "/hello" 10 minutes ago Exited (0) 3 seconds ago peaceful_kowalevski
A hello-world konténer ismét leállt, de ez rendben is van. Viszont nem is írt ki semmit, pedig az lett volna a lényege. Ehhez csatlakozni kell a konténerhez az alábbi módon, mert a start a run-nal ellentétben a háttérben indít mindent:
docker start -a peaceful_kowalevski
Egyedi nevek
Nem csak fantázianevekkel lehet dolgozni természetesen. Az alábbi módon nevet is lehet rendelni a köszöntéshez:
docker rename peaceful_kowalevski hello-2
Erre megjelent a hello-1 nevű konténer is, a peaceful_kowalevski nevű pedig hello-2 -re lett átnevezve
Elérés böngészőből
Legyen valami látványosabb is. Ideje böngészőben is elérni a webszervert. Ahhoz meg kell adni a konténer létrehozásakor, hogy melyik porton szeretném a hoszton elérhetővé tenni a konténer 80-as portját:
docker run -d -p 8080:80 --name pharex-1 rimelek/phar-examples
A "-d" miatt a háttérben indul, a "-p" miatt pedig a 8080-as porton lesz elérhető a hoszton, ami a konténerben a 80-as porton fut. A Play with Docker-nél, mivel virtuális IP címek vannak, megjelenik egy link a választott portszámmal az oldal tetején. Arra kattintva látható a webszerver kezdőoldala egy generált webcímen.
(A generált webcím alulvonás karaktereket tartalmaz, ami nem érvényes a webcímekben.
Ennek ellenére az nginx és a PHP built-in szerver megbirkózik vele. A HTTPD viszont nem. Saját szerveren lehet azzal is próbálkozni.)
Takarítás
Ideje kitakarítani. Jelenleg 3 konténer van. A leállt hello-world konténer letörölhető egyszerűen:
docker rm hello-1 hello-2
A futó konténereket viszont előbb le kell állítani:
docker rm unruffled_leakey competent_blackwell
Ezt a két parancsot röviden így is lehet írni:
docker rm -f unruffled_leakey competent_blackwell
Időnként az image-eket sem árt törölni. Erre az "rmi" utasítás való:
docker rmi rimelek/phar-examples
Összefoglalás
Már az ebben a cikkben megismert parancsok is nagyon hasznosak, de persze jóval több is van, amiket a docker help
ki is listáz. Egy konkrét utasításról pedig, mint az rmi, a docker help rmi
sorral lehet többet megtudni.
Ráadásul a Docker rohamosan fejlődik, így érdemes is figyelni a változásokat. A fent használt ps, images, rmi és rm utasítások is egységesítve lettek. Az alábbi táblázat mutatja az eredeti, és az egységesített verziókat:
Funkció | Eredeti | Egységesített |
---|---|---|
Image-ek listája | docker images |
docker image list |
Konténerek listája | docker ps |
docker container list |
Konténer törlése | docker rm <containername> |
docker container rm <containername> |
Image törlése | docker rmi <imagename> |
docker image rm <imagename> |
Ennek a cikknek a célja egy valódi, de egyszerű példa lépésről lépésre bemutatása volt. Ha úgy érzed, még mindig nem tudsz mindent, ne aggódj. Ez még sokáig így is lesz, de apránként, ha gyakorolsz, egyre inkább látni fogod, hogyan segíthetik a te munkádat is a konténerek. Hamarosan jövök a saját PHP és HTTPD image-ek bemutatáásval, de az image készítése sem maradhat el természetesen.