Делегирование, поэтапные обновления и локальные действия
- Размер пакета поэтапного обновления
- Максимальный процент сбоев
- Делегирование
- Делегированные факты
- Выполнить один раз
- Локальные плейбуки
- Прерывание выполнения при любой ошибке
Разработанный с самого начала для многоуровневых развертываний, Ansible отлично справляется с выполнением задач на одном хосте от имени другого или выполнением локальных шагов со ссылкой на некоторые удалённые хосты.
Это особенно актуально при настройке инфраструктуры непрерывной интеграции или поэтапных обновлений без простоев, когда вам нужно взаимодействовать с балансировщиками нагрузки или системами мониторинга.
Дополнительные возможности позволяют настраивать порядок завершения задач и задавать размер пакетной обработки для количества машин, обрабатываемых одновременно во время поэтапного обновления.
В этом разделе рассматриваются все эти возможности. Примеры использования этих элементов см. в репозитории ansible-examples. Там есть множество примеров процедур поэтапного обновления без простоев для различных типов приложений.
Также следует обратиться к разделу Работа с модулями, различные модули, такие как ‘ec2_elb’, ‘nagios’, ‘bigip_pool’ и ‘netscaler’, тесно связаны с концепциями, упомянутыми здесь.
Также необходимо ознакомиться с Ролями, так как понятия ‘pre_task’ и ‘post_task’ — это места, где обычно вызываются эти модули.
Обратите внимание, что некоторые задачи невозможно делегировать, например include, add_host, debug, и т. д., так как они всегда выполняются на контроллере.
Размер пакета поэтапного обновления
По умолчанию Ansible пытается управлять всеми машинами, указанными в плейбуке, параллельно. Для сценария поэтапного обновления вы можете определить, сколько хостов Ansible должен обрабатывать за раз, используя ключевое слово serial.
- name: test play
hosts: webservers
serial: 2
gather_facts: False
tasks:
- name: task one
comand: hostname
- name: task two
command: hostname
В приведенном примере, если в группе «webservers» есть 4 хоста, 2 из них полностью завершат выполнение плейбука, прежде чем перейти к следующим 2 хостам:
PLAY [webservers] **************************************** TASK [task one] ****************************************** changed: [web2] changed: [web1] TASK [task two] ****************************************** changed: [web1] changed: [web2] PLAY [webservers] **************************************** TASK [task one] ****************************************** changed: [web3] changed: [web4] TASK [task two] ****************************************** changed: [web3] changed: [web4] PLAY RECAP *********************************************** web1 : ok=2 changed=2 unreachable=0 failed=0 web2 : ok=2 changed=2 unreachable=0 failed=0 web3 : ok=2 changed=2 unreachable=0 failed=0 web4 : ok=2 changed=2 unreachable=0 failed=0
Ключевое слово serial также может быть задано в процентах, которые будут применяться к общему количеству хостов в плейбуке для определения количества хостов за проход:
- 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 или более.
Максимальный процент сбоев
По умолчанию Ansible будет продолжать выполнять действия, пока есть хосты в пакете, которые еще не завершились ошибкой. Размер пакета для плейбука определяется параметром serial. Если serial не задан, то размер пакета равен всем хостам, указанным в поле hosts:. В некоторых ситуациях, таких как описанные выше поэтапные обновления, может потребоваться прервать выполнение плейбука, когда определенный порог сбоев будет достигнут. Для этого можно установить максимальный процент сбоев для плейбука следующим образом:
- hosts: webservers max_fail_percentage: 30 serial: 10
В приведенном примере, если более 3 из 10 серверов в группе откажутся, остальная часть плейбука будет прервана.
Примечание
Установленный процент должен быть превышен, а не равен. Например, если serial был установлен на 4, и вы хотите прервать задачу при отказе 2 систем, процент должен быть установлен на 49, а не на 50.
Делегирование
Это не конкретно для поэтапного обновления, но часто используется в таких случаях.
Если вы хотите выполнить задачу на одном хосте со ссылкой на другие хосты, используйте ключевое слово ‘delegate_to’ в задаче. Это идеально подходит для размещения узлов в пуле балансировщиков нагрузки или для их удаления. Это также очень полезно для управления окнами простоев. Обратите внимание, что не имеет смысла делегировать все задачи, отладка, добавление хоста, включение и т. д. всегда выполняются на контроллере. Использование этого с ключевым словом ‘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) отражает хост, на который делегирована задача.
Делегированные факты
По умолчанию любые факты, собранные делегированной задачей, назначаются хосту inventory_hostname (текущему хосту), а не хосту, который фактически их собрал (хосту, которому делегирована задача). Директива delegate_facts может быть установлена в значение True, чтобы назначить собранные факты задачи хосту, которому делегирована задача, а не текущему хосту:
- hosts: app_servers
tasks:
- name: gather facts from db servers
setup:
delegate_to: "{{item}}"
delegate_facts: True
loop: "{{groups['dbservers']}}"
Вышеприведённое соберет факты для машин в группе dbservers и назначит их этим машинам, а не app_servers. Таким образом, вы можете обратиться к hostvars[‘dbhost1’][‘default_ipv4’][‘address’], даже если dbservers не входили в плейбук или были исключены, используя –limit.
Выполнить один раз
В некоторых случаях может потребоваться запустить задачу только один раз для группы хостов. Это можно сделать, настроив «run_once» для задачи:
---
# ...
tasks:
# ...
- command: /opt/application/upgrade_db.py
run_once: true
# ...
Эта директива принуждает задачу к попытке выполнения на первом хосте текущего пакета, а затем применяет все результаты и факты ко всем хостам в этом же пакете.
Этот подход похож на применение условия к задаче, например:
- command: /opt/application/upgrade_db.py when: inventory_hostname == webservers[0]
Но результаты применяются ко всем хостам.
Как и большинство задач, это можно дополнительно сочетать с «delegate_to», чтобы указать отдельный хост для выполнения:
- command: /opt/application/upgrade_db.py run_once: true delegate_to: web01.example.org
Как всегда при делегировании, действие будет выполнено на делегированном хосте, но информация остаётся от исходного хоста в задаче.
Примечание
При использовании вместе с «serial», задачи, помеченные как «run_once», будут выполняться на одном хосте в каждом пакете serial. Если крайне важно, чтобы задача выполнялась только один раз, независимо от режима «serial», используйте конструкцию when: inventory_hostname == ansible_play_hosts[0].
Примечание
Любое условие (например, when:) будет использовать переменные «первого хоста», чтобы решить, выполняется ли задача или нет; другие хосты не будут проверены.
Локальные плейбуки
Иногда полезно использовать плейбук локально, а не подключаясь по SSH. Это может быть полезно для проверки конфигурации системы, помещая плейбук в crontab. Это также может использоваться для выполнения плейбука внутри установщика ОС, например, в Anaconda kickstart.
Чтобы запустить весь плейбук локально, просто установите строку «hosts:» в «hosts: 127.0.0.1», а затем запустите плейбук так:
ansible-playbook playbook.yml --connection=local
В качестве альтернативы, локальное соединение можно использовать в отдельном плейбуке плей, даже если другие плей в плейбуке используют стандартный тип удалённого подключения:
- hosts: 127.0.0.1 connection: local
Примечание
Если вы установили подключение к локальному хосту и не задан ansible_python_interpreter, модули будут выполняться в /usr/bin/python, а не в {{ ansible_playbook_python }}. Убедитесь, что вы установили ansible_python_interpreter: “{{ ansible_playbook_python }}” в host_vars/localhost.yml, например. Вы можете избежать этой проблемы, используя local_action или delegate_to: localhost вместо этого.
Прерывание выполнения при любой ошибке
С помощью опции ‘’any_errors_fatal’’ любой сбой на любом хосте в многохостовом плейбуке будет рассматриваться как критический и Ansible немедленно завершит работу, не дожидаясь других хостов.
Иногда выполнение ‘’serial’’ не подходит; количество хостов непредсказуемо (из-за динамичной инвентаризации) и скорость важна (требуется одновременное выполнение), но все задачи должны быть на 100% успешны для продолжения выполнения плейбука.
Например, рассмотрим службу, расположенную во многих дата-центрах с балансировщиками нагрузки для передачи трафика от пользователей к службе. Существует плейбук для развертывания, чтобы обновить пакеты deb службы. Плейбук имеет этапы:
- отключение трафика на балансировщиках нагрузки (должно быть отключено одновременно)
- безопасная остановка службы
- обновление программного обеспечения (этап включает тесты и запуск службы)
- включение трафика на балансировщиках нагрузки (должно быть включено одновременно)
Служба не может быть остановлена с «живыми» балансировщиками нагрузки; их необходимо отключить в первую очередь. Из-за этого второй этап не может быть выполнен, если любой сервер завершился ошибкой на первом этапе.
Для дата-центра «A» плейбук можно написать так:
---
- 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 запустит обновление программного обеспечения на front-end только в том случае, если все балансировщики нагрузки будут успешно отключены.
См. также
- Работа с Playbook
- Вступление в Playbook
- Примеры 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.6/user_guide/playbooks_delegation.html