Как создать приложение Django и Gunicorn с помощью Docker

Вступление

Django - это мощный веб-фреймворк, который может помочь вам быстро запустить приложение Python. Он включает несколько удобных функций, таких как object-relational mapper, аутентификацию пользователя и настраиваемый административный интерфейс для вашего приложения. Он также включает в себя caching framework и поощряет чистый дизайн приложения через его https://docs.djangoproject.com/en/2.1/topics/http. / urls / [URL Dispatcher] и Template system.

В этом руководстве вы узнаете, как создать масштабируемое и переносимое приложение Django Polls с контейнерами Docker. Из коробки, приложению Django требуется несколько модификаций для эффективной работы внутри контейнеров, например, регистрация в стандартных выходных потоках и конфигурирование себя с помощью переменных среды, передаваемых в контейнер. Кроме того, выгрузка статических ресурсов, таких как таблицы стилей JavaScript и CSS, в хранилище объектов позволяет упростить и централизовать управление этими файлами в многоконтейнерной среде.

Вы реализуете эти модификации, основанные на методологии Twelve-Factor, для создания масштабируемых облачных веб-приложений - на примере Django https://github.com/do-community/ django-polls [Опросы] приложение. Затем вы создадите образ приложения и запустите контейнерное приложение с помощью Docker.

К концу этого учебного курса вы настроите контейнер в https://www.digitalocean.com/community/tutorials/how-to-set-up-a-scalable-django-app-with-digitalocean-managed в контейнере. базы данных и пробелы [Как настроить масштабируемое приложение Django]. В последующих руководствах этой серии вы узнаете, как использовать Docker Compose для связывания контейнера Django с обратным прокси-сервером Nginx и развертывания этой архитектуры в кластере Kubernetes.

Настоятельно рекомендуется изучить руководство, чтобы понять, какие изменения вы вносите в приложение, но если вы хотите пропустить его, вы можете получить измененный код по адресу https://github.com/do-community/. django-polls / tree / polls-docker [ветвь polls-docker] репозитория GitHub приложения Опросы.

Предпосылки

Чтобы следовать этому руководству, вам понадобится:

  • Сервер Ubuntu 18.04, настроенный в соответствии с этим Initial Руководством по установке сервера.

  • Docker установлен на вашем сервере, следуя шагам 1 и 2 Как установить и Используйте Docker в Ubuntu 18.04. Убедитесь, что вы добавили своего пользователя в группу + docker +, как описано в шаге 2.

  • Https://www.digitalocean.com/products/spaces/[DigitalOcean Space] для хранения статических файлов вашего проекта Django и набора ключей доступа для этого пространства. Чтобы узнать, как создать пространство, обратитесь к документации по продукту How to Create Spaces. Чтобы узнать, как создавать ключи доступа для пространств, обратитесь к Sharing Access to Spaces with Keys Access. С небольшими изменениями вы можете использовать любую S3-совместимую службу хранения объектов.

  • Управляемый DigitalOcean кластер PostgreSQL. Чтобы узнать, как создать кластер, обратитесь к документации по DigitalOcean Managed Databases. С небольшими изменениями вы можете использовать любую базу данных, которую поддерживает Django.

Шаг 1 - Создание базы данных PostgreSQL и пользователя

Для начала мы подключимся к серверу PostgreSQL из экземпляра Ubuntu. Затем мы создадим базу данных PostgreSQL и пользователя для приложения Django и настроим базу данных для эффективной работы с Django.

Прежде чем мы подключимся к базе данных с нашего компьютера с Ubuntu (не с контейнера приложения), нам нужно установить пакет + postgresql-client + из репозиториев Ubuntu. Сначала обновите локальный индекс пакета + apt +, а затем загрузите и установите пакет:

sudo apt update
sudo apt install postgresql-client

Нажмите + Y +, а затем + ENTER +, когда будет предложено начать загрузку и установку пакетов.

Теперь, когда вы установили клиент, мы будем использовать его для создания базы данных и пользователя базы данных для нашего приложения Django.

Чтобы начать, возьмите * Параметры соединения * для своего кластера, перейдя к * Базы данных * на Cloud Control Panel и щелкнув по своей базе данных. Вы должны увидеть окно * Сведения о соединении *, содержащее * параметры соединения * для вашего кластера. Запишите это вниз.

Вернитесь в командную строку, войдите в свой кластер, используя эти учетные данные и клиент + psql + PostgreSQL, который мы только что установили:

psql -U username -h host -p port -d database -set=sslmode=require

При появлении запроса введите пароль, отображаемый рядом с именем пользователя Postgres, и нажмите + ENTER +.

Вам будет предложено приглашение PostgreSQL, из которого вы сможете управлять базой данных.

Сначала создайте базу данных для вашего проекта с именем + polls +:

CREATE DATABASE polls;

Теперь мы можем переключиться на базу данных + polls +:

\c polls;

Далее создайте базу данных пользователя для проекта. Убедитесь, что вы выбрали безопасный пароль:

CREATE USER  WITH PASSWORD '';

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

Мы устанавливаем кодировку по умолчанию на + UTF-8 +, что ожидает Django. Мы также устанавливаем схему изоляции транзакции по умолчанию «read commit», которая блокирует чтение из незафиксированных транзакций. Наконец, мы устанавливаем часовой пояс. По умолчанию наши проекты Django будут настроены на использование + UTC. Это все рекомендации из https://docs.djangoproject.com/en/2.0/ref/databases/#optimizing-postgresql-s-configuration так же самого проекта Django].

Введите следующие команды в приглашении PostgreSQL:

ALTER ROLE  SET client_encoding TO 'utf8';
ALTER ROLE  SET default_transaction_isolation TO 'read committed';
ALTER ROLE  SET timezone TO 'UTC';

