← Vissza a bloghoz Bevált gyakorlatok

Dockerfile bevált gyakorlatok: tippek profi image-ekhez

Réteg-sorrend a cache-ért, .dockerignore, konkrét tagek, nem-root felhasználó, kis alapképek. A legfontosabb Dockerfile bevált gyakorlatok egy helyen.

Egy Dockerfile megírása viszonylag könnyű, de egy Dockerfile megírása már igazi szakma. A különbség gyorsabb buildekben, kisebb image-ekben, jobb cache-kihasználásban és biztonságosabb konténerekben mutatkozik meg. Ebben a cikkben összegyűjtöttem a legfontosabb bevált gyakorlatokat, amelyeket érdemes minden projektnél alkalmazni. Mindegyikhez kapsz konkrét, copy-paste-elhető példát, hogy ne csak elméletben értsd, hanem rögtön használni is tudd.

1. Rendezd az utasításokat a cache miatt

A Docker rétegekben (layer) építi az image-et, és minden utasítás egy réteget hoz létre. A build során a Docker addig használja a cache-elt rétegeket, amíg egy utasítás vagy annak bemenete nem változik. Amint egy réteg megváltozik, az összes utána következő réteg újraépül.

A gyakorlati következmény: a ritkán változó dolgokat tedd előre, a gyakran változókat hátra. A függőségek telepítését válaszd külön a forráskód másolásától:

FROM node:22-slim

WORKDIR /app

# Ritkán változik -> jó cache-kihasználás
COPY package.json package-lock.json ./
RUN npm ci

# Gyakran változik -> csak ez épül újra kódmódosításkor
COPY . .

CMD ["node", "server.js"]

Ha a COPY . . előbb lenne, akkor minden kódmódosításkor újra lefutna az npm ci, ami feleslegesen lassítaná a buildet.

2. Vond össze a RUN utasításokat és takaríts utánuk

