Spec-Zone.ru › Ansible 2.8

Делегирование, поэтапные обновления и локальные действия

  • Размер пакета поэтапного обновления
  • Максимальный процент сбоев
  • Делегирование
  • Делегированные факты
  • Выполнить один раз
  • Локальные плейбуки
  • Прервать выполнение при любой ошибке

Разработанный с самого начала для многоуровневых развертываний, Ansible отлично справляется с выполнением действий на одном хосте от имени другого или с выполнением локальных шагов со ссылкой на некоторые удалённые хосты.

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

Дополнительные возможности позволяют настраивать порядок завершения задач и назначать размер пакета для обработки сразу нескольких машин во время поэтапного обновления.

В этом разделе описываются все эти возможности. Примеры использования этих элементов можно найти в репозитории ansible-examples на GitHub. Там есть множество примеров процедур поэтапного обновления без простоя для различных типов приложений.

Также следует обратиться к разделу Работа с модулями, различные модули, такие как ‘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
    command: hostname
  - name: task two
    command: hostname

В приведённом примере, если у нас есть 4 хоста в группе ‘webservers’, 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’ в задаче. Это идеально подходит для размещения узлов в пуле балансировки нагрузки или для их удаления. Это также очень полезно для управления периодами простоя. Имейте в виду, что нет смысла делегировать все задачи, отладку, 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) отражает хост, на который делегирована задача.

Делегированные факты

По умолчанию любые факты, собранные делегированной задачей, назначаются хосту 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’][‘ansible_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_all[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 }}. Убедитесь, что в host_vars/localhost.yml, например, установлен ansible_python_interpreter: “{{ ansible_playbook_python }}”. Вы можете избежать этой проблемы, используя local_action или delegate_to: localhost вместо этого.

Прервать выполнение при любой ошибке

С помощью параметра ‘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 начнёт обновление программного обеспечения на front-end только в том случае, если все балансировщики нагрузки будут успешно отключены.

См. также

Работа с плейбуками
Введение в плейбуки
Примеры 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.8/user_guide/playbooks_delegation.html

Spec-Zone.ru

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