Докеризация Django с Postgres, Gunicorn, и Traefik

Spread the love

Оригинальная статья: Amal ShajiDockerizing Django with Postgres, Gunicorn, and Traefik

В этом руководстве мы рассмотрим, как настроить Django с помощью Postgres и Docker. Для производственных сред мы добавим Gunicorn, Traefik и Let’s Encrypt.

Настройка проекта

Начнем с создания каталога проекта:

$ mkdir django-docker-traefik && cd django-docker-traefik
$ mkdir app && cd app
$ python3.9 -m venv venv
$ source venv/bin/activate

Не стесняйтесь использовать вместо virtualenv и Pip Poetry или Pipenv. Для получения дополнительной информации просмотрите Modern Python Environments.

Затем давайте установим Django и создадим простое приложение Django:

(venv)$ pip install django==3.2.3
(venv)$ django-admin.py startproject config .
(venv)$ python manage.py migrate

Запустим приложение:

(venv)$ python manage.py runserver

Перейдите по адресу http://localhost:8000/, чтобы проверить экран приветствия Django. Завершите работу сервера и выйдите из виртуальной среды после завершения. Также удалите виртуальную среду. Теперь у нас есть простой проект Django, с которым можно работать.

Создайте файл requirements.txt в каталоге app и добавьте Django в качестве зависимости:

Django==3.2.3

Поскольку далее мы перейдем к Postgres, удалите файл db.sqlite3 из каталога «app».

Каталог вашего проекта должен выглядеть так:

└── app
    ├── config
    │   ├── __init__.py
    │   ├── asgi.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── manage.py
    └── requirements.txt

Docker

Установите Docker, если у вас его еще нет, добавьте Dockerfile в каталог «app»:

# app/Dockerfile

# pull the official docker image
FROM python:3.9.5-slim

# set work directory
WORKDIR /app

# set env variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# install dependencies
COPY requirements.txt .
RUN pip install -r requirements.txt

# copy project
COPY . .

Итак, мы начали с slim образа Docker image для Python 3.9.5. Затем мы настраиваем рабочий каталог (working directory) вместе с двумя переменными среды:

  1. PYTHONDONTWRITEBYTECODE: Запрещает Python записывать файлы pyc на диск (эквивалент опции python -B)
  2. PYTHONUNBUFFERED: Запрещает Python буферизовать stdout и stderr (эквивалент опции python -u)

В конце, мы скопировали файл requirements.txt, установили зависимости и скопировали проект.

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

Затем добавьте файл docker-compose.yml в корень проекта:

# docker-compose.yml

version: '3.8'

services:
  web:
    build: ./app
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - ./app:/app
    ports:
      - 8008:8000
    environment:
      - DEBUG=1

Просмотрите Compose file reference для получения информации о том, как этот файл работает.

Создайте образ:

$ docker-compose build

После создания образа запустите контейнер:

$ docker-compose up -d

Перейдите по адресу http://localhost:8008, чтобы снова просмотреть страницу приветствия.

Проверьте наличие ошибок в журналах, если что то не работает, с помощью команды docker-compose logs -f.

Postgres

Чтобы настроить Postgres, нам нужно добавить новую службу в файле docker-compose.yml, обновить настройки Django и установить Psycopg2.

Сначала добавим новую службу db в docker-compose.yml:

# docker-compose.yml

version: '3.8'

services:
  web:
    build: ./app
    command: bash -c 'while !</dev/tcp/db/5432; do sleep 1; done; python manage.py runserver 0.0.0.0:8000'
    volumes:
      - ./app:/app
    ports:
      - 8008:8000
    environment:
      - DEBUG=1
      - DATABASE_URL=postgresql://django_traefik:django_traefik@db:5432/django_traefik
    depends_on:
      - db
  db:
    image: postgres:13-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    expose:
      - 5432
    environment:
      - POSTGRES_USER=django_traefik
      - POSTGRES_PASSWORD=django_traefik
      - POSTGRES_DB=django_traefik

volumes:
  postgres_data:

Чтобы сохранить данные по истечении срока службы контейнера, мы настроили том. Эта конфигурация привяжет postgres_data к каталогу «/var/lib/postgresql/data/» в контейнере.

Мы также добавили ключ среды, чтобы определить имя для базы данных по умолчанию и установить имя пользователя и пароль.

Дополнительные сведения смотри в разделе «Environment Variables» на странице Postgres Docker Hub.

Обратите внимание на новую команду в веб-службе:

