Első lépések a Docker konténerekig

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:

nohup docker run hello-world &
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!

# leállt szerver elindítása
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 run --name hello-1 hello-world
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 stop unruffled_leakey competent_blackwell
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 hello-world
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.

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