Kihagyás

01 - Konténerizáció

Cél

A labor célja megismerni a Docker konténerek használatának alapjait és a leggyakrabban használt Docker CLI parancsokat.

Előkövetelmények

Előkészület

A feladatok megoldása során ne felejtsd el követni a feladat beadás folyamatát GitHub.

Git repository létrehozása és letöltése

  1. Moodle-ben keresd meg a laborhoz tartozó meghívó URL-jét és annak segítségével hozd létre a saját repository-dat.
  2. Várd meg, míg elkészül a repository, majd checkout-old ki.
  3. Hozz létre egy új ágat megoldas néven, és ezen az ágon dolgozz.
  4. A neptun.txt fájlba írd bele a Neptun kódodat. A fájlban semmi más ne szerepeljen, csak egyetlen sorban a Neptun kód 6 karaktere.

NEPTUN

❗ A példákban a neptun helyett a saját neptunkódunkat helyettesítsük be. Ha neptun-ként látod, akkor kisbetűvel írd; ha NEPTUN-ként, akkor nagybetűvel ❗

0. Feladat

Docker hello world

Teszteljük a Docker telepítésünket a hello-world image futtatásával.

Nyissunk egy konzolt, és adjuk ki a következő parancsokat. Ezzel ellenőrizhetjük, hogy a docker CLI elérhető-e.

docker --version

Futtassunk egy egyszerű előre elkészített konténert, ami kiír egy példa szöveget a konzolra. Fontos, hogy a telepített Docker Desktop fusson a háttérben!

docker run hello-world

Konténer futtatása interaktív módon

  • Futtassunk egy natúr ubuntu konténert interaktív módon (-it kapcsolóval), így a futó konténerben egy shell-en keresztül tudunk tetszőleges parancsokat futtatni.

    docker run -it ubuntu
    
  • Nézzük meg a fájlrendszert:

    ls
    
  • Lépjünk ki az interaktív shell-ből:

    exit
    

    Konténer terminált, mert a bash folyamat megállt az exit hatására. Konténer addig fut, amíg a benne levő alkalmazás (folyamat) fut. Leállt konténer nem törlődik automatikusan, tartalma nem veszik el.

  • Listázzuk ki a konténereinket:

    docker ps -a
    

    Nézzük meg a parancs eredményét. Keressük meg a konténerek id-ját.

  • Távolítsuk el a két konténert, amit mi indítottunk:

    docker rm <id1|name> <id2|name>
    

    Tip

    ID helyett a konténer nevét is megadhatjuk. Az automatikusan generált nevek helyett pedig a run parancs --name kapcsolójával adhatunk nevet a konténernek.

Gyakoribb Docker parancsok
  • Adjuk ki a docker parancsot a help-hez.
  • Adminisztratív parancsok: mivel mit, pl. docker image ls
  • Kezelő parancsok: parancs argumentumok, pl. docker rmi <id>
  • Gyakran használtak:
  • Konténerek kezelése
    • docker container ls [-all] vagy docker ps [-a]
    • docker run [opciók] <image>
    • docker stop <id>
    • docker rm <id>
  • Image-ek kezelése
    • docker pull <image>
    • docker image ls vagy docker images
    • docker rmi <image>
    • docker tag <id> <tag>
  • Konkrét parancshoz segítség: docker <parancs> --help
  • Minden konténer (futók is!) eltávolítása: docker rm -f $(docker ps -aq)

GUI vs CLI

A Dockerhez már nagyon sok hasznos GUI-val rendelkező eszköz létezik, amik nagyban megkönnyítik a fejlesztők életét. A labor viszont elsősorban konzolos használatra fókuszál, mert az a leguniverzálisabb és a GUI-s eszközök is valójában az itt elérhető funkciókra építenek. A labor elvégzése során ha kényelmesebb nyugodtan használd a számodra kényelmesebb eszközt.

1. Feladat

1.1 Volume csatolása (bind mount)

