Вводные сведения о Playbooks
О Playbooks
Playbooks — это совершенно другой способ использования Ansible, отличный от выполнения задач в режиме adhoc, и они особенно мощные.
Проще говоря, playbooks — это основа действительно простой системы управления конфигурацией и развертывания на нескольких машинах, не похожей ни на одну из уже существующих, и очень подходящей для развертывания сложных приложений.
Playbooks могут объявлять конфигурации, но они также могут организовывать шаги любого ручного упорядоченного процесса, даже если разные шаги должны передавать данные между группами машин в определённом порядке. Они могут запускать задачи синхронно или асинхронно.
Хотя вы можете запустить основную /usr/bin/ansible программу для задач ad-hoc, playbooks скорее всего будут храниться в системе контроля версий и использоваться для распространения вашей конфигурации или обеспечения соответствия конфигураций ваших удалённых систем.
Также есть полные наборы playbooks, иллюстрирующие многие из этих техник в репозитории ansible-examples. Мы рекомендуем ознакомиться с ними в другом окне во время работы.
После изучения playbooks также есть множество путей для развития, поэтому после завершения этого раздела вернитесь к индексу документации.
Пример языка Playbooks
Playbooks написаны в формате YAML (см. YAML Синтаксис) и имеют минимальный синтаксис, который намеренно пытается не быть языком программирования или скриптом, а скорее моделью конфигурации или процесса.
Каждый playbook состоит из одного или нескольких «plays» в списке.
Цель play состоит в том, чтобы сопоставить группу хостов с некоторыми хорошо определёнными ролями, представленными элементами, которые Ansible называет задачами. На базовом уровне задача — это не более чем вызов модуля Ansible (см. О модулях).
Компонуя playbook из нескольких «plays», можно организовать развертывание на нескольких машинах, выполнив определённые шаги на всех машинах в группе веб-серверов, затем определённые шаги на сервере базы данных, затем дополнительные команды на группе веб-серверов и так далее.
«Plays» — это аналогия из спорта. Вы можете иметь довольно много plays, которые влияют на ваши системы для выполнения различных задач. Это не означает, что вы просто определяете одно конкретное состояние или модель, и вы можете запускать разные plays в разное время.
Для начала вот playbook, содержащий только один play:
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running (and enable it at boot)
service: name=httpd state=started enabled=yes
handlers:
- name: restart apache
service: name=httpd state=restarted
При работе с задачами, имеющими очень длинные параметры или модулями, принимающими много параметров, вы можете разбить элементы задач на несколько строк, чтобы улучшить структуру. Ниже приведён другой вариант предыдущего примера, использующий словари YAML для передачи модулям их key=value аргументов.
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum:
name: httpd
state: latest
- name: write the apache config file
template:
src: /srv/httpd.j2
dest: /etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running
service:
name: httpd
state: started
handlers:
- name: restart apache
service:
name: httpd
state: restarted
Playbooks могут содержать несколько plays. Вы можете иметь playbook, который сначала нацелен на веб-серверы, а затем на серверы базы данных. Например:
---
- hosts: webservers
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
- hosts: databases
remote_user: root
tasks:
- name: ensure postgresql is at the latest version
yum: name=postgresql state=latest
- name: ensure that postgresql is started
service: name=postgresql state=started
Этот метод можно использовать для переключения между группой хостов, на которые вы нацеливаетесь, именем пользователя, который входит в удалённые серверы, использовать ли sudo или нет и т. д. Plays, как и задачи, выполняются в указанном порядке в playbook: сверху вниз.
Ниже мы рассмотрим различные возможности языка playbooks.
Основы
Хосты и пользователи
Для каждого play в playbook вы можете выбрать, какие машины в вашей инфраструктуре целесообразно нацелить, и под каким удалённым пользователем выполнить шаги (называемые задачами).
Строка hosts — это список одной или нескольких групп или шаблонов хостов, разделённых двоеточиями, как описано в документации по Шаблонам. remote_user — просто имя учётной записи пользователя:
--- - hosts: webservers remote_user: root
Примечание
Параметр remote_user ранее назывался просто user. Он был переименован в Ansible 1.4, чтобы сделать его более различимым от модуля user (используемого для создания пользователей на удалённых системах).
Удалённые пользователи также могут быть определены по каждой задаче:
---
- hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yourname
Примечание
Параметр remote_user для задач был добавлен в 1.4.
Поддержка выполнения действий от имени другого пользователя также доступна (см. Become (Эскалация привилегий)):
--- - hosts: webservers remote_user: yourname become: yes
Вы также можете использовать become для конкретной задачи вместо всего play:
---
- hosts: webservers
remote_user: yourname
tasks:
- service: name=nginx state=started
become: yes
become_method: sudo
Примечание
Синтаксис become устаревает старый синтаксис, специфичный для sudo/su, начиная с версии 1.9.
Вы также можете войти как свой пользователь, а затем стать пользователем, отличным от root:
--- - hosts: webservers remote_user: yourname become: yes become_user: postgres
Вы также можете использовать другие методы эскалации привилегий, например, su:
--- - hosts: webservers remote_user: yourname become: yes become_method: su
Если вам нужно указать пароль для sudo, запустите ansible-playbook с --ask-become-pass или при использовании старого синтаксиса sudo --ask-sudo-pass (-K). Если запущенный playbook с эскалацией привилегий зависает, он, вероятно, застрял на запросе эскалации привилегий. Просто Control-C для его убийства и запустите его снова, добавив соответствующий пароль.
Важно
При использовании become_user для пользователя, отличного от root, аргументы модуля временно записываются в случайный временный файл в /tmp. Они удаляются сразу после выполнения команды. Это происходит только при изменении привилегий от пользователя, такого как «bob», к пользователю «timmy», а не при переходе от «bob» к «root», или при непосредственном входе как «bob» или «root». Если вас беспокоит, что эти данные кратковременно читаемы (не записываемы), избегайте передачи нешифрованных паролей с become_user установленным. В других случаях /tmp не используется, и это не играет роли. Ansible также заботится о том, чтобы не регистрировать параметры пароля.
Добавлено в версии 2.4.
Вы также можете управлять порядком выполнения хостов. По умолчанию порядок соответствует порядку, предоставленному инвентарём:
- hosts: all
order: sorted
gather_facts: False
tasks:
- debug: var=inventory_hostname
Возможные значения для order:
- inventory:
- По умолчанию. Порядок — «как предоставлено» инвентарём
- reverse_inventory:
- Как следует из названия, этот порядок меняет порядок «как предоставлено» инвентарём
- sorted:
- Хосты сортируются по имени в алфавитном порядке
- reverse_sorted:
- Хосты сортируются по имени в обратном алфавитном порядке
- shuffle:
- Хосты упорядочиваются случайным образом при каждом запуске
Список задач
Каждый play содержит список задач. Задачи выполняются в порядке, по одной за раз, на всех машинах, соответствующих шаблону хоста, прежде чем перейти к следующей задаче. Важно понимать, что в пределах одного play все хосты получат одинаковые директивы задач. Цель play — сопоставить выборку хостов с задачами.
При запуске playbook, выполняющегося сверху вниз, хосты с невыполненными задачами исключаются из цикла для всего playbook. Если что-то не удаётся, просто исправьте файл playbook и запустите его снова.
Цель каждой задачи — выполнить модуль со специфическими аргументами. Переменные, как упоминалось выше, могут использоваться в аргументах модулей.
Модули должны быть идемпотентными, то есть многократное выполнение модуля в последовательности должно иметь тот же эффект, что и его выполнение один раз. Один из способов достижения идемпотентности — заставить модуль проверить, достигнуто ли желаемое конечное состояние, и если это состояние достигнуто, выйти, не выполняя никаких действий. Если все модули, используемые playbook, идемпотентны, то и сам playbook, вероятно, будет идемпотентным, поэтому повторный запуск playbook должен быть безопасным.
Модули command и shell, как правило, повторно запускают одну и ту же команду, что вполне нормально, если команда, например, chmod или setsebool, и т. д. Хотя есть флаг creates, который можно использовать, чтобы сделать эти модули также идемпотентными.
Каждая задача должна иметь name, которая включена в вывод при выполнении playbook. Это удобочитаемый вывод, поэтому полезно предоставлять хорошие описания каждого шага задачи. Если имя не указано, будет использоваться строка, переданная в «действие».
Задачи могут быть объявлены с использованием устаревшего action: module options формата, но рекомендуется использовать более стандартный module: options формат. Этот рекомендуемый формат используется на протяжении всей документации, но вы можете встретить старый формат в некоторых playbooks.
Вот как выглядит базовая задача. Как и большинство модулей, модуль service принимает key=value аргументы:
tasks:
- name: make sure apache is running
service: name=httpd state=started
Модули command и shell — единственные модули, которые просто принимают список аргументов и не используют формат key=value. Это позволяет им работать так же просто, как вы ожидаете:
tasks:
- name: enable selinux
command: /sbin/setenforce 1
Модули command и shell обращают внимание на коды возврата, поэтому, если у вас есть команда, для которой успешный код выхода не равен нулю, вы можете сделать так:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
Или так:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
Если строка действия становится слишком длинной, вы можете разбить её на пробел и отступать любые строки продолжения:
tasks:
- name: Copy ansible inventory file to client
copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts
owner=root group=root mode=0644
Переменные могут использоваться в строках действий. Предположим, вы определили переменную под названием vhost в разделе vars, вы можете сделать так:
tasks:
- name: create a virtual host file for {{ vhost }}
template: src=somefile.j2 dest=/etc/httpd/conf.d/{{ vhost }}
Эти же переменные могут быть использованы в шаблонах, о которых мы поговорим позже.
Теперь в очень простом playbook все задачи будут перечислены непосредственно в play, хотя обычно более целесообразно разбивать задачи, как описано в Создание многоразовых playbooks.
Сокращённый синтаксис действий
Добавлено в версии 0.8.
Ansible предпочитает перечисление модулей так в 0.8 и более поздних версиях:
template: src=templates/foo.j2 dest=/etc/foo.conf
Вы заметите, что в более ранних версиях это было доступно только как:
action: template src=templates/foo.j2 dest=/etc/foo.conf
Старый формат по-прежнему работает в более новых версиях без планов устаревания.
Обработчики: Выполнение операций при изменении
Как мы уже упоминали, модули должны быть идемпотентными и могут сигнализировать о внесённых изменениях на удалённой системе. Playbooks распознают это и имеют базовые механизмы событий, которые могут быть использованы для реагирования на изменения.
Эти действия «notify» запускаются в конце каждого блока задач в play и будут запущены только один раз, даже если уведомление получено от нескольких различных задач.
Например, несколько ресурсов могут указывать на необходимость перезапуска apache, потому что они изменили файл конфигурации, но apache будет перезапущен только один раз, чтобы избежать ненужных перезапусков.
Вот пример перезапуска двух сервисов при изменении содержимого файла, но только если файл изменился:
- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify:
- restart memcached
- restart apache
Элементы, перечисленные в разделе notify задачи, называются обработчиками.
Обработчики — это списки задач, не сильно отличающиеся от обычных задач, на которые ссылаются по уникальному глобальному имени и на которые реагируют уведомители. Если обработчик не получает уведомлений, он не будет запущен. Независимо от того, сколько задач отправляют уведомления обработчику, он будет запущен только один раз после завершения всех задач в конкретном выполнении.
Вот пример раздела обработчиков:
handlers:
- name: restart memcached
service: name=memcached state=restarted
- name: restart apache
service: name=apache state=restarted
Начиная с Ansible 2.2, обработчики также могут «прослушивать» общие темы, и задачи могут отправлять уведомления об этих темах следующим образом:
handlers:
- name: restart memcached
service: name=memcached state=restarted
listen: "restart web services"
- name: restart apache
service: name=apache state=restarted
listen: "restart web services"
tasks:
- name: restart everything
command: echo "this task will restart the web services"
notify: "restart web services"
Это значительно упрощает триггер нескольких обработчиков. Это также отвязывает обработчики от их имён, что упрощает совместное использование обработчиков между книгами задач и ролями (особенно при использовании ролей сторонних разработчиков из общего источника, например, Galaxy).
Примечание
- Обработчики уведомлений всегда выполняются в том же порядке, в котором они определены,
notв порядке, указанном в инструкции notify. Это также относится к обработчикам, использующимlisten. - Имена обработчиков и
listenтемы существуют в глобальном пространстве имён. - Если две задачи обработчика имеют одинаковое имя, будет выполнена только одна из них. *
- Вы не можете отправлять уведомления обработчику, определённому внутри include. Начиная с Ansible 2.1, это работает, но include должен быть
static.
Роли описываются позже, но стоит отметить, что:
- обработчики, уведомлённые в разделах
pre_tasks,tasks, иpost_tasks, автоматически очищаются в конце раздела, где они были уведомлены; - обработчики, уведомлённые в разделе
roles, автоматически очищаются в концеtasksраздела, но до любыхtasksобработчиков.
Если вы хотите немедленно очистить все команды обработчика, начиная с версии 1.2 и выше, вы можете:
tasks: - shell: some tasks go here - meta: flush_handlers - shell: some other tasks
В приведённом примере все обработчики, находящиеся в очереди, будут обработаны заранее, когда будет достигнута инструкция meta. Это довольно специфический случай, но иногда может быть полезен.
Выполнение книги задач
Теперь, когда вы ознакомились с синтаксисом книги задач, как запустить книгу задач? Это просто. Давайте запустим книгу задач с уровнем параллелизма 10:
ansible-playbook playbook.yml -f 10
Ansible-Pull
Если вам нужно изменить архитектуру Ansible так, чтобы узлы регистрировались в центральном месте, а не получать конфигурацию от него, вы можете это сделать.
ansible-pull — это небольшой скрипт, который скачает репозиторий инструкций конфигурации из git и затем запустит ansible-playbook против этого содержимого.
Предполагая, что вы настроите балансировку нагрузки для места скачивания, ansible-pull будет масштабироваться практически бесконечно.
Запустите ansible-pull --help для получения подробностей.
Также есть умная книга задач, которая позволяет настроить ansible-pull через crontab из режима push.
Советы и рекомендации
Чтобы проверить синтаксис книги задач, используйте ansible-playbook с флагом --syntax-check. Это выполнит книгу задач через парсер, чтобы убедиться, что включённые файлы, роли и т. д. не содержат синтаксических ошибок.
Внизу вывода выполнения книги задач вы увидите сводку узлов, которые были обработаны, и как они выполнялись. Общие ошибки и фатальные попытки связи «недостижимы» подсчитываются отдельно.
Если вам когда-нибудь понадобится увидеть подробный вывод успешных модулей, а также неуспешных, используйте флаг --verbose. Он доступен в Ansible 0.5 и более поздних версиях.
Вывод книги задач Ansible существенно улучшается, если установлен пакет cowsay. Попробуйте!
Чтобы увидеть, какие хосты будут затронуты книгой задач перед её запуском, вы можете сделать следующее:
ansible-playbook playbook.yml --list-hosts
См. также
- Синтаксис YAML
- Узнайте о синтаксисе YAML
- Рекомендации по лучшим практикам
- Различные советы по управлению книгами задач в реальном мире
- Документация Ansible
- Возвращение к индексу документации для многих специальных тем о книгах задач
- О модулях
- Узнайте о доступных модулях
- Разработка модулей
- Узнайте, как расширить Ansible, написав собственные модули
- Шаблоны
- Узнайте, как выбрать хосты
- Директория примеров GitHub
- Полные примеры книг задач "от начала до конца"
- Список рассылки
- Вопросы? Помощь? Идеи? Загляните на список рассылки на Google Groups
© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.4/playbooks_intro.html