Разворачиваем Django с Ansible

31/05/2019

ansible automation

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

Добавить комментарий

Ваш адрес email не будет опубликован.