Gyakran szeretnénk a host gépről elérni a konténerben lévő fájlokat, vagy éppen a konténerben lévő fájlokat szeretnénk a host gépen tárolni. Erre megoldás a volume csatolás, amikor a host gép egy könyvtárát csatoljuk a konténerbe.

  • Hozzunk létre egy munkakönyvtárat tetszőleges helyen a neptun kódunkkal, például c:\work\neptun (windows) ~/work/neptun (linux)

  • Indítsunk el egy konténert úgy, hogy ezt a könyvtárat felcsatoljuk a -v kapcsolóval:

    Windows
    docker run -it --rm -v c:\work\neptun:/neptun ubuntu
    
    Linux
    docker run -it --rm -v ~/work/neptun:/neptun ubuntu
    

    Szintaktika: helyi teljes elérési útvonal kettőspont konténeren belüli teljes elérési útvonal

  • Konténeren belül listázzuk ki a könyvtárat:

    ls
    

    Látjuk a /neptun könyvtárat

  • Írjunk bele:

    echo "hello NEPTUN" > /neptun/hello.txt
    
  • írjuk ki a tartalmát:

    cat /neptun/hello.txt
    
  • Lépjünk ki a konténerből:

    exit
    
  • Nézzük meg a munkakönyvtárunkat.

--rm

A docker run --rm opciója törli a konténert leállás után; pl. teszteléshez hasznos, mint most.

BEADANDÓ

Készíts egy képernyőképet (f1.1.png) és commitold azt be a házi feladat repó gyökerébe, amin a fenti Volume csatolás feladatok parancsainak eredményei láthatóak.

1.2 Port mappelés

Docker konténerek esetében gyakran webalkalmazásokat futtatunk, amiket a host gépről szeretnénk elérni. Ezt a port mappeléssel érhetjük el, ahol a host gép egy portját mappeljük a konténer egy portjára.

  • Indítsunk el egy nginx webszervert tartalmazó konténert:

    docker run -d -p 8085:80 nginx
    
    • -d (detach): háttérben fut, a konzolt "visszakapjuk", amint elindult a konténer, és kiírja az image id-t
    • -p (port): helyi port kettőspont konténeren belüli port
  • Nyissuk meg böngészőben a címet a neptun kódunkkal: http://localhost:8085/index.html?student=NEPTUN

  • Nézzük meg a konténer logjait:

    docker logs <id|name>
    
  • Állítsuk le a konténert:

    docker stop <id|name>
    

BEADANDÓ

Készíts egy képernyőképet (f1.2.png) és commitold azt be a házi feladat repó gyökerébe, amin a fenti webcím megnyitásának a logjai látszódnak. Emeld ki a képen a releváns logbejegyzést (pl.: karikázd be vagy sárga kiemelevőlvel színezd.)

1.3 Műveletvégzés futó konténerben

Gyakran már egy futó konténerben szeretnénk műveleteket végezni, pl. fájlokat nézni, módosítani, stb. Ehhez a docker exec és docker cp parancsot használjuk most.

  • Indítsunk el egy nginx webszervert:

    docker run -d -p 8085:80 nginx
    

    Jegyezzük meg a kiírt konténer id-t, alább használni fogjuk. (A kiírt karakterlánc első 12 karaktere jelöli az ID-t.)

  • Futtassunk le egy parancsot a konténerben:

    docker exec <id|name> ls /
    

    A parancs kilistázta a konténer fájlrendszerének gyökerét.

  • Kérhetünk egy shell-t is a konténerbe ily módon:

    docker exec -it <id|name> /bin/bash
    
    • Az -it opció az interaktivitásra utal, azaz a konzolunkat "hozzáköti" a konténerben futó shellhez.
    • Tipikusan vagy /bin/bash vagy /bin/sh a Linux konténerekben a shell. Utóbbi az alpine alapú konténerekben gyakori.
    • Ebben az interaktív shell-ben bármit csinálhatunk, beléphetünk könyvtárakba, megnézhetünk fájlokat, stb. Arra viszont ügyeljünk, hogy az így végzett módosításaink elvesznek, amikor a konténer törlésre kerül!
  • Például nézzük meg az nginx konfigurációját:

    cat /etc/nginx/conf.d/default.conf
    
  • Módosítsuk az index.html-t a következő módon:

    echo "hello NEPTUN from nginx" > /usr/share/nginx/html/index.html
    
  • Nyissuk meg böngészőben ezt a címet: http://localhost:8085/index.html és ellenőrizzük, hogy a módosított tartalom látszik-e.

  • Lépjünk ki az exit utasítással. Ez csak a "második" shellt állítja le, a konténer még fut, mert az eredeti indítási pont is még fut.

  • Ha szükségünk van egy fájlra, akkor azt kimásolhatjuk a futó konténerből:

    Windows
    docker cp <id|name>:/etc/nginx/conf.d/default.conf c:\work\neptun\nginx.conf
    
    Linux
    docker cp <id|name>:/etc/nginx/conf.d/default.conf ~/work/neptun/nginx.conf
    
    • Szintaktikája: docker cp <id|name>:</full/path> <cél/hely>
    • A másolás az ellenkező irányba is működik, helyi gépről a konténerbe.
  • Állítsuk le és töröljük a konténert.

    docker stop <id|name>
    docker rm <id|name>
    

