Spec-Zone.ru › Ansible 2.9

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

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

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

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

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

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

Также следует обратиться к разделу документации модулей. Модули, такие как ec2_elb, nagios, bigip_pool и другие сетевые модули, гармонично сочетаются с описанными здесь концепциями.

Также вам следует ознакомиться с ролями, так как концепции «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

В приведённом примере, если в группе «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’][‘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», используйте конструкцию when: inventory_hostname == ansible_play_hosts_all[0].

Примечание

Любое условие (например when:) будет использовать переменные «первого хоста», чтобы решить, запускать задачу или нет, другие хосты не будут проверены.

Примечание

Если вы хотите избежать стандартного поведения по установке факта для всех хостов, установите delegate_facts: True для конкретной задачи или блока.

Локальные плейбуки

Иногда полезно использовать плейбук локально, а не подключаясь по 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 завершится, как только все хосты в текущем пакете завершат выполнение фатальной задачи. Последующие задачи и плейбуки не будут выполняться. От ошибки, которая обычно считается фатальной, можно восстановиться, добавив раздел rescue в блок.

Иногда выполнение в режиме «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-ends, если все балансировщики нагрузки успешно отключены.

См. также

О книгах сценариев
Введение в книги сценариев
Примеры 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.9/user_guide/playbooks_delegation.html

Spec-Zone.ru

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