Оригинальная статья: Amal Shaji — Dockerizing 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, если у вас его еще нет, добавьте 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) вместе с двумя переменными среды:
PYTHONDONTWRITEBYTECODE
: Запрещает Python записывать файлы pyc на диск (эквивалент опции python -B)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, нам нужно добавить новую службу в файле 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, сервер 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.
Создайте новый файл 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? Ознакомьтесь с официальным руководством Getting Started по началу работы.
Traefik vs Nginx: Traefik — это современный обратный HTTP-прокси и балансировщик нагрузки. Его часто сравнивают с Nginx, веб-сервером и обратным прокси. Поскольку Nginx в первую очередь является веб-сервером, его можно использовать для обслуживания веб-страницы, а также в качестве обратного прокси-сервера и балансировщика нагрузки. В целом Traefik проще запустить, а Nginx более универсален.
Traefik:
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
службе следующие метки:
traefik.enable=true
позволяет Traefik обнаружить службуtraefik.http.routers.django.rule=Host(`django.localhost`)
когда запрос имеет Host = django.localhost, запрос перенаправляется на эту службуОбратите внимание на volumes в сервисе traefik:
"$PWD/traefik.dev.toml:/etc/traefik/traefik.toml"
сопоставляет локальный файл конфигурации с файлом конфигурации в контейнере, чтобы настройки синхронизировались"/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:
Когда закончите, выключите контейнеры и тома:
$ docker-compose down -v
Мы успешно создали рабочий пример 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 своим адресом электронной почты.
Что тут происходит:
entryPoints.web
устанавливает точку входа для нашего небезопасного HTTP-приложения на порт 80entryPoints.websecure
устанавливает точку входа для нашего защищенного приложения HTTPS на порт 443entryPoints.web.http.redirections.entryPoint
перенаправляет все небезопасные запросы на защищенный портexposedByDefault = false
закрываем все остальные сервисы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-адрес вашего инстанса:
django-traefik.your-domain.com
— для веб-сервиса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 сервисе мы добавили следующие метки:
traefik.http.routers.django.rule=Host(`django-traefik.your-domain.com`)
меняет хост на фактический доменtraefik.http.routers.django.tls=true
позволяет HTTPStraefik.http.routers.django.tls.certresolver=letsencrypt
устанавливает издателя сертификата как Let’s EncryptЗатем для службы traefik мы добавили соответствующие порты и том для каталога сертификатов. Том (volume) гарантирует, что сертификаты сохранятся, даже если контейнер выйдет из строя.
Что касается меток:
traefik.http.routers.dashboard.rule=Host(`dashboard-django-traefik.your-domain.com`)
определяет хост панели инструментов, поэтому к нему можно получить доступ по адресу $Host/dashboard/traefik.http.routers.dashboard.tls=true
позволяет HTTPStraefik.http.routers.dashboard.tls.certresolver=letsencrypt
устанавливает преобразователь (resolver) сертификатов в Let’s Encrypttraefik.http.routers.dashboard.middlewares=auth
позволяет HTTP BasicAuth
middlewaretraefik.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-адреса работают:
Также убедитесь, что при доступе к 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 и включили безопасную панель инструментов для мониторинга наших сервисов.
Что касается фактического развертывания в производственной среде, вы, вероятно, захотите использовать:
Вы можете найти код в репозитории django-docker-traefik.
Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…
Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…
Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…
Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…
Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…
Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…
View Comments
Статья обалденная , по контенту супер , было бы супер если тоже самое с кубернетесом появилось