BEADANDÓ

Készíts egy képernyőképet (f1.3.png) és commitold azt be a házi feladat repó gyökerébe, amin a fenti weboldal látszik a böngészőben.

2. Feladat

2.1 Image készítése parancssorból

Docker registry

Korábban használt parancs: docker run ubuntu Az ubuntu az image neve. Ez egy ún. registry-ből jön, analóg más csomagkezelőkhöz pl.: NPM, NuGet stb. Az alapértelmezett registry a https://hub.docker.com, ahol tipikusan open-source szoftverek image-ei és az általunk is használt alap image-ek találhatóak. Léteznek természetesen továbbiak is (Azure, Google, stb.).

Az image neve valójában nem ubuntu, hanem index.docker.io/ubuntu:latest

  • index.docker.io registry szerver elérési útvonala
  • ubuntu image neve (lehet többszintű is)
  • :latest tag neve

Jogosultság szempontból két fajta registry létezhet: publikus (pl. Docker Hub) és privát. Privát registry esetén docker login <url> és docker logout <url> szükséges az authentikációhoz.

Letöltés a registry-ből: docker pull mcr.microsoft.com/dotnet/aspnet:8.0

Ugyan a run parancs is letölti, de csak akkor, ha még nem létezik. Nem ellenőrzi viszont, hogy nincs-e újabb image verzió publikálva. A pull mindig frisset szed le.

Készítünk egy saját image-et, ami egy módosított nginx image-et fog tartalmazni a saját tartalmunkkal. Ehhez az előző feladatban lévő lépéseket kell ismét elvégezned, de most ne lépj ki a konténerből, hanem a konténer állapotát mentsd egy új image-be, ami az nginx-re épít, és egy új image layer-t tartalmaz a saját tartalmunkkal.

  1. Az előző feladat alapján futtass egy nginx konténert, amiben módosítod az index.html tartalmát.

  2. Készíts egy pillanatmentést a konténer jelenlegi állapotáról:

    docker commit <id|name>
    
  3. Állítsd le a háttérben futó konténert:

    docker stop <id|name>
    
  4. Az előbbi parancs készített egy image-et, aminek kiírta a hash-ét. Ellenőrizd, hogy tényleg létezik-e ez az image:

    docker images
    
  5. Taggeld meg az image-et:

    docker tag <imageid> nginx-neptun
    

    Warning

    Itt már az image id-ja kell az images listából!

  6. Indíts el egy új konténert az előbb létrehozott saját image-ből:

    docker run -it --rm -p 8086:80 nginx-neptun
    

    Warning

    A portszám szándékosan más, hogy biztosan legyünk benne, nem a korábban futóhoz csatlakozunk - ha mégsem állítottuk volna azt le.

  7. Nyisd meg böngészőből a http://localhost:8086 címet. Látható, hogy ez a módosított tartalmat jeleníti meg. Tehát nginx-neptun néven létrehoztunk egy saját image-et.

BEADANDÓ

Készíts egy képernyőképet (f2.1.png) és commitold azt be a házi feladat repó gyökerébe, amin a fenti weboldal látszik a böngészőben és a konténert futtató parancs a terminálban és annak a logjai.

Takarítás

