Управление местом выполнения задач: делегирование и локальные действия
По умолчанию Ansible собирает факты и выполняет все задачи на машинах, соответствующих строке hosts вашего плейбука. На этой странице показано, как делегировать задачи другой машине или группе, делегировать сбор фактов определённым машинам или группам либо запускать плейбук целиком локально. Эти подходы позволяют точно и эффективно управлять взаимосвязанными средами. Например, при обновлении веб-серверов может потребоваться временно исключить их из пула балансировщика нагрузки. Выполнить эту задачу непосредственно на веб-серверах нельзя. Делегировав задачу localhost, вы сохраняете все задачи в одном плейбуке.
- Задачи, которые нельзя делегировать
- Делегирование задач
- Шаблонизация в контексте делегирования
- Делегирование и параллельное выполнение
- Делегирование сбора фактов
- Локальные плейбуки
Задачи, которые нельзя делегировать
Некоторые задачи всегда выполняются на управляющем узле. Эти задачи, включая include, add_host и debug, нельзя делегировать. Возможность делегирования действия можно определить по документации атрибута connection. Если атрибут connection указывает, что support равен False или None, действие не использует подключение и не может быть делегировано.
Делегирование задач
Если нужно выполнить задачу на одном узле, используя сведения о других узлах, укажите в задаче ключевое слово delegate_to. Это удобно для управления узлами в пуле балансировщика нагрузки или контроля периодов недоступности. Для управления количеством узлов, выполняющих задачи одновременно, можно использовать делегирование вместе с ключевым словом serial:
---
- hosts: webservers
serial: 5
tasks:
- name: Take out of load balancer pool
ansible.builtin.command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
delegate_to: 127.0.0.1
- name: Actual steps would go here
ansible.builtin.yum:
name: acme-web-stack
state: latest
- name: Add back to load balancer pool
ansible.builtin.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: ansible.builtin.command
args:
cmd: /usr/bin/take_out_of_pool {{ inventory_hostname }}
# ...
- name: Add back to load balancer pool
local_action: ansible.builtin.command
args:
cmd: /usr/bin/add_back_to_pool {{ inventory_hostname }}
Для рекурсивного копирования файлов на управляемые серверы можно использовать локальное действие, вызывающее ‘rsync’:
---
# ...
tasks:
- name: Recursively copy files from management server to target
local_action: ansible.builtin.command
args:
cmd: "rsync -a /path/to/files {{ inventory_hostname }}:/path/to/target/"
Обратите внимание: для этого необходимо настроить SSH-ключи без парольной фразы или ssh-agent, иначе rsync запросит парольную фразу.
Чтобы указать дополнительные аргументы, используйте следующий синтаксис:
---
# ...
tasks:
- name: Send summary mail
local_action: community.general.mail
args:
subject: "Summary Mail"
to: "{{ mail_recipient }}"
body: "{{ mail_body }}"
run_once: True
Примечание
- Переменная
ansible_hostи другие переменные подключения, если они заданы, содержат сведения об узле, которому делегирована задача, а не об inventory_hostname. - Узел, которому делегирована задача, не наследует переменные узла, делегирующего задачу.
Предупреждение
Хотя вы можете delegate_to узел, которого нет в инвентаре (указав IP-адрес, DNS-имя или другое значение, необходимое модулю подключения), это не добавит узел в инвентарь и может вызвать проблемы. Узлы, делегированные таким образом, наследуют переменные группы «all» (при условии, что VARIABLE_PRECEDENCE включает all_inventory). Если необходимо delegate_to узел, отсутствующий в инвентаре, используйте модуль add host.
Шаблонизация в контексте делегирования
Обратите внимание: при делегировании интерпретатор выполнения (обычно Python), параметры плагина connection, become и shell будут подставляться с использованием значений делегированного узла. Теперь все переменные, кроме inventory_hostname, будут браться с этого узла, а не с исходного узла задачи. Если для этих параметров нужны переменные исходного узла задачи, необходимо использовать hostvars[inventory_hostname]['varname'], даже если inventory_hostname_short ссылается на делегированный узел.
Делегирование и параллельное выполнение
По умолчанию задачи Ansible выполняются параллельно. Делегирование задачи не меняет этого и не решает проблемы параллельного доступа (например, когда несколько процессов записывают в один файл). Чаще всего пользователи сталкиваются с этим при обновлении одного файла на одном делегированном узле для всех узлов (например, с помощью модулей copy, template или lineinfile). Задачи по-прежнему будут выполняться параллельно в процессах (по умолчанию их 5) и перезаписывать данные друг друга.
Это можно решить несколькими способами:
- name: "handle concurrency with a loop on the hosts with `run_once: true`"
lineinfile: "<options here>"
run_once: true
loop: '{{ ansible_play_hosts_all }}'
Использовав промежуточный плей с serial: 1 или указав throttle: 1 на уровне задачи. Подробнее см. раздел Управление выполнением плейбуков: стратегии и другие возможности.
Делегирование сбора фактов
Делегирование задач Ansible похоже на делегирование задач в реальном мире: продукты принадлежат вам, даже если кто-то другой доставляет их к вам домой. Аналогичным образом факты, собранные делегированной задачей, по умолчанию назначаются inventory_hostname (текущему узлу), а не узлу, который собрал эти факты (делегированному узлу). Чтобы назначить собранные факты делегированному узлу, а не текущему, задайте delegate_facts значение true:
---
- hosts: app_servers
tasks:
- name: Gather facts from db servers
ansible.builtin.setup:
delegate_to: "{{ item }}"
delegate_facts: true
loop: "{{ groups['dbservers'] }}"
Эта задача собирает факты для машин из группы dbservers и назначает их этим машинам, хотя плей нацелен на группу app_servers. Так можно находить hostvars[‘dbhost1’][‘ansible_default_ipv4’][‘address’], даже если dbservers не входят в плей или исключены с помощью --limit.
Локальные плейбуки
Иногда полезно запускать плейбук локально на удалённом узле, а не подключаться к нему по 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.
См. также
- Плейбуки Ansible
-
Введение в плейбуки
- Управление выполнением плейбуков: стратегии и другие возможности
-
Дополнительные способы управления тем, как и где Ansible выполняет задачи
- Общение
-
Есть вопросы? Нужна помощь? Хотите поделиться идеями? Посетите руководство по общению с сообществом Ansible
© 2012–2018 Michael DeHaan
© 2018–2025 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_delegation.html