Цей допис розрахований на юних(та не дуже:) падаванів на шляху до становлення джедаєм в розробці web-додатків за допомогою Django.
Поговоримо про те, коли, рано чи пізно, ви зіткнетеся з питанням - йой, а як же його задеплоїти на сервері, в хмарі, локально, на компі бабусі (потрібне підкреслити)? Що потрібно зробити, щоб було достатньо однієі команди для безболісного деплою?
Правильно! Docker!
Docker
- це магія для розробників, яка допомагає запускати наші програми в спеціальних контейнерах. Контейнери допомагають зробити наш додаток "переносимим", а це означає, що ми можемо запускати його на будь-якому комп'ютері або хмарному сервері, і не хвилюватись, чи все правильно налаштовано.
Мабуть, ви чули про Docker, але могли стикнутись з невдалими спробами його використання. Не хвилюйтесь, я сам декілька разів попадав у такі ж халепи. Тому я зібрав свій досвід у цій статті, щоб поділитись з вами найкращим рішенням, яке спростить ваш процес деплою.
Ми покроково розглянемо, як поєднати силу Django та Docker для безболісного деплою вашого проекту. Не треба витрачати час на нудні пошуки гайдів - давайте разом розберемося, як зробити ваше деплоїнг життя простішим і веселішим!
Щоб почати нашу пригоду з Docker, зверніться до офіційної документації Docker для його встановлення. Розглядати це тут ми не будемо.
Отже,
Підготовка Django до деплою
Virtual environment (не pyvenv єдиним!)
В своїй повсякденній практиці я використовую Poetry
- прекрасна альтернатива pip
.
Що ж це за звір такий та як він працює?
Poetry
- це потужний інструмент для управління залежностями та віртуальним середовищем у вашому проекті. Він дозволяє створювати ізольовані середовища для вашого додатку, де можна встановлювати і оновлювати залежності без впливу на інші проекти або систему в цілому.
Чому Poetry
, а не звичайний pyvenv
або pip
? Він має багато переваг, включаючи зручний синтаксис для встановлення пакетів, автоматичне створення та оновлення файлу pyproject.toml
, а також підтримку requirements.txt
. Poetry
робить управління залежностями більш зрозумілим та зручним.
З Poetry все надзвичайно просто. По-перше, встановіть Poetry у вашій системі (детальні інструкції можна знайти на офіційному сайті Poetry). Потім, у папці вашого Django проекту, виконайте команду poetry init, яка допоможе створити новий проект або використати існуючий. Виберіть свої налаштування та введіть необхідну інформацію про ваш проект.
Додайте необхідні залежності
Після того, як ми ознайомилися з Poetry та його простотою управління залежностями, давайте перейдемо до кількох додаткових кроків, щоб наш Django проект був готовий до деплою.
Для запуску проекту та деплою ми будемо використовувати gunicorn - потужний WSGI-сервер (Web Server Gateway Interface). Це забезпечить швидкий та надійний запуск нашого Django додатку.
poetry add gunicorn
Тепер, для того щоб наш Django проект міг працювати з базою даних Postgresql, потрібно встановити залежність psycopg2:
poetry add psycopg2-binary
Після виконання цих команд в директорії вашого проекту з'являться два файли:
-
pyproject.toml
це основний файл конфігурації вашого проекту, де містяться всі залежності та налаштування. -
poetry.lock
це файл з замкнутими версіями залежностей, які гарантують стабільність у вашому проекті. Ви можете ігнорувати цей файл у системі контролю версій, оскільки Poetry буде автоматично виправляти його при встановленні залежностей.
Завдяки Poetry, ми зберегли наші залежності у віртуальному середовищі, що робить наш Django проект більш незалежним та структурованим.
Отже, virtual environment готовий до деплою.
Сконфігуруйте settings.py
та urls.py
під "продакшн" та "local development"
Перш за все створіть .env
файл для визначення змінних оточнення (кредли БД, хости і так далі)
#.env
DB_PORT=5432
DB_HOST=projectname_postgres # ім'я хоcту в мережі Docker
POSTGRES_DB=postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
Далі треба створити файл local_settings.py
та покласти його в теку ядра проекту (там, де settings.py
)
# local_settings.py
from .settings import *
# Додаємо '127.0.0.1' до ALLOWED_HOSTS, щоб Django міг обслуговувати запити з localhost
ALLOWED_HOSTS = ['127.0.0.1', 'localhost']
# Використовуємо SQLite базу даних для локального розробки
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Додаємо дебаг-режим для локальної розробки
DEBUG = True
Редагуємо основний файл налаштувань settings.py
:
# settings.py
import os
...
# Вказуємо реальні хости доменів, які Django може обслуговувати на продакшн сервері
ALLOWED_HOSTS = ['example.com', 'www.example.com']
# Використовуємо PostgreSQL базу даних для продакшн сервера
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('POSTGRES_DB'),
'USER': os.environ.get('POSTGRES_USER'),
'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),
'HOST': os.environ.get('DB_HOST'), # або адреса вашого PostgreSQL сервера
'PORT': os.environ.get('DB_POST'), # порт (залиште порожнім, якщо використовуєте дефолтний порт)
}
}
# Вимикаємо дебаг-режим для продакшн сервера
DEBUG = False
# Описуємо налаштування для статики та медіа
STATIC_ROOT = BASE_DIR / 'static'
STATIC_URL = '/static/'
MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL = '/media/'
Також потрібно доповнити корний файл urls.py
для фетчінгу статики та медіа якщо дебаг режим ввимкнений:
# urls.py
from django.contrib.staticfiles.views import serve
from django.urls import path, include
...
static_and_media_urls = [
path('static/<path:path>', serve, {'document_root': settings.STATIC_ROOT}),
path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT}),
]
urlpatterns = [...]
urlpatterns + static_and_media_urls
Все! Ваш Django-проект готовий до деплою!
Готуємо Docker
Тепер, коли ми підготували наш Django проект та налаштували віртуальне середовище за допомогою Poetry, настав час перейти до Docker. Ця чарівна технологія дозволить нам упакувати наш додаток та всі його залежності у контейнери, що забезпечить легке та безпечне деплою на будь-якому сервері або хмарній платформі.
Створимо дві директорії в корневій директорії проекту:
/backend
/nginx
В директорії backend створюємо два файли: DockerFile
та docker-entrypoint.sh
DockerFile:
FROM python:3.10-buster # обираємо версію Python на якій буде працювати проект
# описуємо вірт.оточення:
ENV PYTHONBUFFERED=1 \
POETRY_VERSION=1.4.2 \
POETRY_VIRTUALENVS_CREATE="false"
RUN pip install "poetry==$POETRY_VERISON" # встановлюємо Poetry
# Вказуємо робочу теку:
WORKDIR /app
# копіюємо файли залежностей та баш-скрипт в корінь контейнера:
COPY pyproject.toml poetry.lock docker-entrypoint.sh ./
# встановлюємо залежності
RUN poetry install --no-interaction --no-ansi --no-dev
# копіюємо проект в робочу теку:
COPY project /app
# вказуємо порт
EXPOSE 8000
# даємо права на виконання ентріпоінту
RUN chmod +x docker-entrypoint.sh
ENTRYPOINT ["./docker-entrypoint.sh"]
docker-entrypoint
#!/bin/sh
set -e
until cd /app
do
echo "Wait for server volume..."
done
# робимо міграції перед запуском wsgi сервера
until python manage.py migrate
do
echo "Waiting for postgres ready..."
done
# збираємо статику
python manage.py collectstatic
# та запускаємо wsgi сервер за допомогою gunicorn
gunicorn project.wsgi:application --bind 8000 --workers 4 --threads 4 # project - це ім'я вашого проекту
Django ми вже остаточно підготували до деплою, тому тепер перейдемо до конфігурації контейнера
NGINX
В теці nginx створюємо: DockerFile
FROM nginx:stable-alpine
CMD ["nginx", "-g", "daemon off;"]
# копіюємо файли ssl сертифікатів, попередньо замовивши-створивши їх для свого домену
COPY nginx/ca.crt /etc/nginx/ssl/ca.crt
COPY nginx/your-domain.com.crt /etc/nginx/ssl/your-domain.com.crt
COPY nginx/your-domain.com.key /etc/nginx/ssl/your-domain.com.key
conf.d
Файл конфігурації nginx
server {
listen 80;
server_name your-domain.com www.your-domain.com;
rewrite ^ https://$server_name$request_uri? permanent;
}
server {
listen 443 ssl;
server_name your-domain.com www.your-domain.com;
server_tokens off;
ssl_certificate /etc/nginx/ssl/your-domain.com.crt;
ssl_certificate_key /etc/nginx/ssl/your-domain.com.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
keepalive_timeout 70;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_trusted_certificate /etc/nginx/ssl/ca.crt;
access_log /var/log/nginx/your-domain.com.access.log;
error_log /var/log/nginx/your-domain.com.su.error.log;
location /admin {
try_files $uri @proxy_api;
}
location @proxy_api {
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Url-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://project_django_1:8000;
}
location /static { alias /app/static; }
location /media { alias /app/media; }
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://project_django_1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
}
}
Фух, так?...:)
Вже майже все!
Тепер нам залишилося сворити найважливіший файл - docker-compose.yaml
Що ж це за файл такий і нащо він потрібен?
docker-compose.yaml
- це файл конфігурації для Docker Compose, інструмента, що дозволяє вам описувати та запускати багатоконтейнерні додатки з легкістю. У цьому файлі ви можете визначити усі контейнери, що складають ваш додаток, а також налаштування для кожного контейнера. Це дозволяє вам встановити всі контейнери за одну команду та легко керувати їх взаємодією.
Чому він потрібен?
docker-compose.yaml
забезпечує простий та стандартизований спосіб описувати ваш додаток та його середовище. Завдяки цьому файлу, інші розробники можуть легко розгортати ваш додаток на своїх комп'ютерах або серверах без необхідності докладного дослідження і налаштування.
Також docker-compose.yaml
дозволяє зберігати всі налаштування проекту в одному місці, що спрощує та зберігає наш процес деплою організованим та структурованим.
Створення docker-compose.yaml
Давайте створимо docker-compose.yaml
для нашого Django проекту. Відкрийте текстовий редактор та створіть новий файл з назвою docker-compose.yaml
у кореневій папці вашого проекту. Додайте такий зміст:
version: '3'
services:
postgres:
restart: unless-stopped
image: postgres:13.1-alpine
env_file:
- ./.env
volumes:
- postgres_data:/var/lib/postgresql/data/
networks:
- project_network
django:
restart: unless-stopped
build:
context: .
dockerfile: Dockerfile
env_file:
- ./.env
volumes:
- static_volume:/app/static
- media_volume:/app/media
networks:
- project_network
depends_on:
- postgres
nginx:
restart: unless-stopped
build:
context: .
dockerfile: ./nginx/DockerFile
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d/default.conf
- static_volume:/app/static
- media_volume:/app/media
networks:
- project_network
depends_on:
- django
volumes:
static_volume:
media_volume:
postgres_data:
networks:
project_network:
driver: bridge
Опис сервісів
Опис кожного сервісу:
postgres
: Цей сервіс використовує образ PostgreSQL версії 13.1, з базовим образом Alpine Linux. Він має зазначені параметри restart: unless-stopped
для автоматичного перезапуску сервісу, якщо він припинить роботу (крім явного зупинення). env_file
вказує на файл .env, де містяться змінні оточення для контейнера. Використовується том postgres_data
, щоб зберігати дані PostgreSQL між рестартами контейнера. django
: Цей сервіс збирається з використанням Dockerfile, що знаходиться в поточній директорії (context: .
) і має назву Dockerfile
. Також використовує файл .env
для змінних оточення. Використовує томи static_volume і media_volume
для зберігання статичних та медіафайлів між рестартами контейнера. Залежить від сервісу postgres
, щоб мати доступ до бази даних. nginx
: Цей сервіс будується з використанням Dockerfile
, що знаходиться в папці ./nginx
. Він перенаправляє порти 80 та 443 з контейнера на відповідні порти на локальній машині. Монтує файли конфігурації Nginx з локальної папки ./nginx/prod/conf.d
. Використовує томи static_volume
і media_volume
для доступу до статичних і медіафайлів. Залежить від сервісу django
, щоб мати доступ до вашого Django додатку через Gunicorn
.
Також, у файлі є визначені томи (volumes
) і мережа (networks
) для спільного використання даних та мережі між контейнерами.
Запуск за допомогою Docker Compose
Для запуску проекту за допомогою Docker Compose відкрийте командний рядок у кореневій папці вашого проекту та виконайте таку команду:
docker-compose up -d --buid
Тепер ваш Django додаток та база даних PostgreSQL будуть запущені, і ваш проект буде доступний за адресою https://your-domain.com.
Готово!
Тепер у нас є повністю підготовлений Django проект, готовий до деплою з використанням Docker та Docker Compose. Ви можете деплоїти його на будь-якому сервері або хмарній платформі з легкістю.
Дякую, що приєдналися до нашої пригоди у розробці web-додатків з Django та Docker. Бажаю вам успіхів у вашому джедайському шляху!
P.S. Корисні команди Docker та Docker-compose
Команди Docker:
docker build
: Збирає Docker образ з Dockerfile. Приклад:docker build -t my_image_name:latest
.docker run
: Запускає контейнер із вибраним образом. Приклад:docker run -d -p 8000:80 my_image_name:latest
docker ps
: Показує список активних контейнерів. Приклад:docker ps
docker stop
: Зупиняє активний контейнер. Приклад:docker stop container_id
docker rm
: Видаляє зупинений контейнер. Приклад:docker rm container_id
docker images
: Показує список доступних Docker образів. Приклад:docker images
docker rmi
: Видаляє Docker образ. Приклад:docker rmi image_id
docker exec
: Виконує команду всередині контейнера. Приклад: `docker exec -it container_id commanddocker logs
: Переглядає логи контейнера. Приклад:docker logs container_id
Команди Docker Compose:
docker-compose up
: Піднімає всі контейнери зі складуdocker-compose.yaml
. Приклад:docker-compose up -d
(запуск в фоновому режимі)docker-compose down
: Зупиняє та видаляє всі контейнери, створені за допомогою docker-compose up. Приклад:docker-compose down
docker-compose ps
: Показує статус контейнерів, визначених у docker-compose.yaml. Приклад:docker-compose ps
docker-compose logs
: Переглядає логи всіх контейнерів з docker-compose.yaml. Приклад:docker-compose logs
docker-compose exec
: Виконує команду всередині контейнера, визначеного в docker-compose.yaml. Приклад:docker-compose exec service_name command
docker-compose build
: Збирає образи для всіх контейнерів, визначених у docker-compose.yaml. Приклад:docker-compose build
docker-compose rm
: Видаляє зупинені контейнери, визначені у docker-compose.yaml. Приклад:docker-compose rm