Fejlesztés közben sok ideiglenes image keletkezik, és konténereket hagyunk hátra. Add ki a következő parancsot a nem futó konténerek törléséhez és az ideiglenes (címke nélküli) image-ek törléséhez:

docker system prune

2.2 Dockerfile

Az előző feladatban az image készítését manuálisan végeztük el, ami nem jól verziózható, és reprodukálhatósági problémákat okozhat.

Készítsünk egy egyszerű webalkalmazás Pythonban a Flask nevű keretrendszerrel, ami egy REST végpontot definiál és szolgál ki. Az adatokat (egy számláló) Redis adatbázisból olvassa és írja, és egy üdvözlő üzenetet ad vissza környezeti változó alapján.

  1. Nyisd meg a házi repositorydat Visual Studio Code-ban.

  2. Készíts a repository mappájába egy almappát pythonweb néven. A továbbiakban ennek a kontextusában dolgozz.

  3. Készíts egy app.py fájlt az alábbi tartalommal.

    from flask import Flask
    from redis import Redis, RedisError
    import os
    import socket
    
    # Connect to Redis
    redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
    
    app = Flask(__name__)
    
    # root endpoint
    # inrements and returns the number of visits from Redis
    # and says hello to the user from the NAME environment variable
    @app.route("/")
    def hello():
        try:
            visits = redis.incr("counter")
        except RedisError:
            visits = "<i>cannot connect to Redis, counter disabled</i>"
    
        html = "<h3>Hello {name}!</h3><b>Visits:</b> {visits}"
        return html.format(name=os.getenv("NAME", "world"), visits=visits)
    
    if __name__ == "__main__":
        app.run(host='0.0.0.0', port=80)
    
  4. Készíts egy requirements.txt fájlt az alábbi tartalommal, ami a Python alkalmazásunk függőségeit tartalmazza.

    Flask
    Redis
    
  5. Készíts egy Dockerfile nevű fájt (kiterjesztés nélkül!) az alábbi tartalommal. A Dockerfile egy szöveges fájl, ami tartalmazza az image létrehozásának lépéseit, mint egy recept.

    FROM python:3.12-slim
    
    WORKDIR /app
    COPY . /app
    
    RUN pip install --trusted-host pypi.python.org -r requirements.txt
    EXPOSE 80
    
    # Ide a saját Neptun kódodat írd
    ENV NAME=NEPTUN 
    
    CMD ["python", "app.py"]
    
  6. Készítsd el a fenti fájlokból az image-et. Konzolból a munkakönyvtárban add ki a következő parancsot:

    docker build -t python-neptun:v1 .
    

    Ez a parancs létrehoz egy image-et a Dockerfile alapján. A végén egy pont van, az is a parancs része, ami a build kontextust jelenti.

    A Dockerfile lépései:

    • FROM: az alap image, amire építjük a sajátunkat. Mi most a Python 3.12-slim image-et használjuk.
    • WORKDIR: a konténerben a munkakönyvtár, a további műveletek ebben a könyvtárban lesznek.
    • COPY: a host gépről a konténerbe másoljuk a fájlokat. A . jelenti a build kontextus mappáját, esetünkben a pythonweb mappát.
    • RUN: a build/image készítés során lefuttatandó parancsok. Itt a requirements.txt fájlban felsorolt Python csomagokat telepítjük a python csomagkezelővel (pip).
    • EXPOSE: a konténer által kiajánlott portokat jelzi. Mi most webalkalmazást készítünk, ezért a 80-as portot jelöljük ki.
    • ENV: környezeti változó beállítása. A NAME környezeti változó értéke a saját Neptun kódod legyen.
    • CMD: a konténer indításakor lefuttatandó parancs és argumentumai. Ebben az esetben a Python alkalmazásunkat indítjuk el.
  7. Ellenőrizd, hogy tényleg létrejött-e az image.

  8. Indíts el egy új konténert ebből az image-ből:

    docker run -it --rm -p 8085:80 python-neptun:v1
    
  9. Nyisd meg böngészőben a http://localhost:8085 oldalt.

A weboldal ki kell írja a neptun kódodat, és egy hibaüzenetet a Redis-szel kapcsolatban.

BEADANDÓ

