Docker Django

Текущая экосистема разработки программного обеспечения быстро развивается, и кажется, что старые фреймворки, такие как Django или Rails, серьезно устарели, но это абсолютно не так! Django — один из уникальных фреймворков, который нам нравится использовать прежде всего потому, что он содержит в себе вообще все, и настраивается при помощи нескольких простых конфигураций.

Допустим, вы хотите создать простую панель администратора на основе существующей БД и уже предопределенных моделей. Даже если проект написан на Node.js или Go, для развертывания базовой панели администратора можно всегда использовать Django, так как здесь не требуется создание пользовательского интерфейса, только простые конфигурации БД и Python.

С другой стороны, Django дает большую гибкость и простоту в создании конечных точек API, особенно после выхода Django Graphene. Мы только что сделали наш полный API с Django и GraphQL на сайте https://treescale.com. Сопровождение кода стало намного проще и гибче.

Docker вместе с Django

Обычно для запуска приложений Python используется виртуальная среда (Virtualenv). Например, если вы хотите иметь несколько версий Python или несколько версий какой-то определенной библиотеки, вам нужно запускать их в своих собственных виртуальных средах. С Docker все стало несколько проще, потому что сам Docker — это совершенно другая среда и файловая система со всеми ее библиотеками, и из-за этого экосистема Python приняла ее в числе первых.

Запуск Django внутри Docker — это настоящий прорыв, особенно когда речь идет о реальных развертываниях DevOps или о простоте управления ресурсами. Так что, нравится вам это или нет, запускать Django внутри контейнера Docker лучше, чем пытаться настроить его с помощью Virtualenv и управлять передачей кода отдельно.

Начало работы

Само приложение Django — это просто хорошо структурированный файл Python с единственной точкой входа. Остальные функции, такие как сама структура Django, хранятся в каталоге пакетов Python. Обычно при создании проектов Python в соответствии с передовыми практиками вы создаете файл requirements.txt для управления пакетами и их версиями через pip.

Скорее всего, ваш файл requirements.txt похож на этот:

django==3.0.6
graphene-django==2.10.0
psycopg2===2.8.5
django-graphql-jwt==0.3.1
requests==2.23.0
django-cors-headers==3.2.1

Такой файл у нас есть в одном из проектов Django и он весьма прост. Основной идеей здесь является сохранение определенных версий библиотек, в противном случае вы можете испортить сборку Docker и выполнение проекта в целом. Иногда пакеты обновляются с некоторыми критическими изменениями, и пока они находятся в вашей локальной среде разработки, вы не видите никаких проблем с этим, но при попадании в сборку Docker они могут дать сбой. Мы это видели и, поверьте, это совсем не весело!

Ключевой идеей наличия файла requirements.txt является возможность автоматизации процесса установки Dockerfile. В противном случае вам будет сложно вспомнить, какой именно пакет используется в вашем проекте для предоставления сценария установки поверх сборки Docker.

Очень простой файл сборки Docker выглядит примерно так:

FROM python:3-alpine
ADD . /api
WORKDIR /api 
# You will need this if you need PostgreSQL, otherwise just skip this
RUN apk update && apk add postgresql-dev gcc python3-dev musl-dev libffi-dev
RUN pip install -r requirements.txt
EXPOSE 8000
CMD ["./manage.py", "runserver"]

Это создаст базовый образ Docker со сценарием запуска. По умолчанию команда ./manage.py runserverиспользуется для запуска сервера разработки Django.

UWSGI для запуска приложений

Запуск Django в реальной среде может быть сложной задачей, если вы не знаете конкретных инструментов, специально разработанных для выполнения серверных приложений Python. Одним из лучших серверов Python является UWSGI, на котором работают мощные серверы Pinterest и Dropbox.

UWSGI — это, по сути, поддерживающий параллельные вычисления сервер Python, который обрабатывает общие HTTP-запросы, и, используя собственный сетевой протокол, основанный на событиях, имитирует обработку соединения, в то время как Django успевает ответить на этот запрос. Это очень похоже на принцип обработки запросов в Node.js и дает вашему приложению Django потрясающую возможность обрабатывать даже несколько тысяч запросов в секунду.

Простой файл сборки Docker с сервером UWSGI выглядит так:

FROM python:3-alpine
ADD . /api
WORKDIR /api
# You will need this if you need PostgreSQL, otherwise just skip this
RUN apk update && apk add postgresql-dev gcc python3-dev musl-dev libffi-dev
RUN pip install -r requirements.txt
# Installing uwsgi server
RUN pip install uwsgi
EXPOSE 8000
# This is not the best way to DO, SEE BELOW!!
CMD uwsgi --http "0.0.0.0:8000" --module api.wsgi --master --processes 4 --threads 2

Как видите, вы можете запустить свой сервер Django, просто указав модуль приложения, например api.wsgi, если имя вашего приложения — api! Надо заметить, что существует определенная конфигурация для количества запущенных процессов и для количества потоков для одного процесса.

Обычно не принято писать такие большие команды конфигурации внутри самого файла сборки Docker. С этой целью создается файл с именем runner.sh внутри корневого каталога и в него добавляется все, что нам нужно для запуска реального приложения Django. Например, запуск заранее предопределенных миграций или что-то еще, по мере необходимости.

#!/usr/bin/env sh
# Getting static files for Admin panel hosting!
./manage.py collectstatic --noinput
uwsgi --http "0.0.0.0:${PORT}" --module api.wsgi --master --processes 4 --threads 2

Обратите внимание, как мы указываем фактический порт для запуска сервера Django в качестве переменной среды, чтобы им можно было управлять через среду выполнения Docker.

Итак, окончательный файл среды Docker будет выглядеть вот так:

FROM python:3-alpine
ADD . /api
WORKDIR /api
# You will need this if you need PostgreSQL, otherwise just skip this
RUN apk update && apk add postgresql-dev gcc python3-dev musl-dev libffi-dev
RUN pip install uwsgi
RUN pip install -r requirements.txt
ENV PORT=8000
EXPOSE 8000
# Runner script here
CMD ["/api/runner.sh"]

После создания этого образа Docker вы получите самый простой и эффективный сервер Django для работы в продакшене, который будет выдерживать значительные нагрузки!

Что же дальше?

Это просто конфигурация сервера Django, но у вас также будут и другие микросервисы, взаимодействующие с ним. Вот где нам пригодятся конфигурации Docker! Таким образом удобно настраивать сервисы Docker Compose. Как, например, этот сервер API Django с экземпляром докера PostgreSQL внутри той же сетевой группы, что и связанные с ним контейнеры. Необходимо, чтобы он не был публично доступен с сервера, но Django мог бы связываться с экземпляром базы данных PostgreSQL по базовой сетевой ссылке. Даже когда вы запускаете кластер Kubernetes, вы можете просто делать почти то же самое с помощью сервисов Kubernetes… Как бы то ни было! Мы можем много говорить о преимуществах установки контейнера Docker практически для любого приложения, но целью этой статьи было показать самую простую конфигурацию образа Docker, способную запускать почти все версии Django, поддерживающие серверы WSGI.

До новых встреч, следите за обновлениями!