Django-стек: работа, установка и настройка на одном сервере

В предыдущей статье мы с помощью Terraform создали 3 виртуальных сервера, объединённых маршрутизируемой сетью в VMware Cloud Director для развертывания на них Production ready Django-стека.

Тема непростая, особенно для новичков, поэтому статья про установку Django-стека с помощью Ansible состоит из 2 частей:

  1. в этой части разберёмся как работает Django-стек от и до, научимся устанавливать его на одну машину, поймем, что такое Application-сервер и как работает Gunicorn.
  2. во второй части научимся устанавливать Django-стек с помощью Ansible и познакомимся с альтернативным путём установки — без Ansible.

Начнем с матчасти — разберемся с тем как работает Django-стек, а потом научимся устанавливать его в ручном режиме на одну машину. Поехали!

Как работает Django-стек?

Как работает Django-стек?

Классический Django-стек состоит из 4 базовых элементов: Web-сервера, WSGI-сервера, самого Django и СУБД. Часто его расширяют и добавляют ещё ПО для работы с безопасностью и памятью, но мы рассмотрим принцип работы классической схемы.

 

Графически схема работы Django-стека выглядит так:

Как работает Django-стек?
 

Разберем подробнее работу каждого элемента стека:

  1. Веб-сервер, в нашем случае Nginx, принимает и обрабатывает HTTP-запрос браузера, затем передаёт его в Application-сервер — Gunicorn.
  2. Gunicorn получает данные от Nginx, разбирает их и исходя из своей конфигурации по протоколу WSGI передаёт их в Django.
  3. Django обрабатывает полученные данные и возвращает результат работы обратно в Gunicorn, а он в свою очередь отдаёт результат в Nginx, который возвращает клиенту готовую HTML-страницу.

Общение между Application-сервером и Django происходит по протоколу WSGI — Web Server Gateway Interface. Это специальный протокол для запуска Python-скриптов. У него есть несколько важных особенностей:

  1. Application-сервер и исполняемые скрипты запускаются в одном процессе и должны быть написаны на одном языке программирования.
  2. Скрипты, которые обрабатывают запросы, загружаются в оперативную память заранее и из них вызываются либо функции, либо классы — так называемые callable-объекты.

Django берёт на себя всё, что связано с роутингом URL и логикой обработки запросов, также Django стандартизирует внутреннюю архитектуру Web-приложений, в которых реализуется основная бизнес-логика проекта.

Обратите внимание, по умолчанию Nginx слушает 80 порт, но его можно перенастроить. Будьте внимательны при работе с портами, в Unix-системах есть разделение портов по привилегиям. Порты ниже 1024 являются привилегированными, чтобы работать с ними программа должна быть запущена от имени суперпользователя.

Из исторически сложившихся сочетаний портов и назначений можно отметить:

  1. 20, 21 — FTP;
  2. 22 — SSH;
  3. 25 — SMTP;
  4. 80 порт — HTTP;
  5. 443 — HTTPS.

Для большей наглядности и понимания взаимодействия всех элементов Django-стека — развернем его в ручном режиме на одном виртуальном сервере.

Django и Gunicorn

Для установки Django-стека воспользуемся быстрым и бюджетным виртуальным сервером на базе Open source под управлением Ubuntu 20. Подключимся к нему по SSH и начнем установку. Устанавливать Django мы будем в виртуальную среду — это наиболее желательный сценарий, в таком случае не затрагиваются глобальные настройки сервера и появляется возможность управлять разными версиями одних и тех же пакетов в разных проектах.

Установка Django и Gunicorn

