Django + Docker для безболісного деплою будь-де
Усім привіт, мене звати Дмитро, я працюю Python Software Developer в Workconsult Ukraine.
Сьогодні, доречі, наша компанія святкує 7 років з дня заснування!
Вітаю щиро усіх колег з цим днем! Ми гарна команда!
Ця статя розрахована на юних (та не дуже:) падаванів на шляху до становлення джедаєм в розробці 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 (conf.d/default.conf)
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: ./backend/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/default.conf:/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 --build
Тепер ваш Django-застосунок та база даних PostgreSQL будуть запущені, і ваш проєкт буде доступний за адресою your-domain.com.
Готово!
Тепер у нас є повністю підготовлений Django-проєкт, готовий до деплою з використанням Docker та Docker Compose. Ви можете деплоїти його на будь-якому сервері або хмарній платформі з легкістю.
Дякую, що приєдналися до нашої пригоди у розробці web-застосунків з Django та Docker. Бажаю вам успіхів у вашому джедайському шляху!
P.S. Корисні команди Docker та Docker-compose
- 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 command
- docker 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
43 коментарі
Додати коментар Підписатись на коментаріВідписатись від коментарів