Címkék: #Container #Docker #Image #node.js #Virtualizáció (Virtualization)
A Docker Desktop teljeskörű dokumentációja itt érhető el: https://docs.docker.com/desktop/
A docker-tutorial konténer elindítása a Docker Desktop-ban:
Eredmény megtekintése a böngészőben:
A folyamatot végigcsináljuk, hogy megismerjük a Docker működését részleteiben és egy Node.js alapú webes alkalmazás futtatását tudjuk szemléltetni. A Node.js-ről eddig még nem esett szó, de nem kell megijedni, nem azt fogjuk megtanulni ebben a leírásban, hanem csak felhasználjuk az abban a környezetben írt webes alkalmazást. Mi is az a Node.js? Ha a weboldalát nézzük, akkor azt írják róla, hogy ez egy aszinkron, eseményvezérelt JavaScript futtatóprogram, amelyet skálázható hálózati alkalmazások építésére terveztek. Hú, ez elég összetetten hangzik, de megijedni nem kell tőle. A Javascript napjaink egyik legnépszerűbb programozási nyelve, és ha már ez így van, akkor a fejlesztők közösségének az volt az ötlete, hogy ne csak a webes alkalmazások kliens oldalán használjuk, hanem szerver oldalon is hasznos lenne az alkalmazása, két legyet üthetünk ezzel egy csapással (egy programozási nyelv részletes megismerésével kliens, és így, szerver oldalon is tudunk majd operálni). Jól hangzik, ugye? De mi most nem fogunk belemenni a részleteiben, csak használunk egy ilyen alkalmazást a példáinkban és csak minimálisan, gyakorlatilag statikus tartalmak, feliratok átírásán túl, nem fogunk belenyúlni és módosítani az alkalmazás működésébe.
Ezért
térjünk is vissza rögtön a Docker-re és futtassuk a következő parancsot
a Windows Terminal-unkban, ami létrehozza és futtatja a konténerünket:
docker run -d -p 80:80 docker/getting-started
A
parancs nem teljesen pontos, lásd az alábbi felsorolásban a megjegyzés
részt. A parancs a konténer elindítását fogja eredményezni. A futtatási
parancs paraméterezése:
A container (konténer) definíciójáról már van némi fogalmunk, de mi is az az image (kép)? Amikor futtatunk egy konténert, akkor az egy elszigetelt (izolált) fájlrendszert használ, amit a "container image" biztosít a számára. Mivel az image tartalmazza a konténer fájlrendszerét, annak tartalmaznia kell mindent, ami az alkalmazás futtatásához szükséges – minden függőséget, beállítást, szkripteket, bináris programokat és sok egyéb mást is. Az image ezen felül még a konténer egyéb konfigurációját is tartalmazza, például a környezeti változókat, egy alapértelmezett futtatandó parancso(ka)t és egyéb metaadatokat is.
A későbbiekben mélyebben belemerülünk az image-ek témakörébe, és olyan témákkal foglalkozunk, mint a rétegezés, a legjobb gyakorlatok (best practices) és még sok egyéb mással is, úgyhogy minden érthetővé válik majd.
A bemutató további részében egy alkalmazást fogunk építeni és működtetni, ami egy egyszerű "todo", vagyis elvégzendő tevékenységi lista menedzselő alkalmazás lesz. Ez a Node.js keretrendszerben működik, de az se ijedjen most meg, aki még sosem használta a Node.js-t, mert nem lesz hozzá szükségünk különösebb Javascript tudásra. Mi most csak egy MVP (Minimum Viable Product) terméket fogunk használni, amellyel tudjuk szemléltetni a Docker környezet működését és hogy mire vagyunk vele képesek.
Az
alkalmazás maga (forráskódja) egy-az-egyben "letölthető" saját
magunktól, a saját konténerünk kiszolgálása által a böngészőnkben: http://localhost/assets/app.zip
(ha esetleg futna már alapértelmezetten webszerver a gépünkön, például
egy Apache a XAMPP vagy WAMP által, akkor ezt érdemes leállítani,
mielőtt most a Docker-rel dolgoznánk).
A zip fájl tartalmát bárhova kicsomagolhatjuk a gépünkön, majd utána a mappáját nyissuk meg a kedvenc kódszerkesztőnkkel. Én a Visual Studio Code-ot fogom ehhez használni.
A projektnek az app mappanevet adtam és ide másoltam be a zip fájlban lévő app mappa tartalmát, így tehát bekerült ide két további almappa (spec és src), valamint van itt egy package.json és egy yarn.lock fájl is.
Ehhez szükségünk van a projekt gyökerében egy új fájlra: Dockerfile néven (kiterjesztés nélkül!).
A VSCode meg is kérdezi rögtön (jobb alul), hogy akarjuk-e telepíteni a Docker kiterjesztést. Én telepítem, mivel még többször fogom ezt használni a jövőben.
Ezután visszatérhetünk a Dockerfile tartalmához és feltölthetjük kóddal:
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
Most építsük fel a "container image"-t a következő paranccsal a terminal-ban (terminal-t tudunk indítani a VSCode-ban is, ha úgy kényelmesebb):
docker build -t getting-started .
Ez a parancs felhasználja az iménti Dockerfile-t az építkezéshez. Ehhez letölti majd a node:18-alpine image-t kiindulásnak. Beállítja a munkakönyvtárat az /app mappának. Átmásolja oda a teljes tartalmát, telepíti az alkalmazás függőségeit a yarn csomagkezelő segítségével. A -t kapcsoló után pedig simán elneveztük itt az image-t getting-started néven. A parancs végén lévő . (pont) mondja meg a Docker-nek, hogy hol kell keresnie a Dockerfile-t, ami a "receptúra" az image felépítéséhez.
Meg is jelent az új image a listában:
Az image-ünk így már megvan, futtathatjuk az alkalmazás konténerét.
Adjuk ki a parancsot a terminal-ban:
docker run -dp 3000:3000 getting-started
Megjegyzés: a -d kapcsoló együttesen is használható a -p kapcsolóval (-dp). Így a konténer elszigetelten fog működni, és a portot összekapcsoljuk: a kiszolgáló gép 3000-es portját csatlakoztatjuk a konténer 3000-es portjához.
A parancs futtatásának eredménye egy véletlenszerűen generált angol név, ami a neve lesz az új konténerünknek (azonosítója is egyben, hiszen, amíg ilyen nevű konténer létezik a listában, addig ilyet nem generál újra). A Docker Desktop konténer listájában pedig meg is jelent ez.
Mivel a konténer neve egy véletlenszerűen generált név lesz, szóval biztosan más a neve nálam, mint nálatok. Böngészőben pedig így néz ki az alkalmazás: http://localhost:3000/
Nyugodtan tesztelhetjük a működését: adhatunk hozzá új elemeket és majd el is végezhetjük őket: ha a bal oldali checkbox-okra kattintunk (áthúzásra kerül a nevük), vagy törölhetjük is őket, ha a jobb oldalukon lévő kuka ikonra kattintunk.
Így tehát van egy "dockerizált" (más néven, konténerizált) alkalmazásunk, aminek a fájlrendszerét az új, felépített image-ünk biztosítja, a futása pedig egy elszigetelt konténerben történik meg, amit mi egyszerű felhasználóként a böngészőnk segítségével érünk el a saját gép (localhost) 3000-es portján keresztül. Itt van a két jelenleg futó konténerünk a Docker Desktop vezérlőpultjában:
Megnézzük azt is, hogy milyen könnyű frissíteni az alkalmazásunk forráskódját. Egy nagyon egyszerű módosítást hajtunk végre, ami az üres lista állapotában kerül kiírásra. Jelenleg ez a szöveg olvasható: "No items yet! Add one above!", cseréljük le erre: "You have no todo items yet! Add one above!".
Keressük meg a VSCode-ban az src / static / js / app.js fájlt és annak is az 56. sorát, ott kell átírni a fenti szöveget az újra, majd mentsük el a fájlt. Ha most ellenőrizzük a böngészőnkben az alkalmazást és kukázzuk az eddig felvitt feladatokat, akkor viszont még azt tapasztaljuk, hogy a korábbi szöveg maradt meg, nem került frissítésre tehát a szöveg. Ez azért van, mivel a változások érvényesítéséhez újra kell építenünk először az image-et…
docker build -t getting-started .
… aztán pedig a konténert is:
docker run -dp 3000:3000 getting-started
Erre viszont hibaüzenetet kapunk, hiszen ezzel a névvel már van futó konténerünk, ami ráadásul be is van kötve a 3000-es portokra. Ezt viszont nagyon egyszerűen tudjuk orvosolni: először állítsuk le, majd töröljük a régi konténert a Docker Desktop vezérlőpultján, majd futtassuk újra az iménti parancsot.
Ha most frissítjük a böngészőnkben az alkalmazás lapját, akkor a frissített eredményt láthatjuk:
Két problémát tudunk azonosítani a fenti műveletsor kapcsán:
Úgyhogy a következő bejegyzésben fogjuk majd orvosolni ezeket a kellemetlenségeket. De előtte egy rövid kitérőt teszünk és megnézzük, hogy hogyan lehet megosztani az elkészített image-eket másokkal.
Docker image-eket a Docker Hub-on lehet megosztani a legegyszerűbben.
Regisztráljunk aztán jelentkezzünk be a Docker Hub oldalra (https://hub.docker.com/).
Ha futtatjuk ezt a parancsot:
docker push docker/getting-started
Akkor egy hibaüzenetet kapunk vissza, ami azt jelzi a számunkra, hogy nem létezik ilyen nevű (docker/getting-started) image a gépünkön.
Ki tudjuk listázni viszont az image-einket (vagy pedig meg tudjuk nézni őket a Docker Desktop-ban is):
docker image ls
Ez eddig rendben is van, látjuk a listában az image-ünket. Viszont össze kellene kötni az alkalmazásunkat a Docker Hub-bal, úgyhogy adjuk ki a parancsot a terminálban:
docker login -u <felhasználóneved>
(Sárga háttérszínnel jelölöm, amit ki kell cserélni a parancsban, mert mindenkinek a saját Docker Hub-os felhasználónevét kell oda beírnia <>-k nélkül.) Utána kérni fogja a jelszavadat is, amit ha jól adsz meg, vissza is igazolja egy "Login Succeeded" üzenettel.
Ezután nevezzük át az image-ünket úgy, hogy belevesszük a Docker Hub-os felhasználónevünket. A docker tag parancs használható erre:
docker tag getting-started <felhasználóneved>/getting-started
Ekkor egy új image jön létre a getting-started mintájára, csak bekerül elé a Docker Hub-os felhasználónevünk is.
Akár a Docker Desktop Image-eket tartalmazó ablakából is tudjuk push-olni az image-ünket:
(A felhasználónevemet kékkel kitakartam és a későbbiekben is kitakarom majd, ha nem felejtem el 😊 )
Vagy pedig a VSCode termináljában kiadhatjuk a parancsot:
docker push <felhasználóneved>/getting-started
Alapértelmezetten a latest tag-et fogja hozzáadni a rendszer.
Az eredmény a Docker Hub-on látható, ha megnyitjuk az új Repo-nkat (korábban ez a "Tags and scans" szekció üres volt):
A sikeres futtatás után én a korábbi (felhasználónév nélküli) image-emet töröltem (előtte a kapcsolódó konténert érdemes leállítani).
Kipróbálhatjuk, hogy a publikus image-ünket meg tudjuk-e futtatni egy nyilvános helyen (persze, csak korlátozott ideig áll majd rendelkezésre, mivel csak kipróbálás céljára használjuk).
Keressük fel ezt a weboldalt és jelentkezzünk be: https://labs.play-with-docker.com/ A Docker Hub-os felhasználónk fog kelleni hozzá. A bejelentkezés elfogadása után indíthatjuk is a "játékot":
4 óráig használhatjuk, bal felül el is indult a visszaszámlálás.
Kattintsunk itt rá, az "+ ADD NEW INSTANCE" gombra, aminek következtében a fő tartalmi részen meg fog nyílni nekünk egy terminál. Írjuk be oda ezt a parancsot:
docker run -dp 3000:3000 <felhasználóneved>/getting-started
Az eredménye itt látható:
Ahogy az látható: én egy "no space left on device" hibaüzenetet kaptam, ami a parancs újra- és újrafuttatásával sem oldódott meg, emiatt én vártam egy picit és utána, ha megint futtattam, akkor már jó lett:
Ha most az oldalon felül rákattintok az "OPEN PORT" gombra, majd beírom a felugró ablakba a "3000"-est (idézőjelek nélkül csak a számot), akkor egy új lapon meg kell jelennie az alkalmazásnak.
A generált webcím megnyílik, ami kiadja az alkalmazást, és már vittem is fel két teszt feladatot, ahogy az az iménti képen látszódik is.
Itt most megismertük, hogy hogyan lehet megosztani az image-einket azáltal, hogy feltöltöttük egy nyilvános repo-ba. De ennyi kitérő után, majd a következő bejegyzésben visszatérünk az előző szekcióban jelzett problémákhoz, elsőként az adatok (beírt feladatok a todo listában) elvesztését fogjuk kiküszöbölni.
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.