Dockerfile írása lépésről lépésre
Tanuld meg megírni az első saját Dockerfile-od. Végigvesszük a FROM, WORKDIR, COPY, RUN, EXPOSE és CMD utasításokat egy valódi példán keresztül.
Eddig kész image-eket futtattál a Docker Hubról, de a Docker igazi ereje akkor mutatkozik meg, amikor saját image-et építesz a saját alkalmazásodhoz. Ennek receptje a Dockerfile: egy egyszerű szöveges fájl, amely lépésről lépésre leírja, hogyan épüljön fel az image-ed. Ebben a cikkben végigvesszük a legfontosabb utasításokat, majd egy valódi Node.js alkalmazáshoz közösen megírunk egy teljes Dockerfile-t. A végére képes leszel a saját projektedet is konténerizálni!
Mi az a Dockerfile?
A Dockerfile egy Dockerfile nevű (kiterjesztés nélküli) szöveges fájl, amely utasítások sorozatából áll. Minden utasítás egy lépést ír le az image felépítésében, és többségük egy új réteget hoz létre. A Docker fentről lefelé, sorban hajtja végre őket, amikor lefuttatod a docker build parancsot.
Nézzük meg az utasításokat egyenként, mielőtt összerakjuk a teljes példát.
Az alapvető utasítások
FROM – az alapimage
Minden Dockerfile egy FROM utasítással kezdődik, amely megadja, milyen alapimage-ből indulsz. Ez lehet egy operációs rendszer vagy egy nyelvi futtatókörnyezet.
FROM node:22-alpine
Itt a Node.js 22-es verzióját választottuk az alpine változatban, amely egy minimális, kis méretű Linux disztribúción alapul. A kisebb alapimage gyorsabb buildet és kisebb végeredményt jelent.
WORKDIR – a munkakönyvtár
A WORKDIR beállítja az aktuális munkakönyvtárat a konténeren belül. Az ezután következő utasítások (COPY, RUN, CMD) ehhez képest értelmeződnek. Ha a könyvtár nem létezik, a Docker létrehozza.
WORKDIR /app
COPY – fájlok másolása
A COPY a build contextből (a gazdagépedről) másol fájlokat az image-be. Az első paraméter a forrás, a második a célhely a konténeren belül.
COPY package.json package-lock.json ./
RUN – parancs futtatása build közben
A RUN egy parancsot futtat le az image építése során, és az eredményt egy új rétegként menti. Tipikusan függőségek telepítésére használjuk.
RUN npm ci --omit=dev
ENV – környezeti változók
Az ENV környezeti változókat állít be, amelyek a build során és a futó konténerben is elérhetők lesznek.
ENV NODE_ENV=production
EXPOSE – a figyelt port dokumentálása
Az EXPOSE jelzi, hogy az alkalmazás melyik porton figyel. Fontos tudni: ez önmagában nem nyitja meg a portot, csak dokumentál. A tényleges port-leképezést a docker run -p kapcsolóval végzed.
EXPOSE 3000
CMD és ENTRYPOINT – mi induljon a konténerben
A CMD megadja az alapértelmezett parancsot, amely a konténer indulásakor lefut. Ezt felül lehet írni a docker run után megadott paraméterekkel. Az ENTRYPOINT ezzel szemben a fő futtatható parancsot rögzíti, amelyet nem írnak felül olyan könnyen. A kettő gyakran együtt használatos: az ENTRYPOINT adja a programot, a CMD az alapértelmezett argumentumokat.
CMD ["node", "server.js"]
💡 Tipp: Mindig az úgynevezett „exec” formátumot használd (szögletes zárójeles JSON-tömb, pl.
["node", "server.js"]), ne a „shell” formátumot. Az exec forma helyesen kezeli a leállítási jelzéseket, így a konténered szabályosan tud leállni.
A teljes példa: egy Node.js alkalmazás
Most rakjuk össze az egészet egy valódi kis Node.js alkalmazáshoz. Tegyük fel, hogy van egy server.js fájlod és egy package.json-od. Így néz ki a teljes Dockerfile:
# Alapimage: Node.js 22 a kis méretű Alpine változaton
FROM node:22-alpine
# Munkakönyvtár a konténeren belül
WORKDIR /app
# Először csak a függőséglistát másoljuk (a cache miatt)
COPY package.json package-lock.json ./
# Függőségek telepítése
RUN npm ci --omit=dev
# Most másoljuk a teljes alkalmazáskódot
COPY . .
# Környezeti változó
ENV NODE_ENV=production
# Az alkalmazás a 3000-es porton figyel
EXPOSE 3000
# Indítóparancs
CMD ["node", "server.js"]
Az image megépítése
Ha kész a Dockerfile, az image megépítése egyetlen paranccsal történik:
docker build -t sajat-app:1.0 .
A kapcsolók jelentése:
-t sajat-app:1.0– Nevet (sajat-app) és tagot (1.0) ad az image-nek..– A build context, vagyis az aktuális könyvtár, ahonnan a Docker a fájlokat eléri.
A build után máris futtathatod:
docker run -d -p 3000:3000 --name app sajat-app:1.0
Miért fontos a rétegek sorrendje? A cache
Biztosan feltűnt, hogy a példában előbb csak a package.json-t másoltuk és telepítettük a függőségeket, és csak utána másoltuk a teljes kódot. Ez nem véletlen.
A Docker minden réteget gyorsítótáraz (cache-el). Ha egy réteg bemenete nem változott, akkor a Docker újra felhasználja a korábbi eredményt ahelyett, hogy újra lefuttatná. A függőségek telepítése (npm ci) a leglassabb lépés, ezért érdemes úgy szervezni a Dockerfile-t, hogy ez csak akkor fusson le újra, ha tényleg változott a package.json.
Mivel a kódod sűrűbben változik, mint a függőségeid, ezzel a sorrenddel a legtöbb buildnél a Docker megspórolja a teljes függőségtelepítést. A szabály egyszerű: a ritkán változó dolgok kerüljenek előre, a gyakran változók hátra.
A .dockerignore fájl
A docker build . parancs a teljes aktuális könyvtárat átküldi a Dockernek build contextként. Ha ide bekerül a node_modules, a .git vagy más felesleges fájl, a build lassú lesz, és akár nem kívánt dolgok is bekerülhetnek az image-be.
A megoldás egy .dockerignore fájl, amely a .gitignore-hoz hasonlóan kihagyja a felesleges fájlokat:
node_modules
.git
.env
*.log
Dockerfile
⚠️ Figyelem: A
node_moduleskihagyása különösen fontos Node.js-nél. A függőségeket a konténeren belül telepítjük aRUN npm cilépésben, így a gazdagépről bemásoltnode_modulesnemcsak felesleges, de platformeltérések miatt hibákat is okozhat.
Egy szó a többlépcsős buildről
Ha még kisebb és biztonságosabb image-et szeretnél, érdemes megismerkedned a többlépcsős (multi-stage) buildekkel. Ennek lényege, hogy egy lépcsőben megépíted az alkalmazást (például lefordítod), egy másikban pedig csak a kész eredményt másolod át egy minimális image-be, a build eszközök nélkül. Ez egy haladóbb téma, amelyre egy külön cikkben térünk vissza, de a most tanult alapokra épül.
Összefoglalás
- A Dockerfile lépésről lépésre írja le, hogyan épüljön fel az image-ed.
- A legfontosabb utasítások:
FROM(alapimage),WORKDIR(munkakönyvtár),COPY(fájlmásolás),RUN(parancs buildkor),ENV(változók),EXPOSE(port),CMD/ENTRYPOINT(indítóparancs). - A
docker build -t név:tag .paranccsal építed meg az image-et. - A rétegek okos sorrendezésével (függőségek előre) kihasználod a cache-t, és gyorsabb lesz a build.
- A
.dockerignorefájllal kihagyod a felesleges fájlokat a build contextből.
Most már képes vagy saját image-et építeni, ez óriási lépés! A következő téma a több konténer együttes kezelése: ehhez olvasd el a Docker Compose bevezető cikket. Ha még az alapfogalmakban bizonytalan vagy, nézd át a Docker alapfogalmak kisszótárt, vagy térj vissza a Kezdő lépések oldalra.