bash -c 'while !</dev/tcp/db/5432; do sleep 1; done; python manage.py runserver 0.0.0.0:8000'

while !</dev/tcp/db/5432; do sleep 1 что означает взять паузу пока не запустится Postgres. Далее запуститься, python manage.py runserver 0.0.0.0:8000 .

Чтобы настроить Postgres, добавим django-environ, для загрузки / чтения переменных среды и Psycopg2 в файл requirements.txt:

Django==3.2.3
django-environ==0.4.5
psycopg2-binary==2.8.6

Инициализируем среду в начальной части config/settings.py:

# config/settings.py

import environ

env = environ.Env()

Затем, обновим словарь DATABASES:

# config/settings.py

DATABASES = {
    'default': env.db(),
}

django-environ автоматически проанализирует строку URL-адреса подключения к базе данных, которую мы добавили в docker-compose.yml:

DATABASE_URL=postgresql://django_traefik:django_traefik@db:5432/django_traefik

Обновите переменную DEBUG:

# config/settings.py

DEBUG = env('DEBUG')

Создадим новый образ и запустим два контейнера:

$ docker-compose up -d --build

Запустим начальную миграцию:

$ docker-compose exec web python manage.py migrate --noinput

Убедитесь, что таблицы Django по умолчанию будут созданы:

$ docker-compose exec db psql --username=django_traefik --dbname=django_traefik

psql (13.2)
Type "help" for help.

django_traefik=# \l
                                            List of databases
      Name      |     Owner      | Encoding |  Collate   |   Ctype    |         Access privileges
----------------+----------------+----------+------------+------------+-----------------------------------
 django_traefik | django_traefik | UTF8     | en_US.utf8 | en_US.utf8 |
 postgres       | django_traefik | UTF8     | en_US.utf8 | en_US.utf8 |
 template0      | django_traefik | UTF8     | en_US.utf8 | en_US.utf8 | =c/django_traefik                +
                |                |          |            |            | django_traefik=CTc/django_traefik
 template1      | django_traefik | UTF8     | en_US.utf8 | en_US.utf8 | =c/django_traefik                +
                |                |          |            |            | django_traefik=CTc/django_traefik
(4 rows)

django_traefik=# \c django_traefik
You are now connected to database "django_traefik" as user "django_traefik".

django_traefik=# \dt
                      List of relations
 Schema |            Name            | Type  |     Owner
--------+----------------------------+-------+----------------
 public | auth_group                 | table | django_traefik
 public | auth_group_permissions     | table | django_traefik
 public | auth_permission            | table | django_traefik
 public | auth_user                  | table | django_traefik
 public | auth_user_groups           | table | django_traefik
 public | auth_user_user_permissions | table | django_traefik
 public | django_admin_log           | table | django_traefik
 public | django_content_type        | table | django_traefik
 public | django_migrations          | table | django_traefik
 public | django_session             | table | django_traefik
(10 rows)

django_traefik=# \q

Вы также можете проверить, что том был создан, запустив:

$ docker volume inspect django-docker-traefik_postgres_data

Вы должны увидеть что-то похожее на:

[
    {
        "CreatedAt": "2021-05-20T01:01:34Z",
        "Driver": "local",
        "Labels": {
            "com.docker.compose.project": "django-docker-traefik",
            "com.docker.compose.version": "1.29.1",
            "com.docker.compose.volume": "postgres_data"
        },
        "Mountpoint": "/var/lib/docker/volumes/django-docker-traefik_postgres_data/_data",
        "Name": "django-docker-traefik_postgres_data",
        "Options": null,
        "Scope": "local"
    }
]

Gunicorn

Двигаясь дальше, для производственных сред давайте добавим Gunicorn, сервер WSGI производственного уровня, в файл requirements:

Django==3.2.3
django-environ==0.4.5
gunicorn==20.1.0
psycopg2-binary==2.8.6

Поскольку мы по-прежнему хотим использовать встроенный сервер Django в разработке, создайте новый файл с именем docker-compose.prod.yml для производства:

# docker-compose.prod.yml

version: '3.8'

services:
  web:
    build: ./app
    command: bash -c 'while !</dev/tcp/db/5432; do sleep 1; done; gunicorn --bind 0.0.0.0:8000 config.wsgi'
    ports:
      - 8008:8000
    environment:
      - DEBUG=0
      - DATABASE_URL=postgresql://django_traefik:django_traefik@db:5432/django_traefik
    depends_on:
      - db
  db:
    image: postgres:13-alpine
    volumes:
      - postgres_data_prod:/var/lib/postgresql/data/
    expose:
      - 5432
    environment:
      - POSTGRES_USER=django_traefik
      - POSTGRES_PASSWORD=django_traefik
      - POSTGRES_DB=django_traefik

