Оглавление:
Карта сайта:
Оглавление:
Карта сайта:
Это старая версия документа!
===== Как использовать loops в Ansible =====+
В этом сообщении в блоге мы поговорим о 'циклах Ansible'. Мы начнем с того, что такое 'циклы', используя простой повседневный пример, чтобы каждый мог понять. Затем мы объясним, почему мы используем циклы в Ansible и как они могут нам помочь. Мы рассмотрим самый базовый тип цикла, а затем рассмотрим несколько различных видов. Мы покажем, как эти циклы используются в реальных ситуациях. И, наконец, мы поделимся некоторыми распространенными ошибками, которых следует избегать при использовании циклов в Ansible.
Циклы в Ansible подобны ярлыкам для многократного выполнения одной и той же задачи. Вместо того чтобы повторять одни и те же шаги снова и снова, мы используем цикл, чтобы выполнять задачу столько раз, сколько нам нужно. Это экономит время и делает наши задачи менее подверженными ошибкам, потому что нам нужно написать инструкции только один раз.
- name: Install nginx apt: name: nginx state: present - name: Install mysql apt: name: mysql state: present - name: Install php apt: name: php state: present
Это работает, но это повторяющийся процесс, и им трудно управлять. Если вам нужно установить десять или двадцать пакетов, руководство становится длинным и его трудно читать.
Теперь давайте используем цикл для выполнения той же задачи. Вы перечисляете все пакеты, которые хотите установить, а затем пишете единственную задачу, которая перебирает список.t.
- name: Install Packages apt: name: "{{ item }}" state: present loop: - nginx - mysql - php
Этот сборник задач выполняет точно такую же работу, как и первый, но он намного короче и понятнее. Если вам нужно добавить больше пакетов, вы просто добавляете их в список. Цикл позаботится об установке каждого из них. В этом сила циклов в Ansible.
В циклах Ansible термин '{{ item }}' используется в качестве заполнителя для каждого элемента в списке, который вы просматриваете. Мы рассмотрим это более подробно позже в этом посте.
Ansible предоставляет простой и читаемый способ перебора набора задач с использованием ключевого слова 'loop'. Цель цикла - многократное повторение одной и той же задачи, что упрощает сценарий и сокращает количество повторений. Вот базовый синтаксис цикла Ansible.
tasks: - name: Task description ansible_module: key: "{{ item }}" loop: [item1, item2, item3]
* 'ansible_module' относится к модулю, который вы используете для выполнения задачи. В Ansible есть множество модулей для различных задач, таких как 'apt' для управления пакетами, 'file' для управления файлами и т.д. * 'ключ: '{{item }}'' - это место, где мы указываем Ansible, что нужно изменить в каждом цикле. '{{ item }}' - это заполнитель, который Ansible заменяет каждым элементом в списке циклов. * 'цикл' - это ключевое слово, которое запускает цикл, за которым следует список элементов для повторения цикла.
Возвращаясь к предыдущему примеру установки пакета, без цикла нам нужно было бы написать отдельную задачу для каждого пакета. С помощью цикла мы можем установить все пакеты с помощью одной задачи.
--- - name: Install packages using Ansible hosts: servers tasks: - name: Install Packages apt: pkg: "{{ item }}" state: present loop: - nginx - mysql - php
* Мы используем модуль 'apt', который управляет пакетами в системах на базе Debian. * Строка pkg: {{ item }} сообщает Ansible, что устанавливать на каждой итерации цикла. Ansible заменяет ' {{ item }}' на каждое имя пакета из списка. * Ключевое слово 'loop' запускает цикл, за которым следует список пакетов, которые мы хотим установить.
Когда вы запустите этот сборник задач, Ansible установит пакеты 'nginx', 'mysql' и 'php' один за другим. Если вам нужно установить больше пакетов, вы просто добавляете их в список. Вот почему циклы настолько мощны в Ansible: они позволяют нам управлять несколькими элементами в рамках одной задачи, независимо от того, сколько элементов у нас есть.
Чтобы перебрать этот словарь, вы можете использовать фильтр 'dict2items', который преобразует словарь в список элементов. Каждый элемент в этом списке представляет собой еще один словарь с 'ключом' и 'значением'.
--- - name: Assign roles to servers hosts: localhost gather_facts: no tasks: - name: Print server role info ansible.builtin.debug: msg: "Server: {{ item.key }}, Role: {{ item.value }}" loop: "{{ servers | dict2items }}" vars: servers: server1: 'web' server2: 'database'
* 'серверы' - это словарь, где каждый ключ представляет собой имя сервера, а значение - роль этого сервера. * Мы используем фильтр 'dict2items' для преобразования словаря 'серверы' в список элементов. Каждый элемент представляет собой словарь меньшего размера с 'ключом' (именем сервера) и 'значением' (ролью). * 'ansible.builtin.debug' - это модуль, который выводит сообщения на консоль. Мы используем его для распечатки каждого сервера и соответствующей ему роли. * сообщение: Сервер: {{ item.key }}, Роль: {{ item.value }} - это место, где мы указываем Ansible, что печатать. Он берет имя каждого сервера и его роль и печатает их в удобочитаемом формате.
Когда вы запускаете этот сборник задач, Ansible распечатывает сообщение для каждого сервера с указанием назначенной ему роли. Это простой способ перебирать словари в Ansible, когда каждый ключ имеет единственное соответствующее значение.
➜ ansible_local ansible-playbook loop_dict.yml PLAY [Assign roles to servers] ******************************************************************************************************** TASK [Print server role info] ********************************************************************************************************* ok: [127.0.0.1] => (item={'key': 'server1', 'value': 'web'}) => { "msg": "Server: server1, Role: web" } ok: [127.0.0.1] => (item={'key': 'server2', 'value': 'database'}) => { "msg": "Server: server2, Role: database" }
вы можете использовать фильтр 'продукт ' для создания декартова произведения данных списков, что означает, что каждый элемент первого списка сопряжен с каждым элементом второго списка. Это может быть полезно в сценариях, когда вам нужно выполнить задачу со всеми возможными комбинациями элементов из нескольких списков. Вот пример использования фильтра 'продукт'.
--- - name: Install packages on servers hosts: localhost gather_facts: no tasks: - name: Install packages ansible.builtin.debug: msg: "Installing {{ item.1 }} on {{ item.0 }}" loop: "{{ ['server1', 'server2'] | product(['nginx', 'mysql', 'php']) | list }}"
➜ ansible_local ansible-playbook nested_loop_product.yml PLAY [Install packages on servers] **************************************************************************************************** TASK [Install packages] *************************************************************************************************************** ok: [127.0.0.1] => (item=['server1', 'nginx']) => { "msg": "Installing nginx on server1" } ok: [127.0.0.1] => (item=['server1', 'mysql']) => { "msg": "Installing mysql on server1" } ok: [127.0.0.1] => (item=['server1', 'php']) => { "msg": "Installing php on server1" } ok: [127.0.0.1] => (item=['server2', 'nginx']) => { "msg": "Installing nginx on server2" } ok: [127.0.0.1] => (item=['server2', 'mysql']) => { "msg": "Installing mysql on server2" } ok: [127.0.0.1] => (item=['server2', 'php']) => { "msg": "Installing php on server2"
В Ansible вы также можете перебирать вложенные списки с помощью фильтра subelements. Это полезно, когда вы хотите выполнить задачу для каждой комбинации элементов во внешнем и внутреннем списках. Вот базовая структура использования фильтра subelements.
--- - name: Install packages on servers hosts: localhost gather_facts: no tasks: - name: Install packages ansible.builtin.debug: msg: "Installing {{ item.1 }} on {{ item.0.name }}" loop: "{{ servers | subelements('packages') }}" vars: servers: - name: server1 packages: - nginx - mysql - name: server2 packages: - httpd - postgresql
* 'серверы' - это список словарей. У каждого словаря есть ключ name для имени сервера и ключ packages для списка пакетов. * Мы используем фильтр subelements('пакеты') для циклического просмотра как серверов, так и их пакетов. * 'ansible.builtin.debug' - это модуль, который выводит сообщения на консоль. Мы используем его для распечатки каждой комбинации сервер-пакет. * 'сообщение: 'Установка {{ item.1 }} на {{ item.0.name }}'' - это место, где мы указываем Ansible, что печатать. Он берет имя каждого сервера и каждого пакета и печатает их в удобочитаемом формате.
➜ ansible_local ansible-playbook nested_list_loop.yml PLAY [Install packages on servers] **************************************************************************************************** TASK [Install packages] *************************************************************************************************************** ok: [127.0.0.1] => (item=[{'name': 'server1', 'packages': ['nginx', 'mysql']}, 'nginx']) => { "msg": "Installing nginx on server1" } ok: [127.0.0.1] => (item=[{'name': 'server1', 'packages': ['nginx', 'mysql']}, 'mysql']) => { "msg": "Installing mysql on server1" } ok: [127.0.0.1] => (item=[{'name': 'server2', 'packages': ['httpd', 'postgresql']}, 'httpd']) => { "msg": "Installing httpd on server2" } ok: [127.0.0.1] => (item=[{'name': 'server2', 'packages': ['httpd', 'postgresql']}, 'postgresql']) => { "msg": "Installing postgresql on server2"
Иногда при выполнении действий в цикле нам может потребоваться сделать паузу между итерациями. Это может быть связано с тем, что мы ожидаем перезапуска сервера, появления файла или по ряду других причин. Вы можете использовать 'loop_control' с 'pause', чтобы добавить задержку между каждой итерацией цикла.
--- - name: Pausing within a loop using loop_control hosts: localhost gather_facts: no tasks: - name: Print number with pause ansible.builtin.debug: msg: "{{ item }}" loop: [1, 2, 3] loop_control: pause: 3
Когда вы запускаете этот сборник задач, Ansible печатает каждое число, делает паузу на 3 секунды, а затем переходит к следующей итерации цикла.