Как сконфигурировать Docker и Docker Compose для Django приложения
Что проверяют
Понимаете ли вы разницу между «запустилось у меня» и конфигурацией, которую не стыдно выкатить: слои образа, секреты, готовность базы, статика. Следом обычно спрашивают, как вы запускаете миграции и чем dev-окружение отличается от прода.
Как отвечать
В Dockerfile:
- базовый образ:
python:3.12-slimили новее. ПеременныеPYTHONDONTWRITEBYTECODE=1иPYTHONUNBUFFERED=1, чтобы логи шли сразу; - кэш слоёв: сначала
COPY requirements.txtи установка зависимостей, потом код. Правка кода не переустанавливает пакеты; - сервер:
gunicorn project.wsgi:application --bind 0.0.0.0:8000, для ASGI с воркерами uvicorn.runserverтолько для разработки; - безопасность: непривилегированный пользователь,
.dockerignore, чтобы.git,.envиvenvне попали в образ; - статика:
collectstaticна сборке, отдача через WhiteNoise или nginx.
В compose.yaml:
- сервисы:
web,dbнаpostgres:17, при необходимостиredisи воркер Celery; - ключ
version: не нужен,docker composeего игнорирует и предупреждает об этом; - секреты: через
env_fileили переменные окружения, вsettings.pyчитаются изos.environ. Хост базы это имя сервисаdb, а неlocalhost; - готовность базы: у
dbhealthcheckнаpg_isready, уwebdepends_onсcondition: service_healthy; - данные: Postgres пишет в именованный том.
Миграции отдельной командой: docker compose run --rm web python manage.py migrate. Для разработки рядом кладут compose.override.yaml с bind mount кода и runserver, в проде его нет.
Где спотыкаются
Пишут depends_on без healthcheck и удивляются, что Django падает на старте: контейнер базы запущен, но Postgres ещё не принимает соединения.
Оставляют DEBUG=True, runserver и пароль открытым текстом в compose.yaml, который лежит в git.
Берут устаревшие образы вроде python:3.9 или postgres:13, у которых поддержка уже закончилась.