31/05/2019

Мне нравится писать программы на языке программирования Python. На этом языке есть популярный фреймворк Django. С помощью него можно создавать серьезные веб приложения. Для запуска работы этого сервиса нам как правило нужнны Nginx, PostgreSQL или MySQL, Gunicorn, а также сам фреймворк Django и несколько подсобных библиотек. Частенько бывают нужны и другие приложения, например Memcached, Redis или RabbitMQ. В этой статье не будем их затрагивать, чтобы чрезмерно не усложнять материал. Каждый раз, запуская сервер для работы с проектом Django, хочется получать готовую среду. Тратить по нескольку часов на установку и базовую настройку всех приложений — утомительное и скучное занятие. С помощью ролей Ansible мы этот процесс можем ускорить с минимумом усилий с нашей стороны при разворачивании.
Ранее в блоге писал, как упростить себе жизнь с помощью Packer (Создаем образ ОС с Packer) и Vagrant (Vagrant — основы работы). Эти два инструмента позволяют автоматизировать разворачивание операционной системы на этапе разработки и тестирования. Добавив к ним систему управления конфигурациями Ansible, мы можем автоматизировать максимум задач по развертыванию сервера, для начала работы с Django. С помощью ролей Ansible мы установим необходимые пакеты и программное обеспечение, выполнив базовую настройку при этом. После выполнения этих ролей, результатом станет готовый сервер с работающим приложением. Необходимость в ручной работе по установке и настройке при этом сведется на ноль.
Установка базовых пакетов
Создадим роль Ansible, которая установит в систему базовые пакеты, которые необходимы Django для того, чтобы он запустился. А также для того, чтобы приложение потом смогло работать с необходимым функционалом. У меня эта роль называется andreyus.servergeneral. Создадим папку с таким названием в местенахождении ролей Ansible на нашем управляющем сервере. В этой папке создадим структуру каталогов, как это требуется для каждой роли. Выполняем команду #mkdir files handlers meta templates tasks vars. В данной конкретной роли у нас будет использоваться только папка tasks. В ней создадим файл main.yml со следующим содержимым.
---
- name: Install base needed apt-packages
apt:
pkg:
- python3-dev
- python3-virtualenv
- python3-pip
- tcl-dev
- tk-dev
- python3-tk
- git
- virtualenv
state: latest
Так как, я поклоник Ubuntu — в примере привожу работу именно с этой системой. Если нам необходимо проделать аналогичные действия в CentOS, Red Hat или еще каком-то дистрибутиве Linux, то мы должны использовать соответствующий модуль вместо apt в файле main.yml. Также использую для работы Django Python 3 версии. Соответственно все пакеты для Django базируются на базе Python3.
Nginx
С помощью роли Ansible для Nginx мы установим веб сервер для взаимодействия с пользователями. Веб сервер будет подключаться к WSGI серверу Gunicorn. Именно через Gunicorn будет запускаться Django приложение. В файле конфигурации веб сервера мы укажем стыковку с Gunicorn через UNIX socket. По аналогии с предыдущей ролью создаем роль andreyus.nginx и группу директорий в ней. Файл tasks/main.yml представлен ниже.
---
- name: Install Nginx
apt: name=nginx state=latest update_cache=true
register: nginxinstalled
notify:
- nginx start
- name: Add Nginx cofig
when: nginxinstalled is success
template: src=default.j2 dest=/etc/nginx/sites-available/default owner=www-data group=www-data
- name: Create Root Directory for Nginx
when: nginxinstalled is success
file: path={{ root }} mode=775 state=directory owner=www-data group=www-data
notify:
- nginx restart
Роль для Nginx будет использовать также файлы с переменными и темплейтами. В папке с темплейтами создадим шаблон конфигурации дефолтного веб сервера, который будет открываться при запросе по HTTP. Файл с шаблоном templates/default.j2 ниже.
server {
listen 80 default_server;
server_name _;
location / {
proxy_pass http://unix:/run/gunicorn.sock;
error_page 500 502 503 504 /50x.html;
}
location = /50x.html {
root /usr/share/nginx/html;
}
}
В конфигурации веб сервера мы указали брать содержимое через UNIX сокет /run/gunicorn.sock. На этом сокете будет работать Gunicorn.
Теперь создадим файлик handlers/main.yml, который будет отвечать за запуск и перезагрузку процесса nginx.
---
- name: nginx start
service: name=nginx state=started
- name: nginx restart
service: name=nginx state=restarted
Также добавим в конфигурацию роли nginx файл c переменными vars/main.yml, в котором отразим их значения, используемых в роли.
---
hostname: django.domain.local
root: /usr/share/nginx/vhosts
domain: djdomain
Пожалуй с настройкой nginx это все.
Postgresql
Предпочитаю по возможности из реляционных СУБД использовать Postgresql. Соответственно при разворачивании сервера с Django приложением, установим и настроим базу данных на базе Postgresql. Для этого на нашей машине управления с Ansible создаем роль andreyus.postgresql и соответствующие директории для роли. Файл tasks/main.yml, с инструкциями по установке ПО Postgresql и созданию БД для приложения и пользователя СУБД представлен ниже.
---
- name: Install PostgreSQL
apt:
pkg:
- postgresql
- postgresql-contrib
- postgresql-server-dev-all
- python3-psycopg2
- python-psycopg2
state: latest
- name: Start and enable postgres
service: name=postgresql enabled=yes state=started
- name: Create database
postgresql_db: name={{ db_name }}
become_user: postgres
become: yes
- name: Create user
postgresql_user: db={{ db_name }}
name={{ db_user }}
password={{ db_password }}
priv=ALL
state=present
role_attr_flags=NOSUPERUSER,NOCREATEDB
become: yes
become_user: postgres
Так же в этой роли нам понадобится файл с переменными vars/main.yml
---
db_user: mydjangouser
db_password: SOMEPASSWORD!!!
db_name: djproject
И файл с хендлерами handlers/main.yml.
---
- name: postgresql start
service: name=postgresql state=started
- name: postgresql restart
service: name=postgresql state=restarted
В этой роли это все файлы, которые будут использоваться. На выходе мы получим готовую базу данных в СУБД Postgresql для работы с нашим приложением.
Django
Сам фреймворк Django написан на Python и устанавливается в систему с помощью менеджера пакетов для Python — pip. В Ansible есть специальные модули как для работы с pip, так и с django. Благодаря этим модулям, инсталяция и настройка проекта в django через Ansible становится предельно комфортной. Для данной роли создадим папку andreyus.django и соответствующие директории в ней. Содержание файла tasks/main.yml с задачами по установке и настройке проекта представлено ниже.
---
- name: Creates directory
file: path={{project_name_path}} state=directory
- name: Install Django Framework
pip:
name: django
virtualenv: "{{project_name_path}}/env"
virtualenv_command: virtualenv
virtualenv_python: python3
- name: Instal python library for PSQL
pip:
name: psycopg2
virtualenv: "{{project_name_path}}/env"
virtualenv_command: virtualenv
virtualenv_python: python3
- name: Install a django project
command: "{{ project_name_path }}/env/bin/django-admin.py startproject {{ project_name }} chdir={{ project_name_path }}/"
- name: Create Settings File for Django
template: src=settings.py.j2 dest={{ project_name_path }}/{{ project_name }}/{{ project_name }}/settings.py
- name: Make migrations
shell: "{{project_name_path}}/env/bin/python3 {{ project_name_path }}/{{ project_name }}/manage.py makemigrations"
- name: Migrate database
django_manage: app_path={{ project_name_path }}/{{ project_name }}
command=migrate
virtualenv={{project_name_path}}/env
- name: Get all static files
django_manage: app_path={{ project_name_path }}/{{ project_name }}
command=collectstatic
virtualenv={{project_name_path}}/env
Кроме файла с выполняемыми задачами в этой роли нам понадобится vars/main.yml с использумемыми переменными.
---
project_name_path: /usr/share/nginx/djangoproject
project_name: djangoproject
А также будет использоваться шаблон файла настроек проект Django templates/settings.py.j2. Исходники для шаблона можем взять в любой инсталяции Django. Ниже приведу часть файла настроек, в которой мы пропишем способ связи с базой данных PostgreSQL. Все остальные параметры файла настроек оставим дефолтными.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'djproject',
'USER': 'mydjangouser',
'PASSWORD': 'SOMEPASSWORD!!!',
'HOST': 'localhost',
'PORT': '',
}
}
Итогом выполнения роли станет работающий пустой Django сервис.
Gunicorn
Gunicorn — WSGI сервис, позволяющий эффективно запускать HTTP сервисы Django в многопроцессорной и многопоточной системе. Будем использовать его для выполнения кода нашего приложения. Для установки и настройки этого сервиса создадим роль andreyus.gunicorn со всеми соответствующими папками в нем. Содержимое файла tasks/main.yml этой роли представлено ниже.
---
- name: Install Gunicorn
pip:
name: gunicorn
virtualenv: "{{project_name_path}}/env"
virtualenv_command: virtualenv
virtualenv_python: python3
- name: Create Gunicorn Socket file
template: src=gunicorn.socket.j2 dest=/etc/systemd/system/gunicorn.socket
- name: Create Gunicorn Service file
template: src=gunicorn.service.j2 dest=/etc/systemd/system/gunicorn.service
- name: Start Gunicorn.socket
shell: "/bin/systemctl start gunicorn.socket"
- name: Enable Gunicorn.socket
shell: "/bin/systemctl enable gunicorn.socket"
Как видно выше мы используем 2 файла с шаблонами для настройки запуска Gunicorn через systemd. Это templates/gunicorn.socket.j2 для описания конфигурации сокета.
[Unit] Description=gunicorn socket [Socket] ListenStream=/run/gunicorn.sock [Install] WantedBy=sockets.target
А также templates/gunicorn.service.j2 с параметрами для запуска сервиса Gunicorn.
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory={{ project_name_path }}/{{ project_name }}
ExecStart={{ project_name_path }}/env/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn.sock \
{{ project_name }}.wsgi:application
[Install]
WantedBy=multi-user.target
Кроме этого в данной Ansible роли мы будем также использовать файл с переменными vars/main.yml.
---
project_name_path: /usr/share/nginx/djangoproject
project_name: djangoproject
После выполнения данной роли получим работающий сервис для запуска Django приложения.
Заключение
Выше мы показали конфигурацию пяти Ansible ролей, которые в сумме позволяют нам произвести оперативную настройку сервера под проект с Django фреймворком. Нам остальнось запустить небольшой playbook, который поочередно выполнит эти роли на сервере. Назовем этот playbook — django-allroles.yml
---
- hosts: django-servers
become: true
roles:
- andreyus.servergeneral
- andreyus.nginx
- andreyus.postgresql
- andreyus.django
- andreyus.gunicorn
Теперь при разворачивании нового сервера с приложением Django, достаточно лишь запустить этот playbook. Через несколько минут все что нужно для приложения будет работать.