Készíts egy képernyőképet (f2.2.png) és commitold azt be a házi feladat repó gyökerébe, amin a fenti weboldal látszik a böngészőben és a konténer futtatás parancsa és logjai.

Kitekintés: Dockerignore és build kontextus

A Dockerfile-ban hivatkoztunk az aktuális könyvtárra a .-tal. Vizsgáljuk meg, hogy ez mit is jelent.

  1. Készítsünk az aktuális könyvtárunkba, az app.py mellé egy nagy fájlt. Ehhez PowerShell-ben adjuk ki a következő parancsot.

    Windows - powershell
    $out = new-object byte[] 134217728; (new-object Random).NextBytes($out); [IO.File]::WriteAllBytes("$pwd\file.bin", $out)
    
    Linux - bash
    dd if=/dev/urandom of=./file.bin bs=1M count=1024
    
  2. Buildeljük le ismét a fenti image-et: docker build -t python-neptun:v1 .

    Menet közben látni fogjuk a következő sort a build logban: Sending build context to Docker daemon 111.4MB, és azt is tapasztalni fogjuk, hogy ez el tart egy kis ideig.

    A docker build parancs végén a . az aktuális könyvtár. Ezzel tudatjuk a Docker-rel, hogy a buildeléshez ezt a kontextust használja, azon fájlok legyenek elérhetőek a build során, amelyek ebben a kontextusban vannak. A Dockerfile-ban a COPY így relatív útvonallal hivatkozik a kontextusban levő fájlokra.

    Elérhető fájlok

    Ennek következménye az is, hogy csak a build kontextusban levő fájlokra tudunk hivatkozni. Tehát nem lehet pl. COPY ..\..\file használatával tetszőleges fájlt felmásolni a build közben.

  3. Ha a build kontextusból szeretnénk kihagyni fájlokat, hogy a build ne tartson sokáig, akkor egy .dockerignore fájlra lesz szükségünk (a .gitignore mintájára). Ide szokás például a build környezet saját könyvtárait (obj, bin, .vs, node_modules, stb.) is felvenni.

    Készítsünk egy .dockerignore-t az alábbi tartalommal

    file.bin
    
  4. Futtassuk ismét a buildet. Így már gyorsabb lesz.

3. Feladat

3.1 Docker-compose

Linux eltérés

Linuxon a compose nem egy külön parancs, hanem a docker parancs kiterjesztése. Emiatt docker-compose helyett docker compose-ként kell meghívnunk.

A fenti alkalmazás egy része még nem működik. A Python alkalmazás mellett egy Redis-re is szükségünk lenne. Futtassunk több konténert egyszerre a docker compose segítségével.

  1. Dolgozzunk a repository gyökerébe (tehát ne az előzőleg használt almappába) és készítsünk ide egy docker-compose.yaml nevű fájlt az alábbi tartalommal.

    services:
      redis:
        image: redis:7.2-alpine
        networks:
          - homework_network
      web:
        build: pythonweb
        ports:
          - 5000:80
        depends_on:
          - redis
        networks:
          - homework_network
    
    networks:
      homework_network:
        driver: bridge
    

    A fájl tartalmának magyarázata:

    • services: a szolgáltatások, amiket indítani szeretnénk
    • redis: egy Redis konténer, ami az alpine verziót használja
    • web: a saját image-ből épített Python alkalmazás konténere
      • build: a build kontextusban lévő mappából építi az image-t
      • ports: a konténer által kiajánlott portokat jelzi. Mi most webalkalmazást készítünk, ezért a konténer 80-as portját mappeljük a host 5000-es portjára.
      • depends_on: a konténer indításának sorrendjét jelzi. A web konténer csak akkor indul, ha a redis konténer már fut.
    • networks: a konténerek közötti hálózatokat definiálja. A homework_network nevű hálózatot használjuk bridge módban, ami a konténerek között adatkapcsolati réteg szintű összeköttetést jelent. Erre hivatkozunk a konténerek networks tulajdonságában is.
  2. Nyiss egy konzolt ugyanebbe a mappába. Indítsd el az alkalmazásokat az alábbi paranccsal:

    docker-compose up --build
    

    Két lépésben a parancs: docker-compose build és docker-compose up

  3. Nyisd meg böngészőben a http://localhost:5000 oldalt.

  4. Egy új konzolban nézd meg a futó konténereket.

    docker ps
    