Установка и тестирование Django и Gunicorn должно идти в определенной последовательности во избежание критических ошибок:

  1. Сначала обновим apt-репозитории и установим необходимые для корректной работы Django и Gunicorn Python-пакеты: sudo apt update && apt install -y zlib1g-dev libbz2-dev libreadline-dev llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev liblzma-dev python3-dev python-pil python3-lxml libxslt-dev libffi-dev libssl-dev python-dev gnumeric libsqlite3-dev libpq-dev libxml2-dev libxslt1-dev libjpeg-dev libfreetype6-dev libcurl4-openssl-dev python-libxml2 python3-venv imagemagick graphicsmagick imagemagick-6.q16hdri

    Установка может занять значительное время. Объем устанавливаемых пакетов порядка 1,7 Gb. Это стоит учесть при выборе размера дискового пространства.

  2. После завершения установки пакетов, можно создавать директорию для будущего проекта. Мы создадим папку для проекта по пути: /var/www/django_test. Внутри директории проекта создадим директорию с виртуальным окружением: python3 -m venv [название виртуального окружения]. У нас оно называется env.
  3. Активируем виртуальное окружение командой source env/bin/activate. В левой части строки терминала появится название виртуального окружения:
  4. Теперь можно установить Django, Gunicorn и модуль для подключения Django к PSQL: pip3 install django
    pip3 install psycopg2
    pip3 install gunicorn

Создание тестового проекта и настройка Django

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

  1. Находясь в директории проекта выполните команду django-admin startproject [название проекта]. В нашем случае проект называется django_test. В результате выполнения команды развернется схожая структура:

    Обратите внимание, что при создании проекта, Django автоматически создает одноименное приложение. На скриншоте проект и одноименное приложение подчеркнуты красным.

    Это приложение точка входа в проект. В нём содержатся файлы с расширением .wsgi, именно к нему будет подключаться Gunicorn.

  2. Теперь создадим первое Django-приложение. Для этого перейдем на уровень проекта (django_test) и вызовем скрипт manage.py с директивой startapp: python3 manage.py startapp [название приложения]. Мы назвали приложение first. Теперь структура проекта test_project выглядит так:

  3. Активируем Django-приложение, внесением его в список зарегистрированных приложений. Это делается через файл settings.py, находящейся в одноименном приложении проекта. В нашем случае — test_project.

В файл нужно внести следующие данные:

  1. В список ALLOWED_HOSTS вносятся 2 IP-адреса: IP-адрес виртуального сервера и внутренний сети. Это нужно для того, чтобы избежать ошибки disallowed hosts при запуске Django;
  2. В список INSTALLED_APPS вносятся все созданные приложения.
  • С помощью встроенного development-сервера Django проверим работоспособность приложения — выполним команду python3 manage.py runserver 0.0.0.0:8000, находясь на уровне одноименного с проектом приложения — test_project. Виртуальное окружение должно быть активировано!

    Если всё сделано правильно — вы увидите вывод следующего вида:

Теперь можно перейти в браузер и обратиться к Django: введите IP-адрес сервера и порт, который слушает Django. Браузер откроет дефолтную страницу Django.

Отлично! Django работает исправно. Теперь Настроим Gunicorn.

Настройка Gunicorn

Gunicorn — это Application-сервер для запуска Web-приложений написанных на Python. Основная его задача — это работа в режиме демона и поддержка постоянной работы Web-приложений.

Пошаговая настройка Gunicorn может выглядеть так:

  1. Сначала создадим конфигурационный файл с настройками Gunicorn в формате .py. Мы назвали его gunicorn_config.py. Он размещается в директории одноименного приложения проекта.

    Конфигурационный файл содержит следующие данные:

    command = "/var/www/django_test/env/bin/gunicorn" #путь расположения Gunicorn
    python_path = "/var/www/django_test/test_project/test_project" #путь к разводящему приложению
    bind = "0.0.0.0:8001" #Порт, который будет слушать Django
    workers = 5 # Кол-во запущенных процессов
    user = "www" #Пользователь, от имени которого будет запущен Django
    raw_env = "DJANGO_SETTINGS_MODULE=test_project.settings" #Переменная окружения с setting.py

    Тут мы указали bind = "0.0.0.0:8001". Это сделано в демонстрационных целях, чтобы протестировать работу Gunicorn и его связку с Nginx. В дальнейшем, конечно, мы изменим этот параметр на 127.0.0.1:8001.

  2. После создания конфигурационного файла, можно создать скрипт запуска Gunicorn в формате .sh и разместить его на уровне проекта. Мы создали скрипт gunicorn.sh.

    Скрипт может содержать следующие:

    #!/bin/bash
    source /var/www/django_test/env/bin/activate #активация виртуального окружения
    exec gunicorn -c "/var/www/django_test/test_project/test_project/gunicorn_config.py" test_project.wsgi #запуск Gunicorn с указанием конфигурационного и wsgi файлов

    После сохранения скрипта, на него нужно навесить права на запуск командой chmod +x [название файла] и добавить нового пользователя в систему командой adduser www. Теперь можно запустить скрипт: source gunicorn.sh.

    Если всё сделано верно — вы увидите следующий отчёт Gunicorn:

