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. Через несколько минут все что нужно для приложения будет работать.