Ansible — популярная система для управления конфигурацией серверов, но не только: с помощью ansible можно также выкатывать (deploy) приложения на тестовые и боевые площадки. Разберем как это делается на примере.

Задача

Пусть у нас есть веб-приложение, исходные коды которого хранятся в системе контроля версий, например git.

Мы хотим реализовать механизм выката новых версий приложения на площадки, который удовлетворял бы следуюшим требованиям:

  • выкат должен происходить без перерывов в работе (без downtime);
  • если в процессе выката возникнут ошибки, выкат должен быть прерван и старая версия приложения должна продолжить работу;
  • должна быть возможность при необходимости откатиться к предыдущей версии веб-приложения;
  • процедура выката должна хорошо масштабироваться с увеличением числа серверов на площадке.

Метод

Один из способов выката без downtime основан на использовании специальной структуры каталогов. Этот способ, в частности, используется в Capistrano. Я впервые познакомился с ним в замечательном автосборщике Haru.

Каждая новая версия приложения выкатывается в отдельный каталог. Например, если сейчас выкачена версия v1.0.0, структура каталогов выглядит следующим образом:

/vagrant
├── releases
│   ├── current -> /vagrant/releases/v1.0.0
│   └── v1.0.0
│       └── index.html
├── shared
└── Vagrantfile

Папка releases содержит версии приложения. Каждая версия – копия приложения, соответствующая определенному тегу из репозитория. Символическая ссылка current указывает на текущую версию.

Файлы, которые должны быть доступны независимо от версии, например, загруженные пользователем картинки, сгенерированные файлы и т.п., помещаются в папку shared.

Процесс выката делится на три этапа:

  1. install: новая версия приложения извлекается из репозитория в отдельный каталог рядом с текущей версией;
  2. configure: на основе шаблонов генерируются необходимые файлы;
  3. link: переключение на новую версию путем изменения символической ссылки.

Первые два этапа подготавливают новую версию приложения к работе, пока работает старая версия приложения. Если установка и конфигурация выполнены успешно на всех серверах, запускается третий этап, линковка, – трафик переключается на новую версию.

После успешного выката версии v1.0.1 структура каталогов примет вид:

/vagrant
├── releases
│   ├── current -> /vagrant/releases/v1.0.1
│   ├── v1.0.0
│   │   └── index.html
│   └── v1.0.1
│       └── index.html
├── shared
└── Vagrantfile

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

Реализация

Исходники сценарие можно посмотреть здесь.

Для выката версии приложения, помеченной тегом v1.0.1, можно воспользоваться следующей командой:

ansible-playbook -i develop deploy/webapp.yml -e deploy_tag=v1.0.1

Сценарий /vagrant/deploy/webapp.yml создает необходимые каталоги и запускает роль library, которая собственно и выкатывает приложение. В данном сценарии выкатывается только одна библиотека, но роль можно использовать несколько раз в одном сценарии, передавая URL репозитария и нужный тег через параметры.

- hosts: webapp
  any_errors_fatal: true

  pre_tasks:
    - name: make sure shared directories exist
      file: dest={{ item }} state=directory
      with_items:
        - "{{ path_releases }}"
        - "{{ path_shared }}"

  roles:
    - role: library
      library_name: example
      library_deploy_tag: "{{ deploy_tag }}"
      library_deploy_src: https://github.com/sergeytsivin/example-lib.git

Скрипт выката описан в файле ansible/deploy/roles/library/tasks/main.yml:

- name: checkout {{ library_name }} lib
  git:
    dest: "{{ library_deploy_dest }}"
    repo: "{{ library_deploy_src }}"
    version: "{{ library_deploy_tag }}"
    accept_hostkey: true
  tags:
    - install

- name: schedule linking {{ library_name }} lib
  command: /bin/true
  notify:
    - link {{ library_name }}
  tags:
    - link

Скрипт очень простой: извлекается версия из репозитория (этап install) и уведомляется обработчик, который должен произвести произвести переключение на новую версию (этап link). Использование обработчика гарантирует, что линковка всех библиотек (если их несколько) будет выполнена после того, как все библиотеки будут успешно установлены и ни один обработчик не будет вызван в случае возникновения ошибок.

Ansible последовательно выполняет команды сценария (playbook), но при этом каждая команда выполняется параллельно на нескольких машинах.

Обработчик ansible/deploy/roles/library/handlers/main.yml переключает символическую ссылку current:

- name: link {{ library_name }}
  file: src={{ item.src }} dest={{ item.dest }} state=link
  with_items:
    - src: "{{ library_deploy_dest }}"
      dest: "{{ library_deploy_current }}"

Благоларя тегам можно запускать этапы выката по отдельности, например для выполнения только этапа установки:

ansible-playbook -i develop deploy/webapp.yml -e deploy_tag=v1.0.1 --tags install

Вывод

Таким образом, с помощью ansible можно реализовать простой и удобный механизм выката, не прибегая к помощи пециализированных инструментов, таких как Capistrano. Дополительное преимущество Ansible – скорость выката на площадки, состоящие из многих серверов.

Установка Jekyll на Mac OS X

Я уже писал о том, как установить Jekyll на Ubuntu.Пришло время написать об установке на Mac OS X 10.11.4 (El Capitan).На самом деле все ...… Continue reading

Знакомьтесь, Jekyll

Published on March 22, 2015