Optymalizacja obrazów Docker dla Python: redukcja rozmiaru o 43–57%
Wieloetapowe budowanie i obrazy slim Python pozwalają zmniejszyć rozmiar obrazu runtime z 895 MB do 508 MB (-43%). Czas budowania po zmianach kodu spada z 56 do 16 sekund. Przyspiesza to wdrożenia w Kubernetes, oszczędza przestrzeń dyskową i ruch sieciowy.
Optymalizacja rozwiązuje kluczowe problemy: szybkie uruchamianie podów przy skokach obciążenia, redukcję opóźnień dla użytkowników. Zależności zarządzane są przez Poetry, testy wykonywane na etapie budowania.
.dockerignore i obrazy slim
Wyklucz testy i niepotrzebne pliki przez .dockerignore. Testy są potrzebne tylko na etapie budowania.
Przejdź na python:3.13-slim-bookworm. Pełny obraz dodaje setki MB.
Wyłącz cache pip/Poetry flagami:
- pip:
--no-cache-dir - Poetry:
poetry cache clear --all pypi
Wieloetapowe budowanie: analiza Dockerfile
Etap builder instaluje Poetry, zależności, uruchamia pytest. Etap runtime kopiuje tylko site-packages, pliki binarne (gunicorn, uvicorn) i kod.
# Etap builder
FROM python:3.13-slim-bookworm AS builder
ENV PYTHONUNBUFFERED=1 \
LANG=C.UTF-8 \
PYTHONDONTWRITEBYTECODE=1
RUN apt-get update -qq && \
apt-get install -y --no-install-recommends \
curl \
gcc \
libc-dev \
&& pip install --no-cache-dir 'poetry==2.3.2' \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
WORKDIR /code
COPY pyproject.toml poetry.lock* ./
RUN poetry config virtualenvs.create false \
&& poetry install --no-root --no-dev --no-interaction --no-ansi \
&& poetry cache clear --all pypi --no-interaction || true \
&& rm -rf ~/.cache/pip
COPY . .
RUN pytest
# Etap runtime
FROM python:3.13-slim-bookworm
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
LANG=C.UTF-8
WORKDIR /code
COPY --from=builder /usr/local/lib/python3.13/site-packages /usr/local/lib/python3.13/site-packages
COPY --from=builder /usr/local/bin/gunicorn /usr/local/bin/gunicorn
COPY --from=builder /usr/local/bin/uvicorn /usr/local/bin/uvicorn
COPY --from=builder /code /code
Wyniki podstawowej optymalizacji:
| Metryka | Przed | Po | Zmiana |
|---------|------|-------|-----------|
| Rozmiar obrazu, MB | 894.84 | 508 | -43% |
| Czas budowania od zera, s | 58 | 315 | +443% |
| Czas budowania po zmianach, s | 56 | 16 | -71% |
Pierwsze budowanie jest wolniejsze z powodu warstw builder, ale cache przyspiesza iteracje.
Zaawansowane metody: Chainguard i analiza ręczna
Obrazy Chainguard
Chainguard wyklucza shell, apt/apk, minimalizując powierzchnię ataku. Brak CVE w obrazach bazowych. Oszczędność: 50–150 MB.
Wady:
- Debugowanie bez shell
- Darmowy tylko tag latest
- Płatne — drogie
Nadaje się do projektów high-security.
Analiza ręczna z dive
Analizuj warstwy:
docker history --format "{{.CreatedBy}}: {{.Size}}" image:tag
docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock wagoodman/dive:latest image:tag
Skup się na dużych warstwach w runtime. Zwijaj katalogi (Shift+Space), usuwaj niepotrzebne libs. Wymaga doświadczenia z Linux, rzadko się opłaca.
Optymalizacja ekstremalna: scratch
Runtime na scratch — kopiuj tylko wymagane libc. Rozmiar spada do 384 MB (-57% od początkowego, -24% od multi-stage).
Wady:
- Debugowanie niemożliwe
- Nowe deps wymagają ręcznego dodawania libs
- Czas na debugowanie: 1+ godzina
Aktualne dla tysięcy podów, Serverless (Knative, Fargate). W Python trudniejsze niż w Go.
Porównanie rozmiarów:
- Bez multi-stage: 894 → 384 MB (-57%)
- Multi-stage: 508 → 384 MB (-24%)
Optymalizacja czasu budowania
Kopiuj pyproject.toml/poetry.lock PRZED kodem:
- COPY pyproject.toml poetry.lock* ./
- RUN poetry install
- COPY . .
- RUN pytest
Cache zależności jest zachowany przy zmianach kodu. Przyspieszenie: 58 → 14 s (x4).
Co jest ważne
- Multi-stage + slim: -43% rozmiaru, -71% czasu iteracji.
- .dockerignore + no-cache: wyklucza testy i cache z runtime.
- Kolejność COPY: zależności cache'owane oddzielnie od kodu.
- Scratch: -57%, ale dla ekstremalnych przypadków (tysiące podów).
- Chainguard/dive: dla bezpieczeństwa i precyzyjnego dostrojenia.
— Editorial Team
Brak komentarzy.