Image-méret optimalizálás: a kisebb image gyorsabb és biztonságosabb
Egy 1 GB-os image lassan utazik és nagyobb a támadási felülete. Megnézzük, hogyan zsugorítsd az image-eidet alapkép-választással, rétegtisztítással és multi-stage buildel.
Az image-méret könnyen olyan dolognak tűnik, amivel nem érdemes foglalkozni — elvégre a tárhely olcsó, és úgyis fut a konténer. A valóságban azonban a túlméretezett image-ek minden nap apró adót szednek tőled: lassabb deploy, lassabb skálázódás, magasabb tárhelyköltség és nagyobb támadási felület. Egy 1 GB-os image lassan utazik a hálózaton, és sokkal több olyan szoftvert tartalmaz, amiben sebezhetőség rejtőzhet. Ebben a cikkben végigvesszük a legfontosabb technikákat, amelyekkel reálisan tört részére zsugoríthatod az image-eidet — anélkül, hogy bármi lényegeset elveszítenél.
Miért számít a méret?
Mielőtt a hogyanba belevágunk, nézzük meg, miért éri meg az erőfeszítés:
- Gyorsabb pull és push: minden deploy, CI futás és skálázás egy image letöltésével kezdődik. A kisebb image gyorsabban érkezik.
- Gyorsabb indulás: a kisebb image hamarabb áll készen, ami autoscaling és gyors helyreállítás esetén kulcsfontosságú.
- Kevesebb tárhely: a registry-ben és a node-okon is kevesebb helyet foglal, ami pénzben is mérhető.
- Kisebb támadási felület: kevesebb csomag = kevesebb potenciális sebezhetőség. Egy fordító, egy shell vagy egy felesleges könyvtár mind kockázat.
💡 Tipp: A méretoptimalizálás és a biztonság gyakran kéz a kézben jár. Amikor kidobsz egy felesleges build eszközt, egyszerre csökkented a méretet és a támadási felületet is.
1. Válassz okosan alapképet
Az alapkép a legnagyobb egyetlen tényező az image méretében. Ugyanaz az alkalmazás drámaian eltérő méretű lehet a választott alapkép szerint:
| Alapkép | Tipikus méret |
|---|---|
ubuntu:24.04 | ~78 MB |
python:3.12 | ~1 GB |
python:3.12-slim | ~130 MB |
python:3.12-alpine | ~50 MB |
node:22 | ~1,1 GB |
node:22-slim | ~240 MB |
gcr.io/distroless/static | ~2 MB |
Három fő irány közül választhatsz:
- slim: a teljes image lecsupaszított változata, glibc-vel. Jó kompromisszum, kevés meglepetéssel.
- alpine: rendkívül kicsi, de musl libc-t használ, ami egyes natív kiterjesztéseknél (pl. Python wheel-ek) kompatibilitási vagy fordítási gondot okozhat.
- distroless: csak a futtatáshoz szükséges minimum, shell és csomagkezelő nélkül. A legkisebb és legbiztonságosabb, de a hibakeresés benne nehezebb, mert nincs shell.
Nincs egyetlen helyes válasz: az alpine kicsi, de néha extra fordítási munkát igényel; a slim biztonságos alapértelmezés; a distroless a végső optimalizáláshoz ideális, főleg fordított nyelveknél.
2. Távolítsd el a build függőségeket
Sok image azért hízik fel, mert a fordításhoz szükséges fejlesztői csomagok (build-essential, gcc, fejlécfájlok) benne maradnak. Ha mindenképpen egyetlen fázisban dolgozol, akkor a build függőségeket telepítsd, használd, majd távolítsd el — mindezt egyetlen rétegben:
RUN apt-get update && \
apt-get install -y --no-install-recommends build-essential && \
pip install --no-cache-dir -r requirements.txt && \
apt-get purge -y --auto-remove build-essential && \
rm -rf /var/lib/apt/lists/*
A --no-cache-dir a pip esetében megakadályozza a letöltött csomagok cache-elését, a purge --auto-remove pedig eltakarítja a build eszközöket a telepítés után.
3. Takaríts ugyanabban a rétegben
Ez az egyik leggyakoribb hiba. A Docker rétegei “csak hozzáadó” jellegűek: ha egy korábbi rétegbe bekerült egy fájl, akkor egy későbbi rétegben való törlése nem teszi kisebbé az image-et — a fájl ott marad a korábbi rétegben. Ezért mindig ugyanabban a RUN utasításban telepíts és takaríts:
# Rossz: a cache külön rétegben marad, az image nem kisebb
RUN apt-get update && apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
# Jó: minden egy rétegben
RUN apt-get update && apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
4. Használj .dockerignore fájlt
A build kontextus minden fájlja potenciálisan az image-be kerülhet egy COPY . . során. A .dockerignore megakadályozza a felesleges fájlok bemásolását:
node_modules
.git
.env
*.log
coverage
dist
tmp
Ez nem csak méretet spórol, hanem gyorsítja a build kontextus feltöltését a Docker daemonhoz, és csökkenti a véletlen titokszivárgás kockázatát is.
5. Aknázd ki a multi-stage buildet
A legnagyobb dobás szinte minden esetben a multi-stage build. A build eszközöket egy külön fázisban tartod, és csak a kész artefaktumot viszed át a minimális futtató image-be:
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o app .
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app/app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]
Ezzel egy 800 MB-os Go image akár 15 MB-ra is csökkenhet. A részleteket a Multi-stage build cikkben fejtem ki bővebben, sok példával.
6. Vizsgáld meg, mi van az image-edben
Optimalizálni csak azt tudod, amit látsz. Először nézd meg a méreteket:
docker images
docker history myapp:latest
A docker history rétegenként megmutatja, melyik utasítás mennyi helyet foglal — így rögtön kiderül, hol hízik az image. Még részletesebb betekintést ad a dive nevű eszköz, amely interaktívan, rétegenként mutatja a fájlokat és a pazarlást:
dive myapp:latest
A dive-val pontosan látod, melyik réteg mekkora, mennyi a redundáns vagy felesleges tartalom, és milyen “wasted space” keletkezett. Ez aranyat ér, ha egy konkrét image-et akarsz lefogyasztani.
⚠️ Figyelem: Ne ess túlzásba az alpine-nal csak a méret kedvéért. Ha egy natív függőség folyamatosan fordítási hibákat dob musl libc alatt, gyakran jobban jársz egy
-slimimage-dzsel — a néhány tíz megabájt megéri a nyugalmat.
Egy reális optimalizálási folyamat
Ha egy meglévő, túlméretezett image-et akarsz lefogyasztani, érdemes ezt a sorrendet követni:
- Futtasd a
docker historyvagydiveparancsot, és azonosítsd a legnagyobb rétegeket. - Cseréld le az alapképet egy
-slimvagyalpineváltozatra, és teszteld, hogy minden működik-e. - Vezess be
.dockerignorefájlt. - Vond össze a
RUNutasításokat, és takaríts a cache-ek után ugyanabban a rétegben. - Vezesd be a multi-stage buildet, és tedd a build eszközöket külön fázisba.
- Mérj újra, és ismételd, amíg elégedett nem vagy.
Összefoglalás
A kisebb image gyorsabban utazik, hamarabb indul, kevesebb helyet foglal és biztonságosabb. A legfontosabb fogások: válassz okosan alapképet (slim, alpine vagy distroless), távolítsd el a build függőségeket, takaríts ugyanabban a rétegben, használj .dockerignore-t, és aknázd ki a multi-stage buildet. A docker history és a dive segít megtalálni, hol pazarolsz helyet.
Vedd elő a legnagyobb image-edet még ma, futtasd rajta a dive parancsot, és kezdj el faragni! Ha még az alapoknál tartasz, nézd meg, hogyan működik a Docker, vagy frissítsd fel a tudásod a Dockerfile írása lépésről lépésre cikkel.