Minden RUN egy külön réteget hoz létre. Ha külön rétegben telepítesz csomagot és külön rétegben törlöd a cache-t, a törölt fájlok továbbra is ott maradnak egy korábbi rétegben — az image nem lesz kisebb. A megoldás: egyetlen RUN utasításban, &&-del láncolva telepíts és takaríts:

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        curl \
        ca-certificates && \
    rm -rf /var/lib/apt/lists/*

A --no-install-recommends elhagyja a felesleges ajánlott csomagokat, a rm -rf /var/lib/apt/lists/* pedig még ugyanabban a rétegben takarítja el az apt cache-t.

3. Használj .dockerignore fájlt

A .dockerignore fájl megakadályozza, hogy felesleges fájlok kerüljenek a build kontextusba (és ezzel az image-be). Ez gyorsítja a buildet és csökkenti a véletlen titokszivárgás kockázatát:

node_modules
.git
.env
*.log
dist
Dockerfile
.dockerignore
README.md

💡 Tipp: A .git mappa és a .env fájlok kihagyása nem csak méret-, hanem biztonsági kérdés is — ezekben gyakran lapulnak titkok vagy érzékeny adatok.

4. Rögzíts konkrét tageket, kerüld a latest-et

A FROM node:latest ma még működhet, de holnap egy teljesen más verzióra mutathat, és kiszámíthatatlanná teszi a buildjeidet. Mindig rögzíts konkrét verziót:

# Rossz: kiszámíthatatlan
FROM python:latest

# Jó: konkrét, reprodukálható
FROM python:3.12-slim

A maximális reprodukálhatóság kedvéért akár a digest-hez (SHA256) is kötheted az image-et, például FROM python:3.12-slim@sha256:.... Így garantáltan ugyanazt az alapképet kapod minden buildnél.

5. Válassz kis alapképet

Az alapkép mérete drámaian befolyásolja a végeredményt. Általában három szintet érdemes ismerni:

AlapképJellemző méretMikor?
debian / teljes100+ MBha sok rendszereszköz kell
*-slim30-80 MBáltalános, kompatibilis választás
*-alpine5-15 MBminimális, de musl libc
distrolessnéhány MBcsak a futtatáshoz, shell nélkül

Az alpine kicsi, de a glibc helyett musl libc-t használ, ami egyes csomagoknál kompatibilitási problémát okozhat. A -slim változatok jó kompromisszumot kínálnak. Ha pedig a lehető legkisebb és legbiztonságosabb image-et akarod, a distroless a befutó.

6. Ne futtasd root felhasználóként

Alapból a konténerek root felhasználóként futnak, ami felesleges kockázat. Hozz létre és válts egy nem-root felhasználóra:

FROM node:22-slim

WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .

# Nem-root felhasználó létrehozása és váltás
RUN useradd --create-home --shell /bin/bash appuser
USER appuser

CMD ["node", "server.js"]

Sok hivatalos image már tartalmaz egy beépített nem-root felhasználót (például a node image-ben a node felhasználó), így gyakran elég egy USER node sor.

⚠️ Figyelem: A USER váltás után a COPY által írt fájlok tulajdonjogára is figyelj. Használhatod a COPY --chown=appuser:appuser . . formát, hogy a fájlok rögtön a megfelelő felhasználóé legyenek.

7. Egy konténer, egy folyamat

A konténerek filozófiája szerint egy konténer ideális esetben egyetlen fő folyamatot futtat. Ne pakold ugyanabba a konténerbe a webszervert, az adatbázist és a cache-t. Bontsd külön őket, és kösd össze a szolgáltatásokat. Ehhez a Docker Compose bevezető ad jó kiindulópontot. Így könnyebb skálázni, frissíteni és hibát keresni.

8. COPY-t használj ADD helyett

Az ADD utasítás többet tud (URL-ek letöltése, tömörített fájlok automatikus kicsomagolása), de pont emiatt kevésbé kiszámítható és kockázatosabb. A bevett szabály: használj COPY-t, hacsak nincs konkrét szükséged az ADD extra funkcióira:

# Egyszerű, kiszámítható
COPY app.jar /app/app.jar

9. Aknázd ki a multi-stage buildet

A build eszközöknek nincs helyük a végső image-ben. A multi-stage build segítségével a fordítást egy “buildelő” fázisban végzed, majd csak a kész artefaktumot viszed át a minimális futtató image-be. Ez gyakran tört részére csökkenti a méretet. Erről részletesen írtam a Multi-stage build cikkben — érdemes elolvasni, mert szinte minden komolyabb projektben hasznos.

10. Adj hozzá HEALTHCHECK-et

A HEALTHCHECK segít az orchestrátornak (vagy a Compose-nak) eldönteni, hogy a konténer valóban egészséges-e, nem csak fut:

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
    CMD curl -f http://localhost:8080/health || exit 1

Az --interval az ellenőrzések gyakorisága, a --timeout a megengedett válaszidő, a --retries pedig hány sikertelen próba után minősül a konténer beteggé. Ezután a docker ps kimenetében látszik az állapot (healthy/unhealthy).

Egy összerakott példa

Lássuk, hogyan néz ki sok tipp együtt, egy tipikus Node.js alkalmazásnál:

FROM node:22-slim

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci --omit=dev && npm cache clean --force

COPY --chown=node:node . .

USER node

EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD node healthcheck.js || exit 1
CMD ["node", "server.js"]

Összefoglalás

A jó Dockerfile néhány következetesen alkalmazott szabályon múlik: rendezd az utasításokat a cache miatt, vond össze és takaríts a RUN-okban, használj .dockerignore-t, rögzíts konkrét tageket, válassz kis alapképet, futtass nem-root felhasználóként, tarts egy folyamatot konténerenként, használj COPY-t, aknázd ki a multi-stage buildet, és adj hozzá HEALTHCHECK-et. Ezekkel az image-eid gyorsabbak, kisebbek és biztonságosabbak lesznek.

Most pedig nyisd meg a saját Dockerfile-odat, és nézd át pontról pontra! Ha még az alapokat csiszolnád, kezdd a Kezdő lépések útmutatóval, vagy ha még nem telepítetted a Dockert, a Telepítés oldal segít elindulni.