Docker for Python 2026-ban: A modern uv + többlépcsős építési útmutató
Nyissa meg bármelyik ötéves „Dockerize your Python app” oktatóanyagot, és ugyanazt a négy sort fogja megtalálni: „FROM python:3.11-slim”, „COPY requirements.txt .”, „RUN pip install -r requirements.txt”, „MÁSOLÁS”. .` Működik. Ezenkívül egy plusz 200 MB-os képfájlt is szállít, lassan újjáépít, mert minden függőségi telepítés egy teljes gyorsítótár, amely kihagyja azt a pillanatot, amikor az alkalmazáskód egy sora megváltozik, és csendesen behúzza a C-fordítót és a fejlécfájlokat, amelyekhez a futó tároló soha többé nem fog hozzányúlni a felépítés befejezése után.
Erre már nincs szükség. Az uv (az Astral Rust-alapú csomagkezelője és telepítője), a BuildKit gyorsítótár-csatlakozások és a disztribúció nélküli alapképek között az éles Python-tárolók 2026-os alapértelmezése egy többlépcsős összeállítás, amely csak egy Python-értelmezést, a virtuális környezetet és a kódot szállítja, semmi mást. Ez az útmutató végigvezeti a régi mintát, az új mintát és egy Docker-fájlt, amelyet ma egy valódi projektbe másolhat.
A régi minta, és miért drága
DOCKERFILEFROM python:3.13-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD ["python", "app.py"]
Ennek a mintának három költsége van, amelyek a projekt növekedésével együtt járnak. Először is, a python:3.13-slim' már nagyjából 150-200 MB-os tömörítéssel kerül kiszállításra, mielőtt egyetlen függőséget adna hozzá, mert a "slim" továbbra is hordozza a teljes Debian felhasználói területet, az apt-t és a Python szabványos könyvtár C-kiterjesztéseit. Másodszor, minden 'RUN pip install' réteget a Docker előző rétegek tartalomkivonata gyorsítótáraz, ezért az 'app.py' fájlban egy sor módosítása a 'COPY' előtt. A . semmit sem érvénytelenít, de a requirements.txt módosítása érvényteleníti a teljes telepítési lépést, és minden kereket újra letölt. Harmadszor, ha bármely függőséghez natív buildre van szükség (hiányzó manylinux kerék, szokatlan csomagváltozat), a pip csendben behúzza az összeépítési eszközöket, amelyek aztán örökre a végső képben maradnak, mert csak egy szakaszban kell kidobni.
Az új minta: uv builder szakasz plusz disztromentes végső fokozat
A javítás egy többlépcsős összeállítás: az egyik szakaszban van egy fordító, az uv és a zárfájl, és egy második, sokkal kisebb szakasz, amely csak a kész virtuális környezetet és a forrásfát másolja. Az utolsó szakasz soha nem lát pip, uv, apt vagy C fordítót.
DOCKERFILEFROM python:3.13-slim AS builder COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=never WORKDIR /app RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ uv sync --frozen --no-install-project --no-dev COPY . /app RUN --mount=type=cache,target=/root/.cache/uv uv sync --frozen --no-dev FROM gcr.io/distroless/python3-debian12 COPY --from=builder /app /app WORKDIR /app ENV PATH="/app/.venv/bin:$PATH" ENTRYPOINT ["/app/.venv/bin/python", "-m", "app"]
A gcr.io/distroless/python3-debian12 nem tartalmaz shellt, csomagkezelőt és pip-et, ami pontosan az, amit élesben szeretnél: nem marad semmi a tárolóban, amivel a kódfuttatást kapó támadó további eszközöket húzhat be. A végső kép a virtuális környezet webhelycsomagjaiból és a kódból áll, amely egy tipikus FastAPI-szolgáltatás esetén jóval 50 MB alá esik a plusz 200 MB helyett.
BuildKit gyorsítótár rögzítése: soha ne töltse le újra ugyanazt a kereket kétszer
A --mount=type=cache,target=/root/.cache/uv sor végzi itt az igazi munkát. Enélkül minden docker build egy friss futón újra letölt minden kereket a PyPI-ből, mert a réteggyorsítótár csak akkor marad fenn, ha az előző rétegek, beleértve a COPY uv.lock-ot is, bájt-azonosak. A BuildKit gyorsítótár-csatolás egy állandó kötet a réteggráfon kívül: fennmarad az ugyanazon a gazdagépen lévő buildek között, vagy a rendszerleíró adatbázis gyorsítótárának hátterével a CI-futók között, még akkor is, ha a zárolási fájl megváltozik. Párosítsa az "uv sync --frozen" paraméterrel, amely nem hajlandó megérinteni a zárolási fájlt, és hangosan meghibásodik, ha a pyproject.toml és az uv.lock nincs szinkronban, ahelyett, hogy csendben feloldana egy másik függőségi fát, mint amit a tesztek futtattak.
Az „uv sync --no-install-project” lépés szétválasztása az utolsó „uv sync”-től a trükk másik fele: az első hívás csak harmadik féltől származó függőséget telepít (gyorsítótárban, amíg az „uv.lock” nem változik), a második hívás pedig a „COPY” után fut. /app`, telepíti a saját projektjét anélkül, hogy újból hozzányúlna a harmadik féltől származó csomagokhoz. Módosítsa az alkalmazáskód egy sorát, és a függőségi réteg gyorsítótárban marad.
Natív függőségek: zsibbadás, párna és a manylinux probléma
Az olyan csomagok, mint a numpy és a Pillow ship előre beépített manylinux kerekeket a közös platformokhoz, így a "linux/amd64" vagy "linux/arm64" 'uv sync' rendszerint csak letölt egy kereket, és soha nem érinti meg a fordítót. A hibamód akkor jelenik meg, ha szokatlan architektúrát használ, egy nagyon új kiadást rögzít, mielőtt a kerekek felzárkóznának, vagy olyan csomagtól függ, amely csak forrásterjesztést szállít. Ebben az esetben az építő szakasznak összeállítási szerszámokra van szüksége, a végső szakasznak soha nem szabad látnia:
DOCKERFILEFROM python:3.13-slim AS builder RUN apt-get update && apt-get install -y --no-install-recommends build-essential \ && rm -rf /var/lib/apt/lists/* # uv + sync steps as in the stage above
A build-essential (gcc, make, libc fejlécek) csak az építő szakaszban él. A disztró nélküli végső szakasz a már lefordított .venv-et másolja, soha nem az azt létrehozó fordítót. Ha szeretné gyakorolni egy valódi konténeres szolgáltatás felépítését és szállítását a végpontokig, a FastAPI tanfolyam pontosan ezt a fajta API-t járja végig, az első végponttól a termelési formájú telepítésig.
UV által kezelt Python: álljon le attól függően, hogy az alapkép milyen értelmezőt kapott
A python:3.13-slim azt a javítási kiadást adja meg, amelyet a Debian azon a héten elhatározott. Az uv ehelyett magát a tolmácsot tudja kezelni: az uv python install 3.13.1 letölt egy adott, reprodukálható CPython buildet a python-build-standalone projektből, és rögzíti a .python-version-ban, így a fejlesztői szakasz és a laptop pontosan ugyanazt az értelmezőt futtatja a patch verzióig. A Dockerfile UV_PYTHON_DOWNLOADS=soha paraméterével kombinálva, így a rosszul rögzített verzió hangosan meghiúsítja a felépítést, ahelyett, hogy csendesen letöltene valami mást, ez bezárja a "működik a gépemen, meghibásodik a futón" rést, amelyet egy lebegő alapképcímke nyitva hagy.
Shell nélküli tároló hibakeresése
A distroless egyetlen valódi ára: nincs shell, így a docker exec -it container sh nem működik. Helyi hibakereséshez készítse el ugyanazt a Dockerfile-t egy olyan céllal, amely megáll az építési szakaszban (docker build --target=builder -t myapp:debug .), amely még mindig tartalmazza a python:3.13-slim teljes felhasználói területét és egy shellt. Tartsa távol ezt a hibakeresési célt a telepítési folyamatból; a terminálhoz létezik, nem a termeléshez.
Az egyfájlos sablon
DOCKERFILEFROM python:3.13-slim AS builder COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=never WORKDIR /app RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ uv sync --frozen --no-install-project --no-dev COPY . /app RUN --mount=type=cache,target=/root/.cache/uv uv sync --frozen --no-dev FROM gcr.io/distroless/python3-debian12 COPY --from=builder /app /app WORKDIR /app ENV PATH="/app/.venv/bin:$PATH" ENTRYPOINT ["/app/.venv/bin/python", "-m", "app"]
Másolja ki ezt, módosítsa az ENTRYPOINT' modul nevét, hogy megfeleljen a projekt elrendezésének, és olyan buildet kap, amely kisebb, gyorsabb az ismétlődő buildeknél, és nehezebb támadni, mint a pip install -r requirements.txt` minta, amelyet a legtöbb oktatóanyag még tanít. Készen áll az ebbe a tárolóba kerülő háttérrendszer gyakorlására? Kezdje a FastAPI-val.
GYIK
Engedélyeznem kell a BuildKit-et, hogy a gyorsítótár-csatlakozás működjön?
Igen, a --mount=type=cache csak BuildKit szolgáltatás. Ez volt az alapértelmezett építő a Docker Desktopban és a legutóbbi Docker Engine-kiadásokban, de régebbi CI-futók esetén előfordulhat, hogy a DOKER_BUILDKIT=1-et kifejezetten be kell állítani, vagy a docker buildx build-et a sima docker build' helyett.
Miért nem használja a python:3.13-alpine-t egy kisebb képhez?
Az Alpine musl libc-je megtöri a manylinux kerék feltételezését, amelyre a numpy, a Pillow és a legtöbb lefordított csomag támaszkodik, így elveszítjük az előre beépített kerekeket, és vagy forrásból fordítunk, vagy finom futásidejű hibákat találunk. A distroless-glibc elkerüli ezt a csapdát.
Az uv teljesen helyettesíti a pip-et és a Poetry-t?
A legtöbb új projekt esetében igen. Az uv gyorsabban oldja meg és telepíti, beolvassa ugyanazt a "pyproject.toml" fájlt, és létrehoz egy zárolási fájlt, de ha egy csapat már függ a Poetry beépülő moduloktól, vagy ha az uv még nem fedi le a munkafolyamatot, akkor nem kell sürgősen áttelepíteni a projekt közepén. Először próbálja ki az uv-t egy új szolgáltatáson.
Mi a teendő, ha az alapképemhez biztonsági javításra van szükség, miután már elkészítettem a lemezképet?
Újjáépíteni. Rögzítsen egy kivonatot, ne csak egy címkét a "python:3.13-slim"-hez az építési szakaszban, és ütemezett újraépítése a legtöbb csapat számára ésszerű, ha a javított alapkép belefolyik egy új buildbe, ahelyett, hogy hónapokig állna.
Használhatom ezt a mintát egy Django projekthez FastAPI helyett?
Igen, a Dockerfile-t nem érdekli, hogy melyik keretrendszert futtatja; csak az utolsó ENTRYPOINT változik (például gunicorn myproject.wsgi:application). A FastAPI tanfolyam egy gyors módja annak, hogy a mintát a végétől a végéig gyakorolja, ha új szolgáltatást indít.
Készen áll a disztrómentes gyártásra, vagy még kísérleti jellegű?
Széles körben használják a gyártásban; A Google tartja karban, és sok csapat alapértelmezett Python-bázisként szállítja. A belépés elfogadásának kompromisszuma a shell hiánya, amely szándékos biztonsági választás, nem hiba.