Dockerfile — это файл с инструкциями для создания Docker образа. Это основа современной контейнеризации приложений в DevOps практике.

Здесь найдешь пример Dockerfile для Django приложения, который использует актуальные практики: многоэтапная сборку, Poetry для управления зависимостями, и оптимизацию для продакшена.

Основные аспекты составления Dockerfile для Django

Многоэтапная сборка (Multi-stage build)

Использование нескольких этапов сборки позволяет создать оптимизированный финальный образ без лишних инструментов разработки.
Также, помещая в кэш отдельные слои, можно получить заметного ускорения финальной сборки. Например, Github это умеет делать почти из коробки.

Управление зависимостями через Poetry

Poetry — актуальный инструмент для управления Python зависимостями, который заменяет pip и requirements.txt.
Можно использовать uv, он теоретически может ускорить первичную сборку на несколько секунд.

Оптимизация запуска

Стоит собирать статические файлы, проводить базовую настройку, а также компилировать Python файлы. Это незначительно увеличивает размер образа, при этом позволяет заметно ускорить старт приложения. В нашем опыте время запуска сократилось с 45 секунд до 15.

Безопасность и оптимизация

Создание непривилегированного пользователя, минимизация размера образа и очистка кэша.

Сборка Dockerfile по шагам

Шаг 1: Подготовка базового образа Python (промежуточная версия)

# Подготовка среды
FROM python:3.13-slim-bullseye AS python

ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PIP_NO_CACHE_DIR=off \
    PIP_DISABLE_PIP_VERSION_CHECK=on \
    PIP_DEFAULT_TIMEOUT=30 \
    POETRY_NO_INTERACTION=1 \
    POETRY_VIRTUALENVS_IN_PROJECT=true \
    POETRY_HOME="/opt/poetry" \
    PYSETUP_PATH="/app" \
    VENV_PATH="/app/.venv" \
    POETRY_VERSION=2.1.3 \
    PIP_VERSION=25.1.1

ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"

RUN pip install -U "pip==$PIP_VERSION" "poetry==$POETRY_VERSION"

Что происходит:

  • FROM python:3.13-slim-bullseye — используем легковесный образ Python 3.13 на базе Debian Bullseye
  • PYTHONUNBUFFERED=1 — отключаем буферизацию вывода Python для лучшего логирования
  • PYTHONDONTWRITEBYTECODE=1 — не создаем .pyc файлы автоматически, бывает требуется для отдельных библиотек.
  • POETRY_VIRTUALENVS_IN_PROJECT=true — создаем виртуальное окружение внутри проекта
  • Устанавливаем Poetry версии 2.1.3 и pip 25.1.1 — стоит фиксировать мажорные версии, чтобы не удивиться одной ночью

Шаг 2: Этап сборки зависимостей (промежуточная версия)

# Подготовка сборки и установка зависимостей
FROM python AS python-build-stage

WORKDIR $PYSETUP_PATH

# Устанавливаем системные зависимости
RUN apt-get update && apt-get install --no-install-recommends -y --fix-missing \
  build-essential \
  libpq-dev \
  libffi-dev \
  libpcre3 \
  libpcre3-dev \
  gettext \
  htop \
  git \
  vim \
  python3-all-dev

# Копируем файлы зависимостей
COPY pyproject.toml poetry.lock ./

# Устанавливаем зависимости
RUN poetry install --without=dev --no-ansi

Что происходит:

  • Создаем отдельный этап для сборки зависимостей
  • Устанавливаем системные пакеты для компиляции Python модулей
  • libpq-dev — для работы с PostgreSQL
  • build-essential — компиляторы и инструменты сборки
  • Копируем только файлы зависимостей для лучшего использования Docker кэша
  • --without=dev — не устанавливаем зависимости для разработки

Шаг 3: Копирование проекта (промежуточная версия)

# Копируем файлы приложения, собираем, чистим кэш
FROM python AS python-run-stage

# Устанавливаем только runtime зависимости
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        libpq5 \
        libpq-dev \
  && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
  && rm -rf /var/lib/apt/lists/*

# Копируем зависимости из этапа сборки
COPY --from=python-build-stage $PYSETUP_PATH $PYSETUP_PATH

WORKDIR $PYSETUP_PATH

# Копируем код приложения
COPY ./ ${PYSETUP_PATH}

# Компилируем Python файлы
RUN python -m compileall . > /dev/null

# Создаем непривилегированного пользователя
RUN addgroup --system django \
    && adduser --system --ingroup django django

# Копируем код с правильными правами
COPY --chown=django:django . ${PYSETUP_PATH}

# Делаем django владельцем рабочей директории
RUN chown django:django ${PYSETUP_PATH}

USER django

# Собираем статические файлы
RUN export STATIC_MODE=True && python manage.py collectstatic --noinput

Что происходит:

  • Устанавливаем только runtime зависимости (без инструментов сборки)
  • Очищаем кэш apt для уменьшения размера образа
  • Копируем зависимости из этапа сборки
  • Компилируем Python файлы для ускорения запуска. Этот шаг безопасен и дает заметное ускорение старта.
  • Создаем пользователя django для безопасности
  • Собираем статические файлы Django

Шаг 4: Итоговая версия

######################################################
# Base Image
######################################################

FROM python:3.13-slim-bullseye AS python

ENV PYTHONUNBUFFERED=1 \
         PYTHONDONTWRITEBYTECODE=1 \
         PIP_NO_CACHE_DIR=off \
         PIP_DISABLE_PIP_VERSION_CHECK=on \
         PIP_DEFAULT_TIMEOUT=30 \
         POETRY_NO_INTERACTION=1 \
         POETRY_VIRTUALENVS_IN_PROJECT=true \
         POETRY_HOME="/opt/poetry" \
         PYSETUP_PATH="/app" \
         VENV_PATH="/app/.venv" \
         POETRY_VERSION=2.1.3 \
         PIP_VERSION=25.1.1

ENV PATH="$POETRY_HOME/bin:$VENV_PATH/bin:$PATH"

RUN pip install -U "pip==$PIP_VERSION" "poetry==$POETRY_VERSION"

######################################################
# Builder Image
######################################################
FROM python AS python-build-stage

WORKDIR $PYSETUP_PATH

# Install apt packages
RUN apt-get update && apt-get install --no-install-recommends -y --fix-missing \
  # dependencies for building Python packages
  build-essential \
  # psycopg2 dependencies
  libpq-dev \
  libffi-dev \
  libpcre3 \
  libpcre3-dev \
  gettext \
  htop \
  git \
  vim \
  python3-all-dev

# Requirements are installed here to ensure they will be cached.
# Create Python Dependency and Sub-Dependency Wheels.
COPY pyproject.toml poetry.lock ./

RUN poetry install --without=dev --no-ansi

######################################################
# Production image
######################################################
FROM python AS python-run-stage

# install required runtime dependencies, and cleanup cached files for a smaller layer
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
        # psycopg2 runtime dependencies
        libpq5 \
        libpq-dev \
  # cleaning up unused files
  && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
  && rm -rf /var/lib/apt/lists/*

# All absolute dir copies ignore workdir instruction. All relative dir copies are wrt to the workdir instruction
# copy python dependency wheels from python-build-stage
COPY --from=python-build-stage $PYSETUP_PATH $PYSETUP_PATH


WORKDIR $PYSETUP_PATH

# copy application code to WORKDIR
COPY ./ ${PYSETUP_PATH}

RUN python -m compileall . > /dev/null

RUN addgroup --system django \
    && adduser --system --ingroup django django

# copy application code to WORKDIR
COPY --chown=django:django . ${PYSETUP_PATH}

# make django owner of the WORKDIR directory as well.
RUN chown django:django ${PYSETUP_PATH}

USER django

RUN export STATIC_MODE=True && python manage.py collectstatic --noinput

Типичные ошибки при работе с Dockerfile

  1. Копирование всего проекта в начале — нарушает кэширование слоев (стоит часто обновляемые команды размещать ближе к концу)
  2. Использование root пользователя — создает уязвимости безопасности
  3. Неоптимизированные базовые образы — увеличивают размер и время сборки
  4. Отсутствие .dockerignore — копирование ненужных файлов
  5. Неиспользование многоэтапной сборки — финальный образ содержит лишние инструменты

Готов попробовать на практике?

Хочешь научиться не только создавать Dockerfile, но и решать реальные проблемы с контейнерами в продакшене? Наш тренажер поможет тебе отработать сценарии сбоев Docker контейнеров и научиться их быстро диагностировать. Это особенно важно для DevOps инженеров, которые работают с контейнеризацией.

В реальных проектах 70% времени уходит на диагностику проблем с контейнерами. Научись решать их быстро и эффективно.

Попробуй наши сценарии тренировок на странице /scenario — там есть специальные задания по работе с Docker, контейнерами и DevOps практиками.

FAQ

Какой размер у финального образа?

В примере используется образ на базе Debian (а не Alpine) и размер зависит от зависимостей, но обычно составляет 200-500 МБ. Многоэтапная сборка позволяет уменьшить размер на 30-50% по сравнению с одноэтапной.

Как добавить переменные окружения?

При использовании kubernetes, переменные вставляются при запуске контейнера через env, а если нужно установить прям во время сборки, используйте ENV в Dockerfile или передавайте через -e при запуске контейнера.

Нужно ли компилировать Python файлы?

Компиляция ускоряет запуск приложения на 10-50%, но (немного) увеличивает время сборки образа. Собираете приложение, как правило, один раз, а запускаете этот образ многократно. Это классическая DevOps практика оптимизации.