Деплой веб-приложений с помощью Ansistrano
ansistrano.deploy и ansistrano.rollback — роли Ansible, предназначенные для управления процессом развертывания приложений, созданных на скриптовых языках программирования (например, PHP, Python и Ruby). По сути это реализация Capistrano в Ansible.
Использование Ansistrano дает следующие преимущества:
- откат за секунды (с ролью ansistrano.rollback);
- настройка процедуры развертывания с использованием методов-обработчиков событий «до» и «после» критически важных шагов;
- оптимизация использования дискового пространства за счет хранения ограниченного количества релизов;
- выбор между SCP, RSYNC, GIT, SVN, HTTP Download или S3 GET-стратегиями развертывания (в дополнение возможно использование unarchive).
Как появился Ansistrano
Вначале был Capistrano, который является инструментом автоматизации управления серверами; его текущая версия — под номером 3. Версия 2.0 была создана для развертывания RoR-приложений. С помощью плагинов можно было работать с не-Rails приложениями, написанными, например, на PHP или Python, применяя различные стратегии развертывания, среды тестирования и многое другое. И это было хорошо.
Capistrano 2 — отличный инструмент, который работает до сих пор. Но он больше не поддерживается, поскольку разработчики переключились на третью версию. При этом, по мнению создателей Ansistrano, Capistrano 3 менее гибкий и не такой мощный, а также не обладает тем набором возможностей, который был у предыдущей версии. Кроме того, другие инструменты развертывания приложений (например, Ansible), не стоят на месте и постоянно совершенствуются.
Разработчики Ansistrano объясняют отказ от Capistrano отсутствием поддержки версии 2 и нехваткой функциональности в v3, а также тем, что все необходимые задачи выполнимы и с помощью Ansible. В качестве альтернативы предлагается посмотреть на Fabric и Chef Solo.
Кстати, название проекта — Ansistrano — получилось путем соединения Ansible и Capistrano.
Анонимная статистика использования Ansistrano
Недавно в Ansistrano был добавлен дополнительный необязательный шаг, который дает разработчикам возможность узнать, сколько людей разворачивают приложения с помощью Ansistrano. Поскольку Ansible Galaxy не предоставляет статистику по загрузкам или использованию, авторы Ansistrano утверждают, что это был чуть ли не единственный способ выяснить количество пользователей проекта.
Код по сбору анонимной статистики см. здесь. Кроме того, этот зонд функционал можно отключить, установив в false настройку ansistrano_allow_anonymous_stats
во всех плейбуках.
Кто использует Ansistrano?
Готов ли Ansistrano к использованию?
- Atrápalo
- Another Place Productions
- Suntransfers
- Ulabox
- Euromillions.com
- Uvinum
- Cycloid
- Spotahome
- Ofertix
- Nice&Crazy
- Gstock
- CMP Group
- Jolicode
- Wavecontrol
- EnAlquiler
- ABA English
- Oferplan
- Yubl
- Fluxus
- TechPump
- Nodo Ámbar
- Cabissimo
- UNICEF Comité Español
- Claranet France
- OpsWay Software Factory
Установка и обновление
Для развертывания приложений с Ansistrano понадобятся:
- Ansible на центральной машине;
rsync
на целевой машине (если используется стратегия развертыванияrsync
,git
илиansistrano_current_via = rsync
).
Ansistrano доступен через Ansible Galaxy. Чтобы запустить установку, выполните:
$ ansible-galaxy install carlosbuenosvinos.ansistrano-deploy carlosbuenosvinos.ansistrano-rollback
Чтобы обновить Ansistrano, добавьте параметр --force:
$ ansible-galaxy install --force carlosbuenosvinos.ansistrano-deploy carlosbuenosvinos.ansistrano-rollback
Основная схема работы
Развертывание приложений с Ansistrano выполняется по той же схеме, что и в Capistrano.
- Настройка (Setup): создается структура каталогов для хранения релизов.
- Обновление кода (Code update): загрузка релиза на целевые машины.
- Обновление ссылок (Symlink): после развертывания нового релиза на целевых машинах ссылка
current
устанавливается на новый релиз. - Очистка (Cleanup): с учетом параметра
ansistrano_keep_releases
удаляются старые версии (см. «Переменные роли»).
Переменные роли
Далее для справки приведен список переменных Ansistrano.
- vars:
ansistrano_deploy_from: "{{ playbook_dir }}" # Расположение проекта (относительный или абсолютный путь).
ansistrano_deploy_to: "/var/www/my-app" # Путь для развертывания.
ansistrano_version_dir: "releases" # Имя каталога с релизами.
ansistrano_current_dir: "current" # Имя ссылки на текущий релиз, меняется редко.
ansistrano_current_via: "symlink" # Стратегия развертывания в каталог "current". Варианты: "symlink" или "rsync".
ansistrano_shared_paths: [] # Общие пути для ссылки на каталог с релизом.
ansistrano_shared_files: [] # Общие файлы для ссылки на каталог с релизом.
ansistrano_keep_releases: 0 # Релизы, которые необходимо сохранить. См. «Удаление старых релизов».
ansistrano_deploy_via: "rsync" # Метод доставки кода на сервер. Варианты: "copy", "rsync", "git", "svn", "s3" или "download". Для "copy", "download" и "s3" есть возможность распаковать (unarchive) загруженный файл (нужно добавить "_unarchive"). Полный список опций можно найти в каталоге *tasks/update-code*.
ansistrano_allow_anonymous_stats: yes
# Переменные, используемые при стратегии развертывания "rsync"
ansistrano_rsync_extra_params: "" # Дополнительные параметры, которые будут использованы при развертывании с помощью rsync одной строкой. Хотя Ansible позволяет использовать массивы, могут быть проблемы при попытке добавления нескольких аргументов "--include". См. соответствующий отчет по ссылке https://github.com/ansistrano/deploy/commit/e98942dc969d4e620313f00f003a7ea2eab67e86
ansistrano_rsync_set_remote_user: yes # См. [ansible synchronize module](http://docs.ansible.com/ansible/synchronize_module.html). Варианты: "yes", "no".
# Переменные, используемые при стратегии развертывания Git
ansistrano_git_repo: git@github.com:USERNAME/REPO.git # Расположение репозитория git.
ansistrano_git_branch: master # Какую версию репозитория использовать. Это может быть целый 40-символьный хеш SHA-1, литерал HEAD, имя ветки или имя тега (tag name).
ansistrano_git_repo_tree: "" # Если указано поддерево (subtree) репозитория для развертывания.
ansistrano_git_identity_key_path: "" # Если указано, то этот файл копируется и используется в качестве идентификационного ключа для команд git, путь указывается относительно плейбука, в котором используется.
# Переменные, используемые при стратегии развертывания SVN
# Обратите внимание: в Ansible 1.8.x была ошибка в модуле subversion (https://github.com/ansible/ansible-modules-core/issues/370), поэтому поддержка этой системы начинается только с Ansible 1.9.
ansistrano_svn_repo: "https://svn.company.com/project" # Расположение репозитория svn
ansistrano_svn_branch: "trunk" # Какую ветку репозитория использовать.
ansistrano_svn_revision: "HEAD" # Какую ревизию репозитория использовать.
ansistrano_svn_username: "user" # SVN authentication username
ansistrano_svn_password: "Pa$$word" # SVN authentication password
# Переменные, используемые при стратегии развертывания download
ansistrano_get_url: https://github.com/someproject/somearchive.tar.gz
# Переменные, используемые при стратегии развертывания S3
ansistrano_s3_bucket: s3bucket
ansistrano_s3_object: s3object.tgz # Добавьте суффикс _unarchive к ansistrano_deploy_via, если ваш объект является пакетом (например, s3_unarchive)
ansistrano_s3_region: eu-west-1
ansistrano_s3_rgw: false # должна быть Ansible >= 2.2, используйте Ceph RGW (когда установлено в "true", игнорируйте ansistrano_s3_region)
ansistrano_s3_url: http://rgw.example.com # при использовании Ceph RGW установите url
# Необязательные переменные, не используются по умолчанию
ansistrano_s3_aws_access_key: YOUR_AWS_ACCESS_KEY
ansistrano_s3_aws_secret_key: YOUR_AWS_SECRET_KEY
# Hooks: (добавьте в задачи необходимые обработчики событий)
ansistrano_before_setup_tasks_file: "{{ playbook_dir }}//my-before-setup-tasks.yml"
ansistrano_after_setup_tasks_file: "{{ playbook_dir }}//my-after-setup-tasks.yml"
ansistrano_before_update_code_tasks_file: "{{ playbook_dir }}//my-before-update-code-tasks.yml"
ansistrano_after_update_code_tasks_file: "{{ playbook_dir }}//my-after-update-code-tasks.yml"
ansistrano_before_symlink_shared_tasks_file: "{{ playbook_dir }}//my-before-symlink-shared-tasks.yml"
ansistrano_after_symlink_shared_tasks_file: "{{ playbook_dir }}//my-after-symlink-shared-tasks.yml"
ansistrano_before_symlink_tasks_file: "{{ playbook_dir }}//my-before-symlink-tasks.yml"
ansistrano_after_symlink_tasks_file: "{{ playbook_dir }}//my-after-symlink-tasks.yml"
ansistrano_before_cleanup_tasks_file: "{{ playbook_dir }}//my-before-cleanup-tasks.yml"
ansistrano_after_cleanup_tasks_file: "{{ playbook_dir }}//my-after-cleanup-tasks.yml"
{{ playbook_dir }}
— переменная Ansible, которая хранит путь к текущему плейбуку.
Развертывание
Чтобы выполнить развертывание с помощью Ansistrano, сделайте несколько шагов.
- Создайте новый файл
hosts
. В случае возникновения вопросов смотрите документацию по Ansible Inventory. В этом файле будут указаны целевые машины. - Создайте новый плейбук для развертывания приложения (например,
deploy.yml
). - Настройте переменные роли.
- Включите роль
carlosbuenosvinos.ansistrano-deploy
в скрипт (play). - Запустите плейбук.
ansible-playbook -i hosts deploy.yml
Если все было настроено правильно, эта команда создаст примерно следующую структуру каталогов на сервере. Проверьте, как будет выглядеть каталог hosts после одного, двух и трех развертываний.
-- /var/www/my-app.com
|-- current -> /var/www/my-app.com/releases/20100509145325
|-- releases
| |-- 20100509145325
|-- shared
-- /var/www/my-app.com
|-- current -> /var/www/my-app.com/releases/20100509150741
|-- releases
| |-- 20100509150741
| |-- 20100509145325
|-- shared
-- /var/www/my-app.com
|-- current -> /var/www/my-app.com/releases/20100512131539
|-- releases
| |-- 20100512131539
| |-- 20100509150741
| |-- 20100509145325
|-- shared
Последовательные развертывания
Чтобы предотвратить установку различных временных меток при развертывании на несколько серверов с использованием опции serial
, установите переменную ansistrano_release_version
.
ansible-playbook -i hosts -e "ansistrano_release_version=`date -u +%Y%m%d%H%M%SZ`" deploy.yml
Откат
Чтобы откатиться с Ansistrano, необходимо настроить развертывание и выполнить плейбук отката.
ansible-playbook -i hosts rollback.yml
При попытке отката с количеством развернутых релизов, равным 1 или 0, система выдаст ошибку; никаких действий при этом выполнено не будет.
В сценарии отката по сравнению с развертыванием гораздо меньше настраиваемых переменных:
- vars:
ansistrano_deploy_to: "/var/www/my-app" # Путь для развертывания.
ansistrano_version_dir: "releases" # Имя каталога с релизами.
ansistrano_current_dir: "current" # Имя ссылки на текущий релиз, меняется редко.
# Hooks: (добавьте в задачи необходимые обработчики событий)
ansistrano_before_symlink_tasks_file: "{{ playbook_dir }}//my-before-symlink-tasks.yml"
ansistrano_after_symlink_tasks_file: "{{ playbook_dir }}//my-after-symlink-tasks.yml"
ansistrano_before_cleanup_tasks_file: "{{ playbook_dir }}//my-before-cleanup-tasks.yml"
ansistrano_after_cleanup_tasks_file: "{{ playbook_dir }}//my-after-cleanup-tasks.yml"
Многостадийные среды (multistage environments) (devel, preprod, prod и т. д.)
При развертывании в разные среды (например, devel, preprod и prod) рекомендуется создавать для них разные файлы hosts. Один и тот же плейбук можно запускать для разных hosts-файлов с помощью параметра -i. В каждом из этих файлов допускается указание различающихся данных (имена пользователей, пароли, параметры соединений и т. д.).
ansible-playbook -i hosts_devel deploy.yml
ansible-playbook -i hosts_preprod deploy.yml
ansible-playbook -i hosts_prod deploy.yml
Hooks: пользовательские задачи (custom tasks)
После шага Symlink
обычно необходимо перезагрузить сервер, или перед Code update
загрузить зависимости, или даже сделать это в production перед Symlink
. Итак, для выполнения пользовательских задач необходимы обработчики (hooks), которые Ansistrano выполнит до или после каждого из 3 основных шагов.
-- /my-local-machine/my-app.com
|-- hosts
|-- deploy.yml
|-- my-custom-tasks
| |-- before-code-update.yml
| |-- after-code-update.yml
| |-- before-symlink.yml
| |-- after-symlink.yml
| |-- before-cleanup.yml
| |-- after-cleanup.yml
Например, чтобы перезапустить Apache после шага Symlink
, добавим в after-symlink.yml
следующие строки:
- name: Restart Apache
service: name=httpd state=reloaded
Как добавить отправку уведомления о завершении развертывания по почте или очистить кеш? Очень просто! С помощью переменных роли ansistrano_before_*_tasks_file
и ansistrano_after_*_tasks_file
можно указать файл с пользовательскими задачами для точек «до» и «после» каждого шага.
Переменные в пользовательских задачах
При написании файлов пользовательских задач могут потребоваться некоторые переменные, доступные в Ansistrano:
{{ ansistrano_release_path.stdout }}
: путь к текущему релизу для развертывания (это, возможно, самая нужная переменная);{{ ansistrano_releases_path.stdout }}
: путь к каталогу с релизами;{{ ansistrano_shared_path.stdout }}
: путь к общей папке (где могут храниться общие для всех релизов файлы);{{ ansistrano_release_version }}
: относительное имя каталога с релизом (по умолчанию равно текущей временной метке (timestamp) в зоне UTC).
Удаление старых релизов
В средах, где применяется Continuous delivery, в промышленную эксплуатацию, как правило, сдается много релизов. Те счастливчики, у которых на дисках избыток свободного места, возможно, не увидят в этом проблемы, но общепринятой практикой является хранение лишь ограниченного количества релизов.
Чтобы удалить старые релизы после развертывания, запишите в переменную ansistrano_keep_releases
количество, которое необходимо сохранить.
Давайте посмотрим, как будет вести себя Ansistrano при развертывании трех релизов и ansistrano_keep_releases: 2
:
-- /var/www/my-app.com
|-- current -> /var/www/my-app.com/releases/20100509145325
|-- releases
| |-- 20100509145325
|-- shared
-- /var/www/my-app.com
|-- current -> /var/www/my-app.com/releases/20100509150741
|-- releases
| |-- 20100509150741
| |-- 20100509145325
|-- shared
-- /var/www/my-app.com
|-- current -> /var/www/my-app.com/releases/20100512131539
|-- releases
| |-- 20100512131539
| |-- 20100509150741
|-- shared
Заметьте, что релиз 20100509145325
был удален.
Пример плейбука
В каталоге example
репозитория Ansistrano можно найти демонстрационный проект, который приводит пример развертывания небольшого приложения.
Чтобы его запустить, понадобятся Vagrant и роли Ansistrano. Для получения информации по работе с Vagrant см. https://www.vagrantup.com.
$ cd example/my-playbook
$ vagrant up
$ ansible-playbook -i hosts deploy.yml
После выполнения этих команд файл index.html, расположенный в каталоге my-app
, будет развернут на обе машины, созданные с помощью Vagrant.
Для тестирования отката нужно запустить deploy.yml как минимум дважды (чтобы было к чему откатываться). После этого выполните:
$ ansible-playbook -i hosts rollback.yml
В папке test есть более сложные примеры, которые используют Travis-CI.