Делегирование, поэтапные обновления и локальные действия
- Размер пакета поэтапного обновления
- Максимальный процент сбоев
- Делегирование
- Делегированные факты
- Выполнение один раз
- Локальные плейбуки
- Прерывание выполнения при любой ошибке
Разработанный с самого начала для многоуровневых развертываний, Ansible отлично справляется с выполнением задач на одном хосте от имени другого или с выполнением локальных шагов со ссылкой на удаленные хосты.
Это особенно актуально при настройке инфраструктуры непрерывной интеграции или поэтапных обновлений без простоев, когда вы взаимодействуете с балансировщиками нагрузки или системами мониторинга.
Дополнительные возможности позволяют настраивать порядок завершения задач и назначать размер пакета для обработки сразу нескольких машин во время поэтапного обновления.
В этом разделе рассматриваются все эти возможности. Примеры использования этих элементов можно найти в репозитории ansible-examples. Там есть множество примеров процедур поэтапных обновлений без простоев для различных типов приложений.
Также следует обратиться к разделу О модулях, различные модули, такие как ‘ec2_elb’, ‘nagios’, ‘bigip_pool’ и ‘netscaler’, гармонично сочетаются с понятиями, упомянутыми здесь.
Также вам необходимо ознакомиться с Ролями, так как понятия ‘pre_task’ и ‘post_task’ — это места, где вы обычно вызываете эти модули.
Обратите внимание, что некоторые задачи невозможно делегировать, например, include, add_host, debug, и т. д., так как они всегда выполняются на контроллере.
Размер пакета поэтапного обновления
Новая версия 0.7.
По умолчанию Ansible пытается управлять всеми машинами, указанными в плейбуке, параллельно. Для случая поэтапного обновления вы можете определить, сколько хостов Ansible должен обрабатывать за один раз, используя ключевое слово ‘’serial’’:
- name: test play hosts: webservers serial: 3
В приведенном выше примере, если у нас было 100 хостов, 3 хоста в группе ‘webservers’ полностью завершат плейбуки перед переходом к следующим 3 хостам.
Ключевое слово ‘’serial’’ также может быть указано в виде процента в Ansible 1.8 и более поздних версиях, которое будет применено к общему числу хостов в плейбуке, чтобы определить количество хостов за один проход:
- name: test play hosts: webservers serial: "30%"
Если количество хостов не делится равномерно на количество проходов, последний проход будет содержать остаток.
Начиная с Ansible 2.2, размеры пакетов могут быть указаны в виде списка, как показано ниже:
- name: test play hosts: webservers serial: - 1 - 5 - 10
В приведенном выше примере первый пакет будет содержать один хост, следующий — 5 хостов, а (если остались хосты) каждый последующий пакет будет содержать 10 хостов, пока не будут использованы все доступные хосты.
Также можно перечислить несколько размеров пакетов в процентах:
- name: test play hosts: webservers serial: - "10%" - "20%" - "100%"
Вы также можете смешивать значения:
- name: test play hosts: webservers serial: - 1 - 5 - "20%"
Примечание
Независимо от того, насколько мал процент, количество хостов за один проход всегда будет равно 1 или больше.
Максимальный процент сбоев
Новая версия 1.3.
По умолчанию Ansible будет продолжать выполнять действия, пока в группе есть хосты, которые еще не завершились с ошибкой. В некоторых ситуациях, таких как поэтапные обновления, описанные выше, может потребоваться прервать выполнение плейбука, когда определенный порог ошибок будет достигнут. Для этого, начиная с версии 1.3, вы можете установить максимальный процент сбоев в плейбуке следующим образом:
- hosts: webservers max_fail_percentage: 30 serial: 10
В приведенном выше примере, если более 3 из 10 серверов в группе выйдут из строя, остальная часть плейбука будет прервана.
Примечание
Установленный процент должен быть превышен, а не равен. Например, если serial был установлен в 4, и вы хотели, чтобы задача прервалась, когда 2 системы вышли из строя, процент должен быть установлен в 49, а не 50.
Делегирование
Новая версия 0.7.
На самом деле, это не специфично для поэтапных обновлений, но часто используется в таких случаях.
Если вам нужно выполнить задачу на одном хосте, ссылаясь на другие хосты, используйте ключевое слово ‘delegate_to’ в задаче. Это идеально подходит для размещения узлов в пуле балансировщиков нагрузки или для их удаления. Это также очень полезно для управления временными окнами простоев. Имейте в виду, что не имеет смысла делегировать все задачи, debug, add_host, include и т. д. всегда выполняются на контроллере. Также рекомендуется использовать это с ключевым словом ‘serial’ для управления количеством хостов, выполняющих задачи одновременно:
---
- hosts: webservers
serial: 5
tasks:
- name: take out of load balancer pool
command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
delegate_to: 127.0.0.1
- name: actual steps would go here
yum: name=acme-web-stack state=latest
- name: add back to load balancer pool
command: /usr/bin/add_back_to_pool {{ inventory_hostname }}
delegate_to: 127.0.0.1
Эти команды будут выполняться на 127.0.0.1, что является машиной, на которой работает Ansible. Также есть сокращенная синтаксическая конструкция, которую вы можете использовать для каждой задачи: ‘local_action’. Ниже приведен тот же плейбук, что и выше, но с использованием сокращенной синтаксической конструкции для делегирования на 127.0.0.1:
---
# ...
tasks:
- name: take out of load balancer pool
local_action: command /usr/bin/take_out_of_pool {{ inventory_hostname }}
# ...
- name: add back to load balancer pool
local_action: command /usr/bin/add_back_to_pool {{ inventory_hostname }}
Распространенный паттерн — использовать локальное действие для вызова ‘rsync’ для рекурсивной копии файлов на управляемые серверы. Вот пример:
---
# ...
tasks:
- name: recursively copy files from management server to target
local_action: command rsync -a /path/to/files {{ inventory_hostname }}:/path/to/target/
Обратите внимание, что для этого необходимо иметь ключи SSH без паролей или настроенный ssh-agent, в противном случае rsync будет запрашивать пароль.
В случае необходимости указания дополнительных аргументов можно использовать следующий синтаксис:
---
# ...
tasks:
- name: Send summary mail
local_action:
module: mail
subject: "Summary Mail"
to: "{{ mail_recipient }}"
body: "{{ mail_body }}"
run_once: True
Переменная ansible_host (ansible_ssh_host в 1.x или специфичная для плагинов ssh/paramiko) отражает хост, на который делегирована задача.
Делегированные факты
Новая версия 2.0.
По умолчанию любые собранные фактами делегированной задачи присваиваются inventory_hostname (текущий хост), а не хосту, который фактически их произвел (хосту, на который делегирована задача). В версии 2.0 директива delegate_facts может быть установлена в True, чтобы назначать собранные фактами задачи хосту, на который делегирована задача, а не текущему:
- hosts: app_servers
tasks:
- name: gather facts from db servers
setup:
delegate_to: "{{item}}"
delegate_facts: True
with_items: "{{groups['dbservers']}}"
В приведенном выше примере будут собраны факты для машин в группе dbservers и факты будут присвоены этим машинам, а не app_servers. Таким образом, вы можете обратиться к hostvars[‘dbhost1’][‘default_ipv4’][‘address’], даже если dbservers не входили в плейбук или были исключены с помощью –limit.
Выполнение один раз
Новая версия 1.7.
В некоторых случаях может потребоваться выполнить задачу только один раз и только на одном хосте. Это можно сделать, настроив “run_once” в задаче:
---
# ...
tasks:
# ...
- command: /opt/application/upgrade_db.py
run_once: true
# ...
Это можно дополнительно использовать с “delegate_to”, чтобы указать отдельный хост для выполнения:
- command: /opt/application/upgrade_db.py run_once: true delegate_to: web01.example.org
Если “run_once” не используется с “delegate_to”, он будет выполняться на первом хосте, определенном в инвентаре, в группе(ах) хостов, на которые нацелен плейбук - например, webservers[0], если плейбук нацелен на “hosts: webservers”.
Этот подход аналогичен применению условия к задаче, например:
- command: /opt/application/upgrade_db.py when: inventory_hostname == webservers[0]
Примечание
При совместном использовании с “serial”, задачи, помеченные как “run_once”, будут выполняться на одном хосте в каждом пакете выполнения. Если крайне важно, чтобы задача выполнялась только один раз независимо от режима “serial”, используйте конструкцию when: inventory_hostname == ansible_play_hosts[0].
Локальные плейбуки
Иногда полезно использовать плейбук локально, а не подключаясь через SSH. Это может быть полезно для проверки конфигурации системы, размещая плейбук в crontab. Это также может быть использовано для выполнения плейбука внутри установщика ОС, например, Anaconda kickstart.
Чтобы выполнить весь плейбук локально, просто установите строку “hosts:” на “hosts: 127.0.0.1”, а затем запустите плейбук следующим образом:
ansible-playbook playbook.yml --connection=local
В качестве альтернативы локальное подключение можно использовать в отдельном плейбуке плей, даже если другие плейбуки в плейбуке используют тип удаленного подключения по умолчанию:
- hosts: 127.0.0.1 connection: local
Прерывание выполнения при любой ошибке
С опцией ‘’any_errors_fatal’’, любая ошибка на любом хосте в плейбуке с несколькими хостами будет считаться фатальной, и Ansible немедленно завершит работу, не ожидая других хостов.
Иногда выполнение ‘’serial’’ не подходит; количество хостов непредсказуемо (из-за динамического инвентаря), а скорость критически важна (требуется одновременное выполнение), но все задачи должны быть на 100% успешными, чтобы продолжить выполнение плейбука.
Например, рассмотрим сервис, расположенный во многих дата-центрах с балансировщиками нагрузки для передачи трафика от пользователей к сервису. Есть плейбук развертывания для обновления пакетов deb сервиса. Плейбук имеет этапы:
- отключение трафика на балансировщиках нагрузки (должны быть выключены одновременно)
- безопасная остановка сервиса
- обновление программного обеспечения (этот шаг включает тесты и запуск сервиса)
- включение трафика на балансировщиках нагрузки (которые должны быть включены одновременно)
Сервис не может быть остановлен с «активными» балансировщиками нагрузки; они должны быть отключены в первую очередь. Из-за этого второй этап не может быть выполнен, если какой-либо сервер завершился ошибкой на первом этапе.
Для дата-центра «А» плейбук может быть написан следующим образом:
---
- hosts: load_balancers_dc_a
any_errors_fatal: True
tasks:
- name: 'shutting down datacenter [ A ]'
command: /usr/bin/disable-dc
- hosts: frontends_dc_a
tasks:
- name: 'stopping service'
command: /usr/bin/stop-software
- name: 'updating software'
command: /usr/bin/upgrade-software
- hosts: load_balancers_dc_a
tasks:
- name: 'Starting datacenter [ A ]'
command: /usr/bin/enable-dc
В этом примере Ansible начнет обновление программного обеспечения на фронтендах только в том случае, если все балансировщики нагрузки будут успешно отключены.
См. также
- Плейбуки
- Вводный курс по плейбукам
- Примеры Ansible на GitHub
- Многие примеры полномасштабных развертываний
- Список рассылки пользователей
- Есть вопрос? Заходите в группу Google!
- irc.freenode.net
- Канал IRC-чата #ansible
© 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_delegation.html