BEADANDÓ

Készíts egy képernyőképet (f3.1.png) és commitold azt be a házi feladat repó gyökerébe, amin a fenti weboldal látszik a böngészőben és a futó konténerek listája a konzolban.

docker-compose üzemeltetéshez

A docker-compose alkalmas üzemeltetésre is. A docker-compose.yaml fájl nem csak fejlesztői környezetet ír le, hanem üzemeltetéshez szükséges környezetet is. Ha a compose fájlt megfelelően írjuk meg (pl. használjuk a restart direktívát is), az elindított szolgáltatások automatikusan újraindulnak a rendszer indulásakor.

Ugyanakkor a docker-compose nem helyettesíti a Kubernetes-t vagy más konténer orkesztrációs megoldásokat, mert azok sokkal komplexebb feladatokat is meg tudnak oldani (pl. skálázás, load balancing, stb.).

3.2 Több compose yaml fájl

A docker-compose parancsnak nem adtuk meg, hogy milyen yaml fájlból dolgozzon. Alapértelmezésként a docker-compose.yaml kiterjesztésű fájlt és ezzel összefésülve a docker-compose.override.yaml fájlt használja.

  1. Készíts egy docker-compose.override.yaml fájlt a másik compose yaml mellé az alábbi tartalommal, amiben a redis konténer naplózását állítjuk át verbose szintre.

    services:
      redis:
        command: redis-server --loglevel verbose
    
  2. Indítsd el a rendszert.

    docker-compose up
    

    A redis konténer részletesebben fog naplózni a command direktívában megadott utasítás szerint. Állítsd le a rendszert.

  3. Nevezd át az előbbi override fájlt docker-compose.debug.yaml-re.

  4. Készíts egy új docker-compose.prod.yaml fájlt a többi yaml mellé az alábbi tartalommal

    services:
      redis:
        command: redis-server --loglevel warning
    
  5. Indítsuk el a rendszert az alábbi paranccsal

    docker-compose -f docker-compose.yaml -f docker-compose.debug.yaml up
    

    A -f kapcsolóval tudjuk kérni a megadott yaml fájlok összefésülését.

Általában a docker-compose.yaml-be kerülnek a közös konfigurációk, és a további fájlokba a környezet specifikus konfigurációk.

BEADANDÓ

Készíts egy képernyőképet (f3.2.png) és commitold azt be a házi feladat repó gyökerébe, amin a fenti weboldal látszik a böngészőben és a részletesebb redis naplóbejegyzések.

Opcionális: 4. Feladat

Docker init

A docker init paranccsal egy megadott technológiához tartozó, docker alapú fejlesztéshez szükséges-hasznos fájlokat generáltathatjuk. A fájlok az adott technológiához illeszkedően készülnek, például ASP .NET Core esetén a megfelelő .NET alap lemezképekre hivatkozik a generált Dockerfile.

.NET

Ehhez a feladathoz telepítened kell a .NET SDK-t (lásd fentebb az Előkövetelmények részt), mely a dotnet parancsot adja.

  1. Készíts a repository mappájába egy almappát aspnetweb néven. A továbbiakban ennek az új mappának a kontextusában dolgozz.

  2. Generálj egy ASP.NET Core alapú kiinduló projektet

    dotnet new webapp
    
  3. Generáld az ASP.NET Core-hoz tartozó docker fájlokat

    docker init
    
    Ez a lépés létrehoz egy Dockerfile-t a projektben, ami ráadásul multi-stage build megoldást tartalmaz, ami a fordítási, publikálási és futtatási fázisokat különválasztja (több FROM utasítás amik egymásra hivatkoznak). Ezáltal biztosítható, hogy a .NET alkalmazásunk fordítása is reprodukálható legyen egy szeparált .NET SDK-t tartalmazó konténerben. A publikálás pedig egy kisebb méretű image-be történik, ami már csak a .NET futtatókörnyezetet tartalmazza.

    Ezen felül létrejön még .dockerignore fájl is, valamint egy egy service-t hivatkozó Docker compose is.

  4. Futtassuk a docker compose configurációt (docker-compose up - Windows vagy docker compose up - Linux). Az alapértelmezetten felkínált lehetőségek általában megfelelőek, csak végig kell Enter -ezni. Böngészőben nyissuk meg a localhost címen a docker init-nek megadott portot pl. http://localhost:8080.

  5. Listázzuk ki a futó konténereket egy külön konzolablakban:

    docker ps
    