volumes:
  postgres_data_prod:

Если у вас несколько сред, вы можете использовать файл конфигурации docker-compose.override.yml. При таком подходе вы должны добавить свою базовую конфигурацию в файл docker-compose.yml, а затем использовать файл docker-compose.override.yml для переопределения этих параметров конфигурации в зависимости от среды.

Обратите внимание на команду по умолчанию (command). Мы используем Gunicorn, а не сервер разработки Django. Мы также удалили том из веб-службы, поскольку он нам не нужен в рабочей среде.

Удалите контейнеры разработки (и связанные тома с флагом -v):

$ docker-compose down -v

Затем создайте рабочие образы и запустите контейнеры:

$ docker-compose -f docker-compose.prod.yml up -d --build

Запустите миграции:

$ docker-compose -f docker-compose.prod.yml exec web python manage.py migrate --noinput

Убедитесь, что база данных django_traefik была создана вместе с таблицами Django по умолчанию. Протестируйте страницу администратора по адресу http://localhost:8008/admin. Статические файлы загружаются неправильно. Это ожидаемо. Скоро мы это исправим.

Опять же, если контейнер не запускается, проверьте наличие ошибок в журналах с помощью docker-compose -f docker-compose.prod.yml logs -f.

Production Dockerfile

Создайте новый файл Dockerfile с именем Dockerfile.prod для использования с производственными сборками:

# app/Dockerfile.prod

###########
# BUILDER #
###########

# pull official base image
FROM python:3.9.5-slim as builder

# set work directory
WORKDIR /app

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# install system dependencies
RUN apt-get update && \
    apt-get install -y --no-install-recommends gcc

# lint
RUN pip install --upgrade pip
RUN pip install flake8==3.9.1
COPY . .
RUN flake8 --ignore=E501,F401 .

# install python dependencies
COPY requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt


#########
# FINAL #
#########

# pull official base image
FROM python:3.9.5-slim

# create directory for the app user
RUN mkdir -p /home/app

# create the app user
RUN addgroup --system app && adduser --system --group app

# create the appropriate directories
ENV HOME=/home/app
ENV APP_HOME=/home/app/web
RUN mkdir $APP_HOME
WORKDIR $APP_HOME