Теперь мы можем предоставить нашему новому пользователю доступ для администрирования нашей новой базы данных:

GRANT ALL PRIVILEGES ON DATABASE polls TO ;

Когда вы закончите, выйдите из приглашения PostgreSQL, набрав:

\q

Приложение Django, правильно настроенное, теперь может подключаться и управлять этой базой данных. На следующем шаге мы клонируем код приложения Опросы из GitHub и явно определяем его зависимости пакета Python.

Шаг 2 - Клонирование репозитория приложений и объявление зависимостей

Чтобы начать процесс контейнерирования нашего приложения Django Опросы, мы сначала клонируем репозиторий django-polls, который содержит полный код для https: // www.djangoproject.com/[Django] tutorial проекта для проекта «Опросы».

Войдите на свой сервер, создайте каталог с именем + polls-project + и используйте + git для клонирования репозитория` + django-polls` из GitHub:

mkdir polls-project
cd polls-project
git clone https://github.com/do-community/django-polls.git

Откройте каталог + django-polls + и перечислите содержимое репозитория:

cd django-polls
ls
OutputLICENSE  README.md  manage.py  mysite  polls  templates

Вы должны увидеть следующие объекты:

  • + manage.py +: основная утилита командной строки, используемая для управления приложением.

  • + polls +: Содержит код приложения + polls +.

  • + mysite +: содержит код и настройки области проекта Django.

  • + templates +: содержит пользовательские файлы шаблонов для административного интерфейса.

Чтобы узнать больше о структуре и файлах проекта, обратитесь к Creating[Creating Project из официальной документации Django.

В этом каталоге мы также создадим файл с именем + needs.txt +, который будет содержать зависимости Python приложения Django.

Откройте файл с именем + needs.txt + в своем редакторе и вставьте следующие зависимости Python:

опрашивает-проект / Джанго-опросы / requirements.txt

boto3==1.9.252
botocore==1.12.252
Django==2.2.6
django-storages==1.7.2
docutils==0.15.2
gunicorn==19.9.0
jmespath==0.9.4
psycopg2==2.8.3
python-dateutil==2.8.0
pytz==2019.3
s3transfer==0.2.1
six==1.12.0
sqlparse==0.3.0
urllib3==1.25.6

Здесь мы устанавливаем Django, плагин + django-storages + для выгрузки статических ресурсов в хранилище объектов, WSGI-сервер + gunicorn +, адаптер PostgreSQL + psycopg2 +, а также некоторые дополнительные пакеты зависимостей. Обратите внимание, что мы явно перечисляем и версии каждого пакета Python, требуемого нашим приложением.

Сохраните и закройте файл.

Теперь, когда мы клонировали приложение и определили его зависимости, мы можем перейти к его модификации для переносимости.

Шаг 3 - Настройка Django с помощью переменных среды

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

Основной файл настроек для нашего проекта Django (+ django-polls / mysite / settings.py +) представляет собой модуль Python, который использует собственные структуры данных для настройки приложения. По умолчанию большинство значений в файле жестко запрограммированы, что означает, что вам нужно отредактировать файл конфигурации, чтобы изменить поведение приложения. Мы можем использовать функцию Python + getenv в модуле` + os`, чтобы сконфигурировать Django для чтения параметров конфигурации из локальных переменных среды.

Для этого мы пройдемся по + settings.py + и заменим жестко закодированные значения каждой из переменных, которые мы хотим установить во время выполнения, на вызов + os.getenv +. Функция + os.getenv + считывает значение из предоставленного имени переменной среды. При желании можно указать второй параметр со значением по умолчанию, который будет использоваться, если переменная среды не установлена.

Это позволяет нам устанавливать переменные следующим образом:

опрашивает-проект / Джанго-опросы / MySite / settings.py

. . .
SECRET_KEY =
. . .
DEBUG =
. . .

Для + SECRET_KEY +, Django будет искать переменную среды с именем + DJANGO_SECRET_KEY +. Так как это не должно быть жестко запрограммировано и должно быть одинаковым на всех наших серверах приложений, мы захотим установить это внешне без запасного значения. Мы хотим, чтобы приложение не работало, если мы этого не предоставим, поскольку это может привести к проблемам, если различные копии нашего приложения используют разные ключи.

Для + DEBUG + Django будет искать переменную окружения с именем + DJANGO_DEBUG +. Однако на этот раз мы предоставили значение по умолчанию, которое будет использоваться как запасной вариант, если переменная не установлена. В этом случае мы решили установить для + DEBUG + значение + False +, если значение не предоставлено, чтобы мы не могли случайно утечь конфиденциальную информацию, если переменная не была преднамеренно определена и не установлена ​​в + True + ..

Чтобы применить эту технику, откройте файл + polls-project / django-polls / mysite / settings.py + в выбранном вами редакторе и перемещайтесь по нему, выводя следующие переменные с предоставленными значениями по умолчанию:

  • + SECRET_KEY = +

  • + DEBUG = +

  • + ALLOWED_HOSTS = +

Для + ALLOWED_HOSTS + мы извлекаем переменную окружения + DJANGO_ALLOWED_HOSTS + и разделяем ее на список Python, используя +, + в качестве разделителя. Если переменная не установлена, + ALLOWED_HOSTS + устанавливается в + 127.0.0.1 +.

После того, как вы изменили вышеуказанные переменные, перейдите к переменной + DATABASES + и настройте ее следующим образом:

опрашивает-проект / Джанго-опросы / MySite / settings.py

. . .
# Database
# https://docs.djangoproject.com/en/2.1/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.{}'.format(
            os.getenv('DATABASE_ENGINE', 'sqlite3')
        ),
        'NAME': os.getenv('DATABASE_NAME', 'polls'),
        'USER': os.getenv('DATABASE_USERNAME', 'myprojectuser'),
        'PASSWORD': os.getenv('DATABASE_PASSWORD', 'password'),
        'HOST': os.getenv('DATABASE_HOST', '127.0.0.1'),
        'PORT': os.getenv('DATABASE_PORT', 5432),
        'OPTIONS': json.loads(
            os.getenv('DATABASE_OPTIONS', '{}')
        ),
    }
}
. . .

Это установит параметры базы данных + default + с помощью переменных среды.

Для + DATABASES ['default'] ['OPTIONS'] + мы использовали + json.loads + для десериализации объекта JSON, переданного через переменную окружения + DATABASE_OPTIONS +. В большинстве случаев интерпретация переменных среды как простых строк облегчает чтение перевода в настройки Django. Однако в этом случае возможность передать произвольную структуру данных является ценной. Каждый механизм базы данных имеет уникальный набор допустимых параметров, поэтому возможность кодировать объект JSON с соответствующими параметрами дает нам гораздо большую гибкость за счет некоторой разборчивости.

Чтобы использовать библиотеку + json +, импортируйте ее в начало + settings.py +:

опрашивает-проект / Джанго-опросы / MySite / settings.py

"""
Django settings for mysite project.

Generated by 'django-admin startproject' using Django 2.1.

For more information on this file, see
https://docs.djangoproject.com/en/2.1/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.1/ref/settings/
"""

import os

. . .

Другая область, которая требует особого внимания, это + DATABASES ['default'] ['NAME'] +. Для большинства механизмов базы данных это имя базы данных в системе управления реляционными базами данных. С другой стороны, если вы используете SQLite, + NAME + используется для указания файла базы данных, поэтому обязательно установите этот параметр соответствующим образом.

Поскольку файл + settings.py + представляет собой код Python, существует много разных способов обработки значений из среды. Метод, который мы использовали здесь, является лишь одним из возможных методов для вывода конфигурации из вашей кодовой базы.

На этом шаге мы сконфигурировали основные переменные настроек Django в общем и переносимом виде, включая параметры базы данных. На следующем шаге мы продолжим настройку параметров для статических файлов, таких как таблицы стилей Javascript и CSS, которые мы централизуем и выгружаем в S3-совместимую службу хранения объектов.

Шаг 4 - Разгрузка статических активов

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

На последнем шаге мы настроили Django так, чтобы мы могли передавать параметры подключения к базе данных через переменные среды. На этом шаге мы сделаем то же самое для нашей службы хранения объектов, которую мы будем использовать для хранения статических ресурсов, которые будут совместно использоваться контейнерами Django.

Пакет django-storages предоставляет бэкэнды удаленного хранилища (включая S3-совместимое хранилище объектов), которые Django может использовать для выгрузки файлов. Мы настроим приложение Опросы для использования + django-storages + для загрузки статических файлов в DigitalOcean Space, как описано в Шаге 7 https://www.digitalocean.com/community/tutorials/how-to-set- up-a-масштабируемое-django-приложение-с-цифровыми-управляемыми-базами данных-и-пространствами # step-7-% E2% 80% 94-разгрузка статических файлов в digitalocean-space [Как настроить Масштабируемое приложение Django с базами данных и пространствами, управляемыми DigitalOcean. В этом руководстве мы будем использовать DigitalOcean Spaces, но вы можете использовать любого S3-совместимого провайдера хранения объектов.

Для начала мы внесем некоторые изменения в тот же файл + django-polls / mysite / settings.py, который мы изменили на предыдущих шагах.

Сначала откройте файл + mysite / settings.py + для редактирования и добавьте приложение + storages + в список Django + INSTALLED_APPS +:

опрашивает-проект / Джанго-опросы / MySite / settings.py

. . .
INSTALLED_APPS = [
   . . .
   'django.contrib.staticfiles',

]
. . .

Приложение + storages + устанавливается через + django-storages + в файле + needs.txt +, который мы определили в шаге 1.

Теперь найдите переменную + STATIC_URL + внизу файла и замените ее следующим блоком:

опрашивает-проект / Джанго-опросы / MySite / settings.py

. . .

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/

# Moving static assets to DigitalOcean Spaces as per:
# https://www.digitalocean.com/community/tutorials/how-to-set-up-object-storage-with-django
AWS_ACCESS_KEY_ID = os.getenv('STATIC_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.getenv('STATIC_SECRET_KEY')

AWS_STORAGE_BUCKET_NAME = os.getenv('STATIC_BUCKET_NAME')
AWS_S3_ENDPOINT_URL = os.getenv('STATIC_ENDPOINT_URL')
AWS_S3_OBJECT_PARAMETERS = {
   'CacheControl': 'max-age=86400',
}
AWS_LOCATION = 'static'
AWS_DEFAULT_ACL = 'public-read'

STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

STATIC_URL = '{}/{}/'.format(AWS_S3_ENDPOINT_URL, AWS_LOCATION)
STATIC_ROOT = 'static/'

Мы жестко кодируем следующие переменные конфигурации:

  • + STATICFILES_STORAGE +: Устанавливает бэкэнд хранилища, который Django будет использовать для выгрузки статических файлов. Этот + S3Boto3Storage + бэкэнд должен работать с любым S3-совместимым бэкэндом, включая DigitalOcean Spaces.

  • + AWS_S3_OBJECT_PARAMETERS + Устанавливает заголовки элементов управления кэшем для статических файлов.

  • + AWS_LOCATION +: Определяет каталог с именем + static + в области хранения объектов, в который будут помещены все статические файлы.

  • ` + AWS_DEFAULT_ACL + `: определяет список контроля доступа (ACL) для статических файлов. Установка его в `+ public-read + гарантирует, что файлы будут публично доступны для конечных пользователей.

  • + STATIC_URL +: указывает базовый URL-адрес, который Django должен использовать при создании URL-адресов для статических файлов. Здесь мы объединяем URL конечной точки и подкаталог статических файлов, чтобы создать базовый URL для статических файлов.

  • + STATIC_ROOT +: указывает, где собирать статические файлы локально, прежде чем копировать их в хранилище объектов.

Чтобы поддерживать гибкость и переносимость, мы настраиваем многие параметры для настройки во время выполнения с использованием переменных среды, как мы делали ранее. Они включают:

  • + AWS_ACCESS_KEY_ID +: Устанавливается переменной окружения + STATIC_ACCESS_KEY_ID +. Идентификатор ключа доступа к DigitalOcean Spaces.

  • + AWS_SECRET_ACCESS_KEY +: устанавливается с помощью + STATIC_SECRET_KEY +. Секретный ключ DigitalOcean Spaces.

  • + AWS_STORAGE_BUCKET_NAME +: устанавливается с помощью + STATIC_BUCKET_NAME +. Область хранения объектов, в которую Django будет загружать ресурсы.

  • + AWS_S3_ENDPOINT_URL +: устанавливается с помощью + STATIC_ENDPOINT_URL +. URL-адрес конечной точки, используемый для доступа к службе хранения объектов. Для DigitalOcean Spaces это будет что-то вроде + https: // nyc3.digitaloceanspaces.com +, в зависимости от региона, в котором находится ваша корзина Spaces.

Когда вы закончите вносить изменения в + settings.py +, сохраните и закройте файл.

С этого момента, когда вы запускаете + manage.py collectstatic + для сборки статических файлов вашего проекта, Django будет загружать их в хранилище удаленных объектов. Теперь Django также настроен на обслуживание статических ресурсов из этой службы хранения объектов.

На этом этапе, если вы используете DigitalOcean Space, вы можете дополнительно включить CDN для вашего Space, который ускорит доставку статических файлов вашего проекта Django, кэшируя их через географически распределенную сеть пограничных серверов. Вы также можете при желании настроить собственный поддомен для своего пространства. Чтобы узнать больше о CDN, обратитесь к Using CDN для ускорения доставки статического контента. Настройка CDN выходит за рамки этого учебного пособия, но шаги очень близко совпадают с шагами в https://www.digitalocean.com/community/tutorials/how-to-set-up-a-scalable-django-app- with-digitalocean-managed-database-and-space # enable-cdn-необязательный раздел [Enabling CDN] https://www.digitalocean.com/community/tutorials/how-to-set-up-a-scalable-django -app-with-digitalocean-managed-database-and-space # enable-cdn-option [Как настроить масштабируемое приложение Django с управляемыми базами данных и пространствами DigitalOcean].

На следующем шаге мы сделаем окончательный набор изменений в + settings.py +, которые позволят протоколировать Django в STDOUT и STDERR, чтобы эти потоки могли быть обработаны Docker Engine и проверены с помощью + docker logs + ,

Шаг 5 - Настройка ведения журнала

По умолчанию Django записывает информацию в стандартный вывод и стандартную ошибку при запуске HTTP-сервера разработки или когда для опции + DEBUG + установлено значение + True +. Однако когда для + DEBUG + установлено значение + False + или когда используется другой HTTP-сервер, оба из которых, вероятно, верны в производственных средах, Django использует другой механизм ведения журнала. Вместо того, чтобы регистрировать все с приоритетом + INFO + и выше в стандартных потоках, он отправляет сообщения с приоритетом + ERROR + или + CRITICAL + в учетную запись администратора электронной почты.

Это имеет смысл для многих ситуаций, но в Kubernetes и контейнерных средах настоятельно рекомендуется вход в систему со стандартным выводом и стандартной ошибкой. Сообщения журнала собираются в централизованном каталоге в файловой системе узла и доступны в интерактивном режиме с помощью команд + kubectl + и + docker +. Эта агрегация на уровне узла облегчает сбор журналов, позволяя операционным командам запускать процесс на каждом узле для просмотра и пересылки журналов. Чтобы использовать эту архитектуру, приложение должно записывать свои журналы в эти стандартные приемники.

К счастью, для входа в Django используется настраиваемый модуль + logging + из стандартной библиотеки Python, поэтому мы можем определить словарь для передачи в https://docs.python.org/3/library/logging.config.html#logging -config-dictschema [+ logging.config.dictConfig +] для определения желаемых результатов и форматирования. Чтобы узнать больше об этой технике и других при настройке регистрации в Django, обратитесь к Django Logging, The Right Way.

Еще раз, откройте + django-polls / mysite / settings.py + в вашем редакторе.

Сначала мы добавим дополнительный оператор + import + в начало файла, чтобы мы могли манипулировать конфигурацией ведения журнала:

опрашивает-проект / Джанго-опросы / MySite / settings.py

import json
import os

. . .

Импорт + logging.config + позволяет нам переопределить поведение ведения журнала по умолчанию в Django, передав словарь новой конфигурации ведения журнала функции + dictConfig +.

Теперь перейдите к нижней части файла и вставьте следующий блок регистрации кода конфигурации:

опрашивает-проект / Джанго-опросы / MySite / settings.py

. . .
# Logging Configuration

# Clear prev config
LOGGING_CONFIG = None

# Get loglevel from env
LOGLEVEL = os.getenv('DJANGO_LOGLEVEL', 'info').upper()

logging.config.dictConfig({
   'version': 1,
   'disable_existing_loggers': False,
   'formatters': {
       'console': {
           'format': '%(asctime)s %(levelname)s [%(name)s:%(lineno)s] %(module)s %(process)d %(thread)d %(message)s',
       },
   },
   'handlers': {
       'console': {
           'class': 'logging.StreamHandler',
           'formatter': 'console',
       },
   },
   'loggers': {
       '': {
           'level': LOGLEVEL,
           'handlers': ['console',],
       },
   },
})

Здесь мы устанавливаем + LOGGING_CONFIG + в + None +, чтобы отключить конфигурацию ведения журнала по умолчанию, предоставляемую Django. Мы устанавливаем + LOGLEVEL + в + INFO + по умолчанию, но проверяем переменную окружения + DJANGO_LOGLEVEL +, чтобы мы могли переопределять при необходимости.

Наконец, мы используем функцию + dictConfig +, чтобы установить новый словарь конфигурации с помощью модуля + logging.config +. В словаре мы определяем текстовый формат, используя + formatters +, определяем вывод, устанавливая + handlers +, и настраиваем, какие сообщения должны отправляться каждому обработчику, используя + loggers +.

Это довольно минимальная конфигурация, которая позволяет вам указывать уровень серьезности ведения журнала, используя переменную среды + DJANGO_LOGLEVEL +, а затем записывать все сообщения на этом уровне или выше в стандартные потоки. Подробное обсуждение механизмов ведения журналов в Django можно найти по адресу Logging в официальных документах Django.

При такой конфигурации, когда мы контейнеризируем приложение, Docker предоставит эти журналы с помощью команды + docker logs +. Точно так же Kubernetes захватит вывод и предоставит его с помощью команды + kubectl logs +.

На этом мы завершаем наши модификации кода для приложения Django Опросы. На следующем шаге мы начнем процесс контейнеризации, написав Dockerfile приложения.

Шаг 6 - Написание Dockerfile приложения

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

Выбор подходящего родительского изображения

Первое важное решение, которое вам придется принять при создании образа контейнера, - это основа для построения. Образы контейнеров могут быть созданы из + SCRATCH +, указывающего на пустую файловую систему, или из существующего образа контейнера. Доступно много разных образов базовых контейнеров, каждый из которых определяет файловую систему и предоставляет уникальный набор предустановленных пакетов. Изображения, основанные на ванильных дистрибутивах Linux, таких как Ubuntu 18.04, предоставляют общую операционную среду, в то время как более специализированные изображения часто включают в себя общие библиотеки и инструменты для определенных языков программирования.

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

Поскольку наше приложение построено с использованием Django, изображение со стандартной средой Python обеспечит прочную основу и включает в себя многие инструменты, необходимые для начала работы. Официальный репозиторий Docker для Python предлагает a широкий выбор изображений на основе Python, каждый из которых устанавливает версию Python и некоторые общие инструменты поверх операционной системы.

Хотя соответствующий уровень функциональности зависит от вашего варианта использования, изображения, основанные на Alpine Linux, часто являются хорошей отправной точкой. Alpine Linux предлагает надежную, но минимальную операционную среду для запуска приложений. Его файловая система по умолчанию очень мала, но включает в себя полную систему управления пакетами с довольно обширными репозиториями, что упрощает добавление функций.

В этом руководстве мы будем использовать изображение Python, помеченное как «+ 3.7.4-alpine3.10 », в качестве родительского изображения для нашего приложения Django. Мы указываем репозиторий и тег родительского изображения в нашем ` Dockerfile `, используя инструкцию ` FROM +`.

Сначала перейдите из каталога + django-polls +.

cd ..

Затем откройте файл с именем + Dockerfile + в выбранном вами редакторе. Вставьте следующее определение родительского изображения:

опрашивает-проект / Dockerfile

FROM python:3.7.4-alpine3.10

Это определяет отправную точку для настраиваемого образа Docker, который мы создаем для запуска нашего приложения.

Добавление инструкций по настройке приложения

Выбрав родительский образ, вы можете начать добавлять инструкции по установке зависимостей, копировать файлы нашего приложения и настраивать работающую среду. Этот процесс обычно отражает шаги, которые вы бы предприняли для настройки сервера для вашего приложения, с некоторыми ключевыми отличиями для учета абстракций контейнера.

После строки + FROM + вставьте следующий блок кода Dockerfile:

опрашивает-проект / Dockerfile

. . .

ADD django-polls/requirements.txt /app/requirements.txt

RUN set -ex \
   && apk add --no-cache --virtual .build-deps postgresql-dev build-base \
   && python -m venv /env \
   && /env/bin/pip install --upgrade pip \
   && /env/bin/pip install --no-cache-dir -r /app/requirements.txt \
   && runDeps="$(scanelf --needed --nobanner --recursive /env \
       | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \
       | sort -u \
       | xargs -r apk info --installed \
       | sort -u)" \
   && apk add --virtual rundeps $runDeps \
   && apk del .build-deps

ADD django-polls /app
WORKDIR /app

ENV VIRTUAL_ENV /env
ENV PATH /env/bin:$PATH

EXPOSE 8000

Давайте рассмотрим эти инструкции, чтобы объяснить некоторые из менее очевидных вариантов. Чтобы узнать больше о создании готовых Docker-файлов для приложений Django, обратитесь к https://www.caktusgroup.com/blog/2017/03/14/production-ready-dockerfile-your-python-django-app/[A Production Готовый Dockerfile для вашего приложения Django.

Первый Docker скопирует файл + needs.txt + в + / app / needs.txt +, чтобы зависимости нашего приложения были доступны в файловой системе образа. Мы будем использовать это для установки всех пакетов Python, которые нужны нашему приложению для запуска. Мы копируем файл зависимостей как отдельный шаг от остальной части нашей кодовой базы, чтобы Docker мог кэшировать слой изображения, содержащий файл зависимостей. Каждый раз, когда файл + needs.txt + не меняется между сборками, Docker может затем использовать кэшированный слой вместо его перестроения, что ускоряет процесс.

Далее у нас есть одна инструкция + RUN +, которая выполняет длинный список команд, каждая из которых объединена в цепочку с помощью оператора Linux + && +. Подводя итог, эти команды:

  • Установите файлы разработки PostgreSQL и базовые зависимости сборки, используя менеджер пакетов Alpine + apk +

  • Создать виртуальную среду

  • Установите зависимости Python, перечисленные в + needs.txt, с помощью` + pip`

  • Составьте список пакетов, необходимых во время выполнения, проанализировав требования установленных пакетов Python.

  • Удалите все ненужные зависимости сборки

Мы объединяем команды вместе вместо того, чтобы выполнять каждую в отдельном шаге + RUN + из-за способа, которым Docker создает слои изображения. Для каждой инструкции + ADD,` + COPY` и + RUN + Docker создает новый слой изображения поверх существующей файловой системы, выполняет инструкцию и затем сохраняет полученный слой. Это означает, что сжатие команд в инструкциях + RUN + приведет к уменьшению количества слоев изображения.

Как только элемент был записан в слой изображения, он не может быть удален в последующем слое, чтобы уменьшить размер изображения. Если мы устанавливаем зависимости сборки, но хотим удалить их после настройки приложения, мы должны сделать это в рамках той же инструкции, чтобы уменьшить размер изображения. В этой команде + RUN + мы устанавливаем зависимости сборки, используем их для сборки пакетов приложения, а затем удаляем их с помощью + apk del +.

После инструкции + RUN + мы используем + ADD для копирования кода приложения и` + WORKDIR` для установки рабочего каталога для изображения в наш каталог кода.

Затем мы используем инструкцию + ENV +, чтобы установить две переменные окружения, которые будут доступны в контейнерах, порожденных нашим изображением. Первая устанавливает + VIRTUALENV в` + / env + , а вторая инструкция изменяет переменную + PATH + , добавляя в нее каталог + + env / bin +. Эти две строки имитируют результаты поиска сценария `+ / env / bin / activ + +, который является традиционным методом активации виртуальной среды.

Наконец, мы используем + EXPOSE +, чтобы сообщить Docker, что контейнер будет прослушивать порт + 8000 + во время выполнения.

На этом этапе + Dockerfile + почти завершен. Нам просто нужно определить команду по умолчанию, которая будет запускаться, когда мы запускаем контейнеры, используя изображение.

Определение команды по умолчанию

Команда образа образа Docker по умолчанию определяет, что происходит, когда контейнер запускается без явного указания команды для выполнения. Инструкции + ENTRYPOINT + и + CMD + могут использоваться независимо или в тандеме для определения команды по умолчанию в + Dockerfile +.

Когда определены и + ENTRYPOINT +, и + CMD +, + ENTRYPOINT + определяет исполняемый файл, который будет запускаться контейнером, а + CMD + представляет список аргументов по умолчанию для этой команды. Пользователи могут переопределить список аргументов по умолчанию, добавив альтернативные аргументы в командной строке: + docker run <image> <arguments> +. В этом формате пользователи не смогут легко переопределить команду + ENTRYPOINT +, поэтому для команды + ENTRYPOINT + часто задается сценарий, который устанавливает среду и выполняет различные действия в зависимости от полученного списка аргументов.

При отдельном использовании + ENTRYPOINT + конфигурирует исполняемый файл контейнера, но не определяет список аргументов по умолчанию. Если установлен только + CMD +, он будет интерпретирован как список команд и аргументов по умолчанию, который может быть переопределен во время выполнения.

На нашем изображении мы хотим, чтобы контейнер запускал ваше приложение по умолчанию, используя сервер приложений + gunicorn. Список аргументов, который мы передаем + gunicorn +, не обязательно должен настраиваться во время выполнения, но мы хотим иметь возможность легко запускать другие команды, если это необходимо для отладки или выполнения задач управления (таких как сбор статических ресурсов или инициализация базы данных). Имея в виду эти требования, имеет смысл использовать + CMD + для определения команды по умолчанию без + ENTRYPOINT +.

Инструкция + CMD + может быть определена с использованием любого из следующих форматов:

  • + CMD [" "," ",. . . , ""] + `: Формат списка аргументов (используется для определения списка аргументов по умолчанию для + ENTRYPOINT + `)

  • + CMD [" "," "," ",. . . , ""] + `: Формат + exec + `

  • `+ CMD" "" ". . . "" + `: Формат оболочки

Первый формат содержит только аргументы и используется вместе с + ENTRYPOINT +. Два других формата определяют команды и их аргументы, с некоторыми ключевыми отличиями. Рекомендованный формат + exec + выполняет команду напрямую, передавая список аргументов без обработки оболочки. Формат оболочки, с другой стороны, передает весь список в + sh -c +. Это необходимо, если, например, вам необходимо заменить значение переменной среды в команде, но обычно это считается менее предсказуемым.

Для наших целей последняя инструкция в нашем + Dockerfile + выглядит следующим образом:

опрашивает-проект / Dockerfile

. . .
CMD ["gunicorn", "--bind", ":8000", "--workers", "3", "mysite.wsgi:application"]

По умолчанию контейнеры, использующие этот образ, будут выполнять + gunicorn +, привязанный к порту localhost + 8000 + с 3 рабочими, и запускать функцию + application + в файле + wsgi.py +, найденном в + mysite + каталог. Вы можете дополнительно предоставить команду во время выполнения, чтобы выполнить другой процесс вместо + gunicorn +.

На этом этапе вы можете использовать + docker build для создания образа вашего приложения и` + docker run` для запуска контейнера на вашем компьютере.

Построение Docker Image

По умолчанию команда + docker build ищет` + Dockerfile` в текущем каталоге, чтобы найти инструкции по сборке. Он также отправляет «контекст» сборки, иерархию локальной файловой системы, которая должна быть доступна во время процесса сборки, демону Docker. Часто текущий каталог устанавливается в качестве контекста сборки.

Получив доступ к каталогу, содержащему ваш + Dockerfile, запустите` + docker build`, передав изображение и имя тега с флагом + -t +, и используйте текущий каталог в качестве контекста сборки. Здесь мы называем изображение + django-polls + и помечаем его версией + v0 +:

docker build -t : .

Команда передаст демону + Docker + Dockerfile + и текущий каталог в качестве контекста сборки. Демон создаст ваше изображение, создав серию слоев изображения во время обработки инструкций + Dockerfile +.

Когда + docker build завершен, вы должны увидеть следующий вывод:

OutputSuccessfully built
Successfully tagged django-polls:v0

После успешного построения образа вы можете запустить контейнер приложения, используя + docker run +. Тем не менее, команда + run + скорее всего потерпит неудачу, так как мы до сих пор не настроили рабочую среду контейнера. Внешние переменные, такие как + SECRET_KEY + и настройки базы данных из + settings.py +, будут либо пустыми, либо будут установлены значения по умолчанию.

На последнем шаге мы настроим работающую среду контейнера с помощью файла переменной среды. Затем мы создадим схему базы данных, сгенерируем и загрузим статические файлы приложения в хранилище объектов и, наконец, протестируем приложение.

Шаг 7 - Настройка рабочей среды и тестирование приложения

Докер предоставляет several методы для установки переменных среды внутри контейнер. Поскольку нам нужно установить все переменные, которые мы вывели на шаге 1, мы будем использовать метод + - env-file +, который позволяет нам передать файл, содержащий список переменных среды и их значений.

Создайте файл с именем + env + в каталоге + polls-project + и вставьте следующий список переменных:

опрашивает-проект / окр

DJANGO_SECRET_KEY=
DEBUG=True
DJANGO_ALLOWED_HOSTS=
DATABASE_ENGINE=postgresql_psycopg2
DATABASE_NAME=polls
DATABASE_USERNAME=
DATABASE_PASSWORD=
DATABASE_HOST=
DATABASE_PORT=
STATIC_ACCESS_KEY_ID=
STATIC_SECRET_KEY=
STATIC_BUCKET_NAME=
STATIC_ENDPOINT_URL=https://.digitaloceanspaces.com
DJANGO_LOGLEVEL=info

Замените следующие значения в этом файле:

  • + DJANGO_SECRET_KEY +: установите это уникальное непредсказуемое значение, как подробно описано в Django docs. Один из способов генерации этого ключа представлен в https://www.digitalocean.com/community/tutorials/how-to-set-up-a-scalable-django-app-with-digitalocean-managed-databases-and-spaces # step-5-% E2% 80% 94-setting-the-app-settings [Регулировка настроек приложения] на странице https://www.digitalocean.com/community/tutorials/how-to-set-up-a -scalable-django-приложение-с-цифровыми-управляемыми-базами данных-и-пространствами # step-5-% E2% 80% 94-настройка-приложения-настройки [Scalable Django App] учебник.

  • + DJANGO_ALLOWED_HOSTS +: установите это в качестве IP-адреса вашего сервера Ubuntu. В целях тестирования вы также можете установить его в + * +, подстановочный знак, который будет соответствовать всем хостам. Обязательно установите это значение соответствующим образом при запуске Django в производственной среде.

  • + DATABASE_USERNAME +: установите это значение для пользователя базы данных, созданного на предыдущем шаге.

  • + DATABASE_PASSWORD +: установите пароль пользователя, созданный на предыдущем шаге.

  • + DATABASE_HOST +: установите это имя хоста вашей базы данных.

  • + DATABASE_PORT +: установите это для порта вашей базы данных.

  • + STATIC_ACCESS_KEY_ID +: установите это в качестве ключа доступа к вашему пространству.

  • + STATIC_SECRET_KEY +: установите для этого параметра ключ доступа к вашему пространству Secret.

  • + STATIC_BUCKET_NAME +: установите это имя своего пространства.

  • + STATIC_ENDPOINT_URL +: установите для него соответствующий URL-адрес конечной точки пространства.

При запуске Django в производственном режиме обязательно установите для + DEBUG + значение + False + и отрегулируйте уровень записи в соответствии с желаемой детализацией.

Сохраните и закройте файл.

Теперь мы будем использовать + docker run +, чтобы переопределить набор + CMD + в Dockerfile и создать схему базы данных с помощью команд + manage.py makemigrations + и + manage.py migrate +:

docker run --env-file env django-polls:v0 sh -c "python manage.py makemigrations && python manage.py migrate"

Здесь мы запускаем образ контейнера + django-polls: v0 +, передаем файл переменной среды, который мы только что создали, и перезаписываем команду Dockerfile с помощью `+ sh -c" python manage.py makemigrations && python manage.py migrate " + `, который создаст схему базы данных, определенную кодом приложения. После запуска команды вы должны увидеть:

OutputNo changes detected
Operations to perform:
 Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
 Applying contenttypes.0001_initial... OK
 Applying auth.0001_initial... OK
 Applying admin.0001_initial... OK
 Applying admin.0002_logentry_remove_auto_add... OK
 Applying admin.0003_logentry_add_action_flag_choices... OK
 Applying contenttypes.0002_remove_content_type_name... OK
 Applying auth.0002_alter_permission_name_max_length... OK
 Applying auth.0003_alter_user_email_max_length... OK
 Applying auth.0004_alter_user_username_opts... OK
 Applying auth.0005_alter_user_last_login_null... OK
 Applying auth.0006_require_contenttypes_0002... OK
 Applying auth.0007_alter_validators_add_error_messages... OK
 Applying auth.0008_alter_user_username_max_length... OK
 Applying auth.0009_alter_user_last_name_max_length... OK
 Applying auth.0010_alter_group_name_max_length... OK
 Applying auth.0011_update_proxy_permissions... OK
 Applying polls.0001_initial... OK
 Applying sessions.0001_initial... OK

Это указывает на то, что схема базы данных была успешно создана.

Далее мы запустим еще один экземпляр контейнера приложения и используем внутри него интерактивную оболочку, чтобы создать администратора для проекта Django.

docker run -i -t --env-file env django-polls:v0 sh

Это предоставит вам приглашение оболочки внутри работающего контейнера, которое вы можете использовать для создания пользователя Django:

python manage.py createsuperuser

Введите имя пользователя, адрес электронной почты и пароль для своего пользователя, и после создания пользователя нажмите + CTRL + D +, чтобы выйти из контейнера и уничтожить его.

Наконец, мы сгенерируем статические файлы для приложения и загрузим их в DigitalOcean Space с помощью + collectstatic +:

docker run --env-file env django-polls:v0 sh -c "python manage.py collectstatic --noinput"
Output
121 static files copied.

Теперь мы можем запустить приложение:

docker run --env-file env -p 80:8000 django-polls:v0
Output[2019-10-17 21:23:36 +0000] [1] [INFO] Starting gunicorn 19.9.0
[2019-10-17 21:23:36 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1)
[2019-10-17 21:23:36 +0000] [1] [INFO] Using worker: sync
[2019-10-17 21:23:36 +0000] [7] [INFO] Booting worker with pid: 7
[2019-10-17 21:23:36 +0000] [8] [INFO] Booting worker with pid: 8
[2019-10-17 21:23:36 +0000] [9] [INFO] Booting worker with pid: 9

Здесь мы запускаем команду по умолчанию, определенную в Dockerfile, + gunicorn --bind: 8000 --workers 3 mysite.wsgi: application +, и выставляем контейнерный порт + 8000 +, чтобы порт + 80 + на Сервер Ubuntu отображается на порт + 8000 + контейнера + django-polls: v0 +.

Теперь вы должны иметь возможность перейти к приложению + polls + с помощью вашего веб-браузера, набрав + http: // + в строке URL-адреса. Поскольку для пути + / + не определен маршрут, скорее всего, вы получите ошибку 404 Page Not Found, которая ожидается.

Перейдите к + http: /// polls +, чтобы увидеть интерфейс приложения Опросы:

изображение: https: //assets.digitalocean.com/articles/scalable_django/polls_app.png [Интерфейс приложения для опросов]

Чтобы проверить интерфейс администратора, посетите + http: /// admin +. Вы должны увидеть окно аутентификации администратора приложения Опросы:

изображение: https: //assets.digitalocean.com/articles/scalable_django/polls_admin.png [Страница аутентификации администратора опроса]

Введите административное имя пользователя и пароль, которые вы создали с помощью команды + createuperuser +.

После аутентификации вы можете получить доступ к административному интерфейсу приложения Опросы:

изображение: https: //assets.digitalocean.com/articles/scalable_django/polls_admin_main.png [Главный интерфейс администратора опросов]

Обратите внимание, что статические ресурсы для приложений + admin + и + polls + доставляются непосредственно из хранилища объектов. Чтобы подтвердить это, обратитесь к https://www.digitalocean.com/community/tutorials/how-to-set-up-a-scalable-django-app-with-digitalocean-managed-databases-and-spaces#testing-spaces -static-file-delivery [Тестирование доставки статических файлов в пространствах].

Когда вы закончите исследование, нажмите + CTRL-C + в окне терминала, в котором запущен контейнер Docker, чтобы уничтожить контейнер.

Заключение

В этом руководстве вы адаптировали веб-приложение Django для эффективной работы в облачной среде на основе контейнеров. Затем вы написали минимальный Dockerfile для образа контейнера, скомпилировали его локально и запустили с помощью Docker Engine. Вы можете увидеть diff изменений, которые вы внедрили в https://github.com/do-community/django-polls/tree / polls-docker [ветвь polls-docker] репозитория GitHub приложения Опросы. Эта ветка содержит все модификации, описанные в этом руководстве.

Отсюда вы можете связать контейнер Django / Gunicorn с контейнером обратного прокси-сервера Nginx для обработки и маршрутизации входящих HTTP-запросов, а также контейнер Certbot для получения сертификатов TLS. Вы можете управлять этой мультиконтейнерной архитектурой, используя Docker Compose; это будет описано в следующем уроке.

Обратите внимание, что как есть, эта установка не готова к работе, поскольку вы должны always запускать Gunicorn за HTTP-прокси для буферизации медленных клиентов. В противном случае ваше веб-приложение Django будет уязвимо для атак типа «отказ в обслуживании». Мы также выбрали 3 в качестве произвольного числа работников Gunicorn в этом уроке. В производственной среде вы должны установить количество рабочих и потоков с помощью тестов производительности.

В этой архитектуре мы сделали выбор дизайна для разгрузки статических активов в хранилище объектов, чтобы контейнерам не приходилось связывать версии этих активов и обслуживать их с помощью Nginx, что может стать затруднительным для управления в кластерных средах с несколькими контейнерами, таких как Kubernetes. , В зависимости от вашего варианта использования, это может быть неэффективным, поэтому вы должны соответствующим образом адаптировать шаги в этом руководстве.

Наконец, теперь, когда вы полностью контейнировали приложение Django Опросы, вы можете поместить изображение в реестр контейнера, например Dockerhub, и сделать его доступным для любой системы, в которой доступен Docker: Ubuntu серверы, виртуальные машины и кластеры контейнеров, такие как Kubernetes.

Related