BEADANDÓ

Készíts egy képernyőképet (f4.1.png) és commitold azt be a házi feladat repó gyökerébe, amin a fenti weboldal látszik a böngészőben és a futó konténerek listája.

Kitekintés

Image-ek használata

Konténer alapú fejlesztésnél tehát két féle image-et használunk:

  • amit magunk készítünk egy adott alap image-re épülve,
  • illetve kész image-eket, amiket csak futtatunk (és esetleg konfigurálunk).

Alap image-ek, amikre tipikusan saját alkalmazást építünk:

  • Linux disztribúciók
  • Futtató platformok
    • .NET Runtime ASP.NET Core-ral, pl. mcr.microsoft.com/dotnet/aspnet:8.0
    • NodeJS pl. node:22.4-alpine
    • Python pl. python:3.12-slim
  • scratch: üres image, speciális esetek, pl. go, vagy distro készítéshez

A kész image-ek, amiket pedig felhasználunk:

  • SDK-k multi stage buildhez
    • .NET SDK pl. mcr.microsoft.com/dotnet/sdk:8.0
  • Adatbázis szerverek, webszerverek, gyakran használt szolgáltatások
    • MSSQL, redis, mongodb, mysql, nginx, ...
  • Termérdek elérhető image: https://hub.docker.com

Verziózás fontos

Az image-ek verziózását minden esetben meg kell érteni! Minden image más-más megközelítést alkalmaz.

Kész image testreszabása

Az előbb a Redis memória alapú adatbázist minden konfiguráció nélkül felhasználtuk. Gyakran az ilyen image-ek "majdnem" jók közvetlen felhasználásra, de azért szükség van egy kevés testreszabásra. Ilyen esetben a következő lehetőségeink vannak:

  • Saját image-et készítünk kiindulva a számunkra megfelelő alap image-ből. A saját image-ben módosíthatunk a konfigurációs fájlokat, avagy további fájlokat adhatunk az image-be. Ezt a megoldást alkalmazhatjuk például tipikusan weboldal kiszolgálásánál, ahol is a kiinduló image a webszerver, viszont a kiszolgálandó fájlokat még mellé kell tennünk.

  • Környezeti változókon (esetleg argumentumokon) keresztül konfiguráljuk a futtatandó szolgáltatást. Az alap image-ek általában elég jó konfigurációval rendelkeznek, csak keveset kell rajta módosítanunk. Erre tökéletesen alkalmas egy-egy környezeti változó. A jól felépített Docker image-ek előre meghatározott környezeti változókon keresztül testreszabhatóak.

    Erre egy jó példa a Microsoft SQL Server Docker változata. Az alábbi parancsban a -e argumentumokban adunk át környezeti változókat, de lehetőség van compose fájlban is megadni ezeket.

    docker run
      -e 'ACCEPT_EULA=Y'
      -e 'SA_PASSWORD=yourStrong(!)Password'
      -p 1433:1433
      mcr.microsoft.com/mssql/server:2017-CU8-ubuntu
    
  • Becsatolhatjuk a saját konfigurációs fájljainkat a konténerbe. Korábban láttuk, hogy lehetőségünk van egy mappát a host gépről a konténerbe csatolni. Ha elkészítjük a testreszabott konfigurációs fájlt, akkor a docker-compose.yaml leírásban a következő módon tudjuk ezt a fájlt becsatolni a konténer indulásakor.

    services:
      redis:
        image: redis:7.2-alpine
        volumes:
          - my-redis.conf:/usr/local/etc/redis/redis.conf
    

    Ezen megoldás előnye, hogy nincs szükség saját image-et készíteni, tárolni, kezelni. Amikor a környezeti változó már nem elegendő a testreszabáshoz, ez a javasolt megoldás.

További olvasnivaló


2024-10-18 Szerzők