Отлично! Теперь сделаем Gunicorn демоном.

Делаем из Gunicorn демона

Gunicorn должен постоянно работать, перезагружаться в случае сбоя и автоматически загружаться при старте виртуального сервера или после перезагрузки.

Воспользуемся systemd для создания демон-процесса (юнита) Gunicorn:

  1. Создадим файл gunicorn.service в директории /etc/systemd/system и поместим в него следующие данные:

    [Unit]
    Description=gunicorn daemon
    After=network.target

    [Service]
    User=www #Пользователь, от чьего имени будет выполнен процесс
    Group=www-data #Группа пользователей, от чьего имени будет выполнен процесс
    WorkingDirectory= /var/www/django_test/test_project #Рабочая директория процесса
    ExecStart= /var/www/django_test/test_project/gunicorn.sh #Программа для запуска
    Restart=on-failure #Условие перезапуска процесса

    [Install]
    WantedBy=multi-user.target

    Сохраним файл и навесим на него 775 права командой chmod 775 gunicorn.service. Обновим список юнитов командой systemctl daemon-reload.

  2. Запустим вновь созданный юнит командой systemctl startgunicorn и проверим статус его работы — system status gunicorn. Если всё сделано правильно, вывод команды будет следующим:

Теперь командой system enable gunicorn установим автозапуск Gunicorn при перезагрузке сервера. Проверим доступность Gunicorn — обратимся через браузер по IP-адресу сервера на порт 8001.

Браузер отобразит дефолтную страницу Django:

Теперь, когда Django и Gunicorn настроены и работают исправно можно установить и настроить Nginx и PostgreSQL.

Установка и настройка Nginx

В Django-стеке установка и настройка Nginx — самый простой этап:

  1. Устанавливаем Nginx из стандартных репозиториев Linux: apt install nginx.
  2. Создадим очень простой конфигурационный файл для Nginx в директории /etc/nginx/sites-available. Укажем в нём только порт прослушивания, домен и условия для проксирования: server {
    listen 80; #Порт прослушивания
    server_name 93.159.221.5; #Название домена
    location / {
    proxy_pass http://0.0.0.0:8001; #Проксирование на IP-адрес
    }
    }

    В качестве домена (server_name) мы указали IP-сервера, так делать можно, если у вас нет зарегистрированного домена или нет доступа к файлу hosts.

  3. Сохраним файл (наш конфиг называется django) и создадим символьную ссылку для активации конфигурационного файла: sudo ln -s /etc/nginx/sites-available/django /etc/nginx/sites-enabled/. Ссылку на дефолтный конфиг можно удалить: rm /etc/nginx/sites-enabled/default.
  4. Перезапускаем Nginx командой systemctl restart nginx и вводим в поисковую строку браузера: [IP-адрес сервера]:80. Откроется дефолтная страница Django.

Теперь, когда Django, Gunicorn и Nginx настроены и работают, можно установить и настроить PostgreSQL.

Установка и настройка PostgreSQL

PostgreSQL так же как и Nginx устанавливается из стандартных репозиториев Linux командой sudo apt -y install postgresql. По умолчанию установится PostgreSQL 10, чтобы установить более новый PostgreSQL — нужно добавить репозиторий и выполнить установку. Вот, например, команды установки PostgreSQL 11:

wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - ; \
RELEASE=$(lsb_release -cs) ; \
echo "deb http://apt.postgresql.org/pub/repos/apt/ ${RELEASE}"-pgdg main | sudo tee /etc/apt/sources.list.d/pgdg.list ; \
sudo apt update ; \
sudo apt -y install postgresql-11 ; \

По умолчанию PostgreSQL запускается от имени postgres. Сменим пароль для этого пользователя и создадим новую базу данных:

sudo passwd postgres #Сменя пароля для пользователя postgres
su - postgres #Логин в PostgreSQL пользователем postgres
export PATH=$PATH:/usr/lib/postgresql/10/bin #Экспорт пути для работы с createdb
createdb --encoding UNICODE dtb_db --username postgres #Создание базы данных dtb_db
exit #выход из PosgreSQL

Теперь нужно создать нового пользователя, из-под которого в PSQL будет заходить Django и назначить ему права на создание БД, а также дать все права на управление только что созданной БД:

sudo -u postgres psql #Логинимся в PSQL под пользователем posgres
create user dc with password 'Django_Connecter'; #Создаём пользователя dc с паролем 'Django_Connecter
ALTER USER dc CREATEDB; #Разрешаем пользователю dc создавать БД
grant all privileges on database dtb_db to dc; #Выдаём все права пользователю dc на базу dtb_db
\c dtb_db #Переход в базу данных dtb_db
GRANT ALL ON ALL TABLES IN SCHEMA public to dc; #Дать все права пользователю dc на создание таблиц
GRANT ALL ON ALL SEQUENCES IN SCHEMA public to dc; #Дать все права пользователю dc на создание последовательностей
GRANT ALL ON ALL FUNCTIONS IN SCHEMA public to dc; #Дать все права пользователю dc на создание функций
\q #Выход из БД
exit #Выход из PSQl

Пропишем данные для подключения Django с PSQL. Изменения вносятся в файл settings.py в список DATABASES. Вот что следует указать:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2', #Движок для подключения
'NAME': 'dtb_db', #Название БД для подключения
'USER': 'dc', # Пользователь для подключения к БД
'PASSWORD': 'Django_Connecter', #Пароль пользователя dc
'HOST': '127.0.0.1', #IP на котором хостится PSQL
'PORT': '5432' #Порт, который прослушивает PSQL
}
}

Теперь выполним миграции в БД:

./manage.py makemigrations
./manage.py migrate

Если все данные для подключения Django к PSQL были внесены верно, вы увидите следующий вывод:

Эти строчки означают, что миграция прошла успешно и соединение Django с PSQL работает исправно. На этом установка и настройка Django-стека на один сервер окончена. Соберем теперь всё воедино.

Собираем все знания о Django воедино

Собираем все знания о Django воедино

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

Расширенная схема работы Django-стека с посерверным разделением может выглядеть так:

Кликнете по картинке, чтобы рассмотреть её детально.

Такая цепочка взаимодействий кажется сложной и длинной, однако у нее есть ряд существенных преимуществ:

  1. Отказоустойчивость — элементы Django-стека могут быть разнесены по разным серверам, на которых реализована система мониторинга и инициализации. Например, systemd.
  2. Масштабируемость — некоторые элементы Django-стека, такие, как Web-серверы и серверы баз данных, могут дублироваться в зависимости от нагрузки на серверы.
  3. Гибкость — Django-стек позволяет гибко настраивать каждый свой элемент и предоставляет возможность полностью их менять. Например, вы можете использовать SQLite вместо PostgreSQL или Apache вместо Nginx.
  4. Расширяемость — Django-стек не ограничивается базовым набором элементов. Можно интегрировать и дополнительные элементы. Например, Redis — система управления NoSQL базами данных, Memcached — сервис кэширования данных в оперативной памяти.

Теперь, когда мы узнали достаточно о том, как работают и взаимодействуют между собой базовые элементы Django-стека, мы можем пойти дальше — разделить Django-стек на заранее созданные с помощью Terraform 3 сервера.

Рекомендуем ознакомиться с предыдущими статьями, они помогут вам более детально разобраться в работе Terraform и Ansible: