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 BullseyePYTHONUNBUFFERED=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
— для работы с PostgreSQLbuild-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
- Копирование всего проекта в начале — нарушает кэширование слоев (стоит часто обновляемые команды размещать ближе к концу)
- Использование root пользователя — создает уязвимости безопасности
- Неоптимизированные базовые образы — увеличивают размер и время сборки
- Отсутствие .dockerignore — копирование ненужных файлов
- Неиспользование многоэтапной сборки — финальный образ содержит лишние инструменты
Готов попробовать на практике?
Хочешь научиться не только создавать Dockerfile, но и решать реальные проблемы с контейнерами в продакшене? Наш тренажер поможет тебе отработать сценарии сбоев Docker контейнеров и научиться их быстро диагностировать. Это особенно важно для DevOps инженеров, которые работают с контейнеризацией.
В реальных проектах 70% времени уходит на диагностику проблем с контейнерами. Научись решать их быстро и эффективно.
Попробуй наши сценарии тренировок на странице /scenario — там есть специальные задания по работе с Docker, контейнерами и DevOps практиками.
FAQ
Какой размер у финального образа?
В примере используется образ на базе Debian (а не Alpine) и размер зависит от зависимостей, но обычно составляет 200-500 МБ. Многоэтапная сборка позволяет уменьшить размер на 30-50% по сравнению с одноэтапной.
Как добавить переменные окружения?
При использовании kubernetes, переменные вставляются при запуске контейнера через env
, а если нужно установить прям во время сборки, используйте ENV
в Dockerfile или передавайте через -e
при запуске контейнера.
Нужно ли компилировать Python файлы?
Компиляция ускоряет запуск приложения на 10-50%, но (немного) увеличивает время сборки образа. Собираете приложение, как правило, один раз, а запускаете этот образ многократно. Это классическая DevOps практика оптимизации.