Инструменты пользователя

Инструменты сайта


linux:ansible:loops

Это старая версия документа!


===== Как использовать loops в Ansible =====+

В этом сообщении в блоге мы поговорим о 'циклах 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
  • loop: [1, 2, 3] указывает, что мы хотим выполнить цикл по числам 1, 2 и 3.
  • модуль ansible.builtin.debug выводит текущий номер.
  • loop_control: pause: 3 приостанавливается на 3 секунды после каждой задачи в цикле.

Когда вы запускаете этот сборник задач, Ansible печатает каждое число, делает паузу на 3 секунды, а затем переходит к следующей итерации цикла.

linux/ansible/loops.1703792275.txt.gz · Последние изменения: 2023/12/28 22:37 — werwolf