Docker pro Python v roce 2026: Moderní uv + průvodce vícestupňovou tvorbou
Otevřete jakýkoli pět let starý tutoriál „Dockerize your Python app“ a najdete stejné čtyři řádky: FROM python:3.11-slim, COPY requirements.txt ., RUN pip install -r requirements.txt, COPY . .. Funguje to. Dodává také bitovou kopii o velikosti 200 MB, přestavuje se pomalu, protože každá instalace závislosti je plná mezipaměť promeškaná ve chvíli, kdy se změní jeden řádek kódu aplikace, a tiše vtáhne kompilátor C a soubory záhlaví, kterých se váš běžící kontejner po dokončení sestavení už nikdy nedotkne.
Nic z toho už není potřeba. Mezi uv (správcem balíčků a instalačním programem založeným na Rustu od společnosti Astral), připojením mezipaměti BuildKit a základními obrazy distroless je výchozím nastavením 2026 pro produkční kontejner Pythonu vícefázové sestavení, které dodává pouze interpret Pythonu, vaše virtuální prostředí a váš kód, nic jiného. Tento průvodce prochází starým vzorem, novým vzorem a souborem Dockerfile, který můžete dnes zkopírovat do skutečného projektu.
Starý vzor a proč je drahý
DOCKERFILEFROM python:3.13-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD ["python", "app.py"]
Tento model má tři náklady, které se s rostoucím projektem skládají. Zaprvé, python:3.13-slim se již dodává se zhruba 150 až 200 MB komprimované před přidáním jediné závislosti, protože "slim" stále obsahuje úplnou uživatelskou oblast Debianu, apt a rozšíření C standardní knihovny Pythonu. Za druhé, každá vrstva RUN pip install je ukládána do mezipaměti pomocí hash obsahu předchozích vrstev Dockeru, takže změňte jeden řádek v app.py před COPY . . neruší nic upstream, ale změna requirements.txt zruší celý instalační krok a znovu stáhne každé kolo. Zatřetí, pokud nějaká závislost potřebuje nativní sestavení (chybějící manylinuxové kolečko, neobvyklá verze balíčku), pip tiše stáhne nástroje pro sestavení, které pak navždy zůstanou v konečném obrazu, protože existuje pouze jedna fáze, do které ji můžete zahodit.
Nový vzor: fáze UV builder plus závěrečná fáze bez distroly
Oprava je vícestupňová sestavení: jedna fáze, která má kompilátor, uv a váš lockfile, a druhá, mnohem menší fáze, která pouze kopíruje hotové virtuální prostředí a váš zdrojový strom. V závěrečné fázi nikdy nenajdete kompilátor pip, uv, apt nebo C.
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"]
gcr.io/distroless/python3-debian12 nemá žádný shell, správce balíčků ani pip, což je přesně to, co chcete v produkci: v kontejneru nezůstane nic, co by útočník, který získá spuštění kódu, mohl použít k natažení dalších nástrojů. Konečným obrazem jsou balíčky webů vašeho virtuálního prostředí plus váš kód, který pro typickou službu FastAPI přistane pod 50 MB místo 200 MB plus.
Připojení mezipaměti BuildKit: nikdy znovu nestahujte stejné kolo dvakrát
Skutečnou práci zde dělá řádek --mount=type=cache,target=/root/.cache/uv. Bez něj si každý docker build na novém runneru znovu stáhne každé kolo z PyPI, protože mezipaměť vrstvy přežije pouze v případě, že předchozí vrstvy, včetně COPY uv.lock, jsou bajtově identické. Připojení mezipaměti BuildKit je trvalý svazek mimo graf vrstvy: přetrvává napříč sestaveními na stejném hostiteli nebo, s backendem mezipaměti registru, mezi běžci CI, i když se změní soubor zámku. Spárujte to s uv sync --frozen, který se odmítá dotknout lockfile a hlasitě selže, pokud pyproject.toml a uv.lock nejsou synchronizované, namísto tichého vyřešení jiného stromu závislostí, než je ten, proti kterému běžely vaše testy.
Oddělení kroku uv sync --no-install-project od posledního uv sync je druhá polovina triku: první volání nainstaluje pouze závislosti třetích stran (uložené do mezipaměti, dokud se uv.lock nezmění) a druhé volání spusťte po COPY . /app, nainstaluje váš vlastní projekt, aniž byste se museli znovu dotýkat balíčků třetích stran. Změňte jeden řádek kódu aplikace a vrstva závislostí zůstane uložena v mezipaměti.
Nativní závislosti: numpy, polštář a mnoholinuxový problém
Balíčky jako numpy a Pillow dodávají mnoho linuxových kol pro běžné platformy, takže na linux/amd64 nebo linux/arm64 uv sync normálně jen stáhne kolo a nikdy se nedotkne kompilátoru. Režim selhání se objeví, když používáte neobvyklou architekturu, připnete zcela nové vydání, než se kola doženou, nebo když závisíte na balíčku, který dodává pouze zdrojovou distribuci. V takovém případě potřebuje fáze stavitele nástroje pro sestavení, konečná fáze nesmí nikdy vidět:
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
build-essential (hlavičky gcc, make, libc) žije pouze ve fázi tvůrce. Konečná fáze bez distribuce kopíruje již zkompilovanou .venv, nikdy kompilátor, který ji vytvořil. Pokud si chcete procvičit vytváření a přepravu skutečné kontejnerové služby od začátku do konce, kurz FastAPI projde přesně tímto druhem API, od prvního koncového bodu až po nasazení ve tvaru produkce.
uv-managed Python: zastavte se v závislosti na jakémkoli interpretu dodávaném základním obrazem
python:3.13-slim vám poskytne jakoukoli opravu, kterou se Debian rozhodl tento týden odeslat. uv může místo toho spravovat interpret sám: uv python install 3.13.1 stáhne konkrétní, reprodukovatelné sestavení CPythonu z projektu python-build-standalone a připne ho do .python-version, takže vaše fáze tvůrce a váš notebook spustí přesně stejný interpret až do verze opravy. V kombinaci s UV_PYTHON_DOWNLOADS=never v Dockerfile, takže špatně připnutá verze selže při sestavení nahlas místo toho, aby tiše stáhla něco jiného, zavře se tím mezera „funguje na mém počítači, selže na běžci“, kterou nechává plovoucí značka základního obrázku otevřenou.
Ladění kontejneru bez shellu
Jediná skutečná cena distroless: není tam žádný shell, takže docker exec -it container sh nefunguje. Pro místní ladění vytvořte stejný soubor Dockerfile s cílem, který se zastaví ve fázi tvůrce (docker build --target=builder -t myapp:debug .), který stále obsahuje úplnou uživatelskou zemi a shell python:3.13-slim. Udržujte tento cíl ladění mimo váš kanál nasazení; existuje pro váš terminál, ne pro výrobu.
Šablona s jedním souborem
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"]
Zkopírujte toto, změňte název modulu ENTRYPOINT tak, aby odpovídal rozvržení vašeho projektu, a budete mít sestavení, které je menší, rychlejší při opakovaných sestaveních a hůře napadnutelné než vzor pip install -r requirements.txt, který většina výukových programů stále učí. Jste připraveni procvičit backend, který jde do tohoto kontejneru? Začít s FastAPI.
Nejčastější dotazy
Potřebuji povolenou sadu BuildKit, aby připojení mezipaměti fungovalo?
Ano, --mount=type=cache je funkce pouze pro BuildKit. Byl výchozím tvůrcem v Docker Desktop a nedávných vydáních Docker Engine, ale na starších CI runnerech může být potřeba explicitně nastavit DOCKER_BUILDKIT=1 nebo docker buildx build místo prostého docker build.
Proč nepoužít python:3.13-alpine pro menší obrázek?
Alpine's musl libc porušuje předpoklad manylinuxových kol, na které spoléhají numpy, Pillow a většina zkompilovaných balíčků, takže ztratíte předem sestavená kola a buď kompilujete ze zdroje, nebo narazíte na jemné runtime chyby. distroless-glibc se této pasti vyhýbá.
Nahrazuje uv pip a poezii úplně?
U většiny nových projektů ano. uv řeší a instaluje rychleji, čte stejný pyproject.toml a generuje lockfile, ale pokud tým již závisí na zásuvných modulech Poetry nebo pracovní postup uv ještě nepokrývá, není naléhavá migrace uprostřed projektu. Nejprve vyzkoušejte UV na nové službě.
Co když můj základní obraz potřebuje bezpečnostní opravu poté, co jsem již vytvořil obraz?
Obnovit. Připněte výtah, ne jen značku, pro python:3.13-slim ve fázi sestavování a přestavbu podle plánu, týdenní je pro většinu týmů rozumné, takže opravený základní obraz přejde do nového sestavení místo toho, aby seděl celé měsíce zatuchlý.
Mohu použít tento vzor pro projekt Django místo FastAPI?
Ano, Dockerfile se nestará o to, který framework používáte; změní se pouze konečný VSTUP (například gunicorn myproject.wsgi:application). Kurz FastAPI je rychlý způsob, jak si procvičit vzor od začátku do konce, pokud spouštíte novou službu.
Je distroless výroba připravena, nebo je stále experimentální?
Je široce používán ve výrobě; Google jej udržuje a mnoho týmů jej dodává jako výchozí základnu Pythonu. Kompromisem za přijetí je absence shellu, což je záměrná bezpečnostní volba, nikoli chyba.