Делегирование, поэтапные обновления и локальные действия
- Размер пакета поэтапного обновления
- Максимальный процент сбоев
- Делегирование
- Делегированные факты
- Выполнить один раз
- Локальные плейбуки
- Прервать выполнение при любой ошибке
Разработанный с самого начала для многоуровневых развертываний, 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-агента, иначе 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
# ...
Это можно дополнительно использовать с «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. Если важно, чтобы задача выполнялась только один раз независимо от режима «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
Примечание
Если вы установили подключение на локальное и не задано 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 начнёт обновление программного обеспечения на фронтендах только если все балансировщики нагрузки будут успешно отключены.
См. также
- Работа с плейбуками
- Вступление к плейбукам
- Примеры Ansible на GitHub
- Многие примеры полномасштабных развертываний
- Список рассылки пользователей
- У вас есть вопрос? Загляните в группу Google!
- irc.freenode.net
- #ansible IRC чат-канал
© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.5/user_guide/playbooks_delegation.html