# install dependencies
COPY --from=builder /usr/src/app/wheels /wheels
COPY --from=builder /app/requirements.txt .
RUN pip install --upgrade pip
RUN pip install --no-cache /wheels/*

# copy project
COPY . $APP_HOME

# chown all the files to the app user
RUN chown -R app:app $APP_HOME

# change to the app user
USER app

Здесь мы использовали многоступенчатую сборку Docker (multi-stage build), чтобы уменьшить размер окончательного образа. По сути, builder — это временный образ, который используется для создания Python wheels. Затем wheels копируются в окончательный производственный образ, а образ компоновщика (builder) удаляется.

Вы можете пойти дальше в многоэтапном подходе к сборке ( multi-stage build approach) и использовать один Dockerfile вместо создания двух Dockerfile. Подумайте о плюсах и минусах использования этого подхода для двух разных файлов.

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

Обновите web службу в файле docker-compose.prod.yml для сборки с помощью Dockerfile.prod:

web:
  build:
    context: ./app
    dockerfile: Dockerfile.prod
  command: bash -c 'while !</dev/tcp/db/5432; do sleep 1; done; gunicorn --bind 0.0.0.0:8000 config.wsgi'
  ports:
    - 8008:8000
  environment:
    - DEBUG=0
    - DATABASE_URL=postgresql://django_traefik:django_traefik@db:5432/django_traefik
  depends_on:
    - db

Попробуйте следующие команды:

$ docker-compose -f docker-compose.prod.yml down -v
$ docker-compose -f docker-compose.prod.yml up -d --build
$ docker-compose -f docker-compose.prod.yml exec web python manage.py migrate --noinput

Traefik

Затем давайте добавим обратный прокси Traefik.

Впервые слышите о Traefik? Ознакомьтесь с официальным руководством Getting Started по началу работы.

Traefik vs Nginx: Traefik — это современный обратный HTTP-прокси и балансировщик нагрузки. Его часто сравнивают с Nginx, веб-сервером и обратным прокси. Поскольку Nginx в первую очередь является веб-сервером, его можно использовать для обслуживания веб-страницы, а также в качестве обратного прокси-сервера и балансировщика нагрузки. В целом Traefik проще запустить, а Nginx более универсален.

Traefik:

  1. Обратный прокси и балансировщик нагрузки
  2. Автоматически выдает и обновляет сертификаты SSL через Let’s Encrypt прямо из коробки
  3. Traefik проще использовать для простых микросервисов на основе Docker

Nginx:

  1. Веб-сервер, обратный прокси и балансировщик нагрузки
  2. Немного быстрее, чем Traefik
  3. Используйте Nginx для сложных сервисов

Добавьте новый файл с именем traefik.dev.toml:

# traefik.dev.toml

# listen on port 80
[entryPoints]
  [entryPoints.web]
    address = ":80"

# Traefik dashboard over http
[api]
insecure = true

[log]
level = "DEBUG"

[accessLog]

# containers are not discovered automatically
[providers]
  [providers.docker]
    exposedByDefault = false

Здесь, поскольку мы не хотим раскрывать службу db, мы устанавливаем для exposedByDefault значение false. Чтобы вручную открыть службу, мы можем добавить метку traefik.enable=true в файл Docker Compose.

Затем обновите файл docker-compose.yml, чтобы наш веб-сервис был обнаружен Traefik, и добавьте новый сервис traefik:

# docker-compose.yml

version: '3.8'

services:
  web:
    build: ./app
    command: bash -c 'while !</dev/tcp/db/5432; do sleep 1; done; python manage.py runserver 0.0.0.0:8000'
    volumes:
      - ./app:/app
    expose:  # new
      - 8000
    environment:
      - DEBUG=1
      - DATABASE_URL=postgresql://django_traefik:django_traefik@db:5432/django_traefik
    depends_on:
      - db
    labels: # new
      - "traefik.enable=true"
      - "traefik.http.routers.django.rule=Host(`django.localhost`)"
  db:
    image: postgres:13-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    expose:
      - 5432
    environment:
      - POSTGRES_USER=django_traefik
      - POSTGRES_PASSWORD=django_traefik
      - POSTGRES_DB=django_traefik
  traefik: # new
    image: traefik:v2.2
    ports:
      - 8008:80
      - 8081:8080
    volumes:
      - "$PWD/traefik.dev.toml:/etc/traefik/traefik.toml"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

volumes:
  postgres_data:

Теперь, web служба доступна только другим контейнерам через порт 8000. Мы также добавили к web службе следующие метки:

  1. traefik.enable=true позволяет Traefik обнаружить службу
  2. traefik.http.routers.django.rule=Host(`django.localhost`) когда запрос имеет Host = django.localhost, запрос перенаправляется на эту службу

Обратите внимание на volumes в сервисе traefik:

  1. "$PWD/traefik.dev.toml:/etc/traefik/traefik.toml" сопоставляет локальный файл конфигурации с файлом конфигурации в контейнере, чтобы настройки синхронизировались
  2. "/var/run/docker.sock:/var/run/docker.sock:ro" позволяет traefik обнаруживать другие контейнеры

Чтобы проверить, сначала отключите все существующие контейнеры:

$ docker-compose down -v
$ docker-compose -f docker-compose.prod.yml down -v

Создайте новые образы разработки и запустите контейнеры:

$ docker-compose up -d --build

Перейдя по адресу http://django.localhost:8008/ вы должны увидеть страницу приветствия Django.

Затем проверьте панель управления на django.localhost:8081:

traefik dashboard

Когда закончите, выключите контейнеры и тома:

$ docker-compose down -v

Let’s Encrypt

Мы успешно создали рабочий пример Django, Docker и Traefik в режиме разработки. Для производственной среды вам нужно настроить Traefik для управления сертификатами TLS через Let’s Encrypt. Traefik будеи автоматически связываться с центром сертификации для выдачи и обновления сертификатов.

Поскольку Let’s Encrypt не будет выдавать сертификаты для localhost, вам необходимо развернуть свои производственные контейнеры на экземпляре облачных вычислений (например, droplet DigitalOcean или инстансе AWS EC2). Вам также понадобится действительное доменное имя. Если у вас его нет, вы можете создать бесплатный домен на Freenom.

Мы использовали дроплет DigitalOcean вместе с Docker, чтобы быстро подготовить инстанса с помощью Docker, и развернули производственные контейнеры для тестирования конфигурации Traefik. Ознакомьтесь с примером DigitalOcean из документации Docker, чтобы узнать больше об использовании Docker Machine для подготовки droplet.

Предполагая, что вы настроили инстанс и использовали бесплатный домен, теперь вы готовы настроить Traefik в производственном режиме.

Начните с добавления производственной версии конфигурации Traefik в файле с именем traefik.prod.toml:

# traefik.prod.toml

[entryPoints]
  [entryPoints.web]
    address = ":80"
  [entryPoints.web.http]
    [entryPoints.web.http.redirections]
      [entryPoints.web.http.redirections.entryPoint]
        to = "websecure"
        scheme = "https"

  [entryPoints.websecure]
    address = ":443"

[accessLog]

[api]
dashboard = true

[providers]
  [providers.docker]
    exposedByDefault = false

[certificatesResolvers.letsencrypt.acme]
  email = "your@email.com"
  storage = "/certificates/acme.json"
  [certificatesResolvers.letsencrypt.acme.httpChallenge]
    entryPoint = "web"

Обязательно замените your@email.com своим адресом электронной почты.

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

  1. entryPoints.web устанавливает точку входа для нашего небезопасного HTTP-приложения на порт 80
  2. entryPoints.websecure устанавливает точку входа для нашего защищенного приложения HTTPS на порт 443
  3. entryPoints.web.http.redirections.entryPoint перенаправляет все небезопасные запросы на защищенный порт
  4. exposedByDefault = false закрываем все остальные сервисы
  5. dashboard = true включаем панель мониторинга

Наконец, обратите внимание на:

[certificatesResolvers.letsencrypt.acme]
  email = "your@email.com"
  storage = "/certificates/acme.json"
  [certificatesResolvers.letsencrypt.acme.httpChallenge]
    entryPoint = "web"

Здесь устанавливается конфигурация Let’s Encrypt. Мы определили, где будут храниться сертификаты, а также тип проверки, которым является HTTP-запрос.

Затем, предполагая, что вы обновили записи DNS своего доменного имени, создайте две новые записи A, которые обе указывают на общедоступный IP-адрес вашего инстанса:

  1. django-traefik.your-domain.com — для веб-сервиса
  2. dashboard-django-traefik.your-domain.com — для панели управления Traefik

Обязательно замените your-domain.com на свой реальный домен.

Затем обновите docker-compose.prod.yml следующим образом:

# docker-compose.prod.yml

version: '3.8'

services:
  web:
    build:
      context: ./app
      dockerfile: Dockerfile.prod
    command: bash -c 'while !</dev/tcp/db/5432; do sleep 1; done; gunicorn --bind 0.0.0.0:8000 config.wsgi'
    expose:  # new
      - 8000
    environment:
      - DEBUG=0
      - DATABASE_URL=postgresql://django_traefik:django_traefik@db:5432/django_traefik
      - DJANGO_ALLOWED_HOSTS=.your-domain.com
    depends_on:
      - db
    labels:  # new
      - "traefik.enable=true"
      - "traefik.http.routers.django.rule=Host(`django-traefik.your-domain.com`)"
      - "traefik.http.routers.django.tls=true"
      - "traefik.http.routers.django.tls.certresolver=letsencrypt"
  db:
    image: postgres:13-alpine
    volumes:
      - postgres_data_prod:/var/lib/postgresql/data/
    expose:
      - 5432
    environment:
      - POSTGRES_USER=django_traefik
      - POSTGRES_PASSWORD=django_traefik
      - POSTGRES_DB=django_traefik
  traefik:  # new
    build:
      context: .
      dockerfile: Dockerfile.traefik
    ports:
      - 80:80
      - 443:443
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./traefik-public-certificates:/certificates"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.dashboard.rule=Host(`dashboard-django-traefik.your-domain.com`)"
      - "traefik.http.routers.dashboard.tls=true"
      - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.middlewares=auth"
      - "traefik.http.middlewares.auth.basicauth.users=testuser:$$apr1$$jIKW.bdS$$eKXe4Lxjgy/rH65wP1iQe1"

volumes:
  postgres_data_prod:
  traefik-public-certificates:

Опять же, не забудьте заменить your-domain.com на свой фактический домен.

Что здесь нового?

В web сервисе мы добавили следующие метки:

  1. traefik.http.routers.django.rule=Host(`django-traefik.your-domain.com`) меняет хост на фактический домен
  2. traefik.http.routers.django.tls=true позволяет HTTPS
  3. traefik.http.routers.django.tls.certresolver=letsencrypt устанавливает издателя сертификата как Let’s Encrypt

Затем для службы traefik мы добавили соответствующие порты и том для каталога сертификатов. Том (volume) гарантирует, что сертификаты сохранятся, даже если контейнер выйдет из строя.

Что касается меток:

  1. traefik.http.routers.dashboard.rule=Host(`dashboard-django-traefik.your-domain.com`) определяет хост панели инструментов, поэтому к нему можно получить доступ по адресу $Host/dashboard/
  2. traefik.http.routers.dashboard.tls=true позволяет HTTPS
  3. traefik.http.routers.dashboard.tls.certresolver=letsencrypt устанавливает преобразователь (resolver) сертификатов в Let’s Encrypt
  4. traefik.http.routers.dashboard.middlewares=auth позволяет HTTP BasicAuth middleware
  5. traefik.http.middlewares.auth.basicauth.users определяет имя пользователя и хешированный пароль для входа в систему

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

# username: testuser
# password: password

$ echo $(htpasswd -nb testuser password) | sed -e s/\\$/\\$\\$/g
testuser:$$apr1$$jIKW.bdS$$eKXe4Lxjgy/rH65wP1iQe1

Не стесняйтесь использовать env_file для хранения имени пользователя и пароля в качестве переменных среды.

USERNAME=testuser
HASHED_PASSWORD=$$apr1$$jIKW.bdS$$eKXe4Lxjgy/rH65wP1iQe1

Затем обновите переменную среды ALLOWED_HOSTS в config/settings.py следующим образом:

# config/settings.py

ALLOWED_HOSTS = env('DJANGO_ALLOWED_HOSTS', default=[])

Наконец, добавьте новый Dockerfile под названием Dockerfile.traefik:

# Dockerfile.traefik

FROM traefik:v2.2

COPY ./traefik.prod.toml ./etc/traefik/traefik.toml

Затем запустите новые контейнеры:

$ docker-compose -f docker-compose.prod.yml up -d --build

Убедитесь, что ваши два URL-адреса работают:

  1. https://django-traefik.your-domain.com
  2. https://dashboard-django-traefik.your-domain.com/dashboard/

Также убедитесь, что при доступе к HTTP-версиям вышеуказанных URL-адресов вы перенаправляетесь на HTTPS-версии.

Наконец, сертификаты Let’s Encrypt имеют срок действия 90 дней. Treafik автоматически обновит сертификаты за вас, так что вам придется беспокоиться на одну вещь меньше!

Статические файлы

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

Сначала добавим его в файл requirements.txt:

Django==3.2.3
django-environ==0.4.5
gunicorn==20.1.0
psycopg2-binary==2.8.6
whitenoise==5.2.0

Обновите middleware в config/settings.py следующим образом:

# config/settings.py

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',  # new
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

Затем настройте обработку ваших статических файлов с помощью STATIC_ROOT:

# config/settings.py

STATIC_ROOT = BASE_DIR / 'staticfiles'

Наконец, добавьте поддержку сжатия и кеширования:

# config/settings.py

STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Для тестирования обновите образы и контейнеры:

$ docker-compose -f docker-compose.prod.yml up -d --build

Соберите статические файлы:

$ docker-compose -f docker-compose.prod.yml exec web python manage.py collectstatic

Убедитесь, что статические файлы правильно обслуживаются в https://django-traefik.your-domain.com/admin.

Заключение

В этом руководстве мы рассмотрели, как поместить приложение Django в контейнер с помощью Postgres для разработки. Мы также создали готовый к работе файл Docker Compose, настроили Traefik и Let’s Encrypt для обслуживания приложения через HTTPS и включили безопасную панель инструментов для мониторинга наших сервисов.

Что касается фактического развертывания в производственной среде, вы, вероятно, захотите использовать:

  1. Полностью управляемая служба базы данных — такая как RDS или Cloud SQL — вместо того, чтобы управлять собственным экземпляром Postgres внутри контейнера.
  2. Пользователя без полномочий root для служб

Вы можете найти код в репозитории django-docker-traefik.

Была ли вам полезна эта статья?
[2 / 5]

Spread the love
Подписаться
Уведомление о
guest
1 Комментарий
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Миаил
Миаил
3 лет назад

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