Spec-Zone.ru › Ansible 2.9

Введение в Playbooks

  • О Playbooks
  • Пример языка Playbook
  • Основы
    • Хосты и Пользователи
    • Список задач
  • Сокращенная запись действий
  • Обработчики: Выполнение операций при изменении
  • Выполнение Playbook
  • Ansible-Pull
  • Проверка playbooks
  • Другие варианты проверки playbooks

О Playbooks

Playbooks — это совершенно другой способ использования Ansible, чем при выполнении задач в режиме ad-hoc, и они особенно мощные.

Проще говоря, playbooks — это основа очень простой системы управления конфигурациями и развертывания на нескольких машинах, не похожей ни на одну из уже существующих, и очень хорошо подходящей для развертывания сложных приложений.

Playbooks могут объявлять конфигурации, но также могут организовывать шаги любого ручного упорядоченного процесса, даже если различные шаги должны перескакивать между наборами машин в определенном порядке. Они могут запускать задачи синхронно или асинхронно.

В то время как вы можете запустить основную /usr/bin/ansible программу для задач ad-hoc, playbooks, скорее всего, будут храниться в системе контроля версий и использоваться для выгрузки вашей конфигурации или обеспечения того, что конфигурации ваших удаленных систем соответствуют спецификациям.

Также существуют полные наборы playbooks, иллюстрирующие многие из этих техник в репозитории ansible-examples. Мы рекомендуем ознакомиться с ними в другом окне во время работы.

После освоения playbooks у вас также есть много вариантов дальнейшего развития, поэтому вернитесь к индексу документации после завершения этого раздела.

Пример языка Playbook

Playbooks выражены в формате YAML (см. Синтаксис YAML) и имеют минимальный синтаксис, который намеренно не является языком программирования или скриптом, а скорее моделью конфигурации или процесса.

Примечание

Некоторые редакторы имеют плагины, которые могут помочь вам писать чистый синтаксис YAML в ваших playbooks. Подробности см. в Другие инструменты и программы.

Каждый playbook состоит из одного или нескольких «plays» в списке.

Цель play — сопоставить группу хостов с некоторыми хорошо определенными ролями, представленными тем, что Ansible называет задачами. На базовом уровне задача — это не более чем вызов модуля Ansible.

Компонуя playbook из нескольких «plays», можно организовывать развертывание на нескольких машинах, выполняя определенные шаги на всех машинах в группе webservers, затем определенные шаги на сервере базы данных, затем дополнительные команды обратно на серверы webservers и т. д.

«Plays» — это, так сказать, аналогия из спорта. У вас может быть довольно много plays, которые влияют на ваши системы для выполнения различных задач. Это не означает, что вы просто определяете одно конкретное состояние или модель, и вы можете запускать разные plays в разное время.

Для начала вот playbook, verify-apache.yml который содержит только один 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
    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

Возможность выполнения действий от имени другого пользователя также доступна (см. Понимание повышения привилегий: 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

Вы также можете войти как ваш пользователь, а затем стать другим пользователем, отличным от 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 или -K. Если вы запускаете playbook, использующий become, и playbook зависает, скорее всего, он застрял на приглашении повышения привилегий и его можно остановить, используя Control-C, что позволит вам повторно выполнить playbook, добавив соответствующий пароль.

Важно

При использовании 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».

Задачи могут быть объявлены с помощью устаревшего формата 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

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

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 предпочитает перечисление модулей следующим образом:

template:
    src: templates/foo.j2
    dest: /etc/foo.conf

Ранние версии Ansible использовали следующий формат, который всё ещё работает:

action: template src=templates/foo.j2 dest=/etc/foo.conf

Обработчики: Выполнение операций при изменении

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

Эти действия «уведомления» срабатывают в конце каждого блока задач в playbook и будут срабатывать только один раз, даже если о них сообщают несколько задач.

Например, несколько ресурсов могут указывать на необходимость перезапуска apache, потому что они изменили конфигурационный файл, но apache будет перезапущен только один раз, чтобы избежать ненужных перезапусков.

Вот пример перезапуска двух служб при изменении содержимого файла, но только если файл изменился:

- name: template configuration file
  template:
    src: template.j2
    dest: /etc/foo.conf
  notify:
     - restart memcached
     - restart apache

Элементы, указанные в разделе notify задачи, называются обработчиками.

Обработчики — это списки задач, ничем не отличающиеся от обычных задач, на которые ссылаются по глобально уникальному имени и которые уведомляются уведомлениями. Если обработчик не уведомляется ничем, он не будет выполняться. Независимо от того, сколько задач уведомляют обработчик, он будет выполняться только один раз после завершения всех задач в конкретном playbook.

Вот пример раздела обработчиков:

handlers:
    - name: restart memcached
      service:
        name: memcached
        state: restarted
    - name: restart apache
      service:
        name: apache
        state: restarted

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

handlers:
# this handler name may cause your play to fail!
- name: restart "{{ web_service_name }}"

Если переменная, используемая в имени обработчика, недоступна, весь playbook завершается ошибкой. Изменение этой переменной в процессе выполнения playbook не приведёт к созданию нового обработчика.

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

tasks:
  - name: Set host variables based on distribution
    include_vars: "{{ ansible_facts.distribution }}.yml"

handlers:
  - name: restart web service
    service:
      name: "{{ web_service_name | default('httpd') }}"
      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"

Это использование значительно упрощает триггер нескольких обработчиков. Это также отвязывает обработчики от их имён, что упрощает совместное использование обработчиков между playbooks и ролями (особенно при использовании ролей сторонних разработчиков из общего источника, например, Galaxy).

Примечание

  • Обработчики уведомлений всегда выполняются в том же порядке, в котором они определены, not в порядке, указанном в инструкции уведомления. Это также относится к обработчикам, использующим listen.
  • Имена обработчиков и listen темы существуют в глобальном пространстве имён.
  • Имена обработчиков могут быть шаблонизированы, а listen темы — нет.
  • Используйте уникальные имена обработчиков. Если вы активируете более одного обработчика с одинаковым именем, первые будут перезаписаны. Будет выполнен только последний из определённых.
  • Вы не можете уведомлять обработчик, который определён внутри include. Однако, начиная с Ansible 2.1, это работает, если include должен быть static.

Роли описываются позже, но стоит отметить, что:

  • обработчики, уведомлённые внутри pre_tasks, tasks, и post_tasks разделов, автоматически очищаются в конце раздела, где они были уведомлены,
  • обработчики, уведомлённые внутри roles раздела, автоматически очищаются в конце tasks раздела, но до выполнения любых tasks обработчиков,
  • обработчики действуют на уровне playbook и, таким образом, могут использоваться вне роли, в которой они определены.

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

tasks:
   - shell: some tasks go here
   - meta: flush_handlers
   - shell: some other tasks

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

Выполнение playbook

Теперь, когда вы изучили синтаксис playbook, как запустить playbook? Это просто. Давайте запустим playbook с уровнем параллелизма 10:

ansible-playbook playbook.yml -f 10

Ansible-Pull

Если вам нужно изменить архитектуру Ansible, чтобы узлы подключались к централизованному месту вместо того, чтобы получать конфигурацию, вы можете это сделать.

ansible-pull — это небольшой скрипт, который будет извлекать репозиторий конфигурационных инструкций из git и затем выполнять ansible-playbook над этим содержимым.

Предполагая, что вы распределяете нагрузку на свой узел для извлечения, ansible-pull будет масштабироваться практически неограниченно.

Запустите ansible-pull --help для получения подробностей.

Также доступен умный playbook для настройки ansible-pull через crontab из режима push.

Проверка playbooks

Вы можете использовать ansible-lint для проверки playbooks перед их выполнением.

Например, если вы запустите ansible-lint для playbook verify-apache.yml, введённого ранее в этом разделе, вы получите следующие результаты:

$ ansible-lint verify-apache.yml
[403] Package installs should not use latest
verify-apache.yml:8
Task/Handler: ensure apache is at the latest version

На странице ansible-lint default rules описаны все ошибки. Для [403], рекомендуемое исправление заключается в изменении state: latest на state: present в playbook.

Другие варианты проверки playbook

См. Инструменты для проверки playbooks для получения подробного списка инструментов, которые вы можете использовать для проверки playbooks. Вот ещё несколько, которые следует рассмотреть:

  • Для проверки синтаксиса playbook используйте ansible-playbook с флагом --syntax-check. Это выполнит playbook-файл через анализатор, чтобы убедиться, что в нём и в его включённых файлах, ролях и т. д. нет синтаксических ошибок.
  • Обратите внимание на вывод в нижней части выполнения playbook для получения сводки о целевых узлах и их работе. Общие ошибки и фатальные попытки связи «недоступно» сохраняются отдельно в подсчётах.
  • Если вам нужно получить подробный вывод успешных модулей, а также неуспешных, используйте флаг --verbose. Он доступен в Ansible 0.5 и более поздних версиях.
  • Чтобы увидеть, на какие узлы повлияет playbook перед его запуском, вы можете сделать это:

    ansible-playbook playbook.yml --list-hosts
    

См. также

ansible-lint
Узнайте, как проверить синтаксис Ansible Playbooks
YAML Syntax
Узнайте о синтаксисе YAML
Рекомендации по практике
Различные советы по управлению playbooks в реальном мире
Все модули
Узнайте о доступных модулях
Разрабатывать ли модуль?
Узнайте, как расширить Ansible, написав собственные модули
Шаблоны: выбор узлов и групп
Узнайте, как выбирать узлы
Директория примеров GitHub
Полные примеры playbooks «от начала до конца»
Список рассылки
Вопросы? Помощь? Идеи? Заходите на список рассылки на 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.9/user_guide/playbooks_intro.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API