Playbook
Playbook (плейбук) в Ansible - это файл YAML, который содержит описание задач и действий, которые Ansible должен выполнить на целевых узлах. Плейбук представляет собой основной инструмент для создания автоматизированных задач конфигурации и управления системами.
Playbook состоит из plays
Play
play - это раздел в плейбуке, который определяет набор задач, которые должны быть выполнены на определенной группе хостов или одном хосте. Плеи представляют собой строительные блоки автоматизации в Ansible и используются для организации задач на основе целевых хостов и их назначения.
---
- name: Название плея
hosts: целевые_хосты
become: yes # (необязательно) Установите 'yes', если вам нужно выполнять задачи с повышенными привилегиями
vars:
имя_переменной: значение # (необязательно) Переменные на уровне плея
pre_tasks: # (необязательно) tasks которые нужно выполнить в первую очередь, до roles и tasks, могут обращаться к handlers
tasks: # (необязательно) можно все делать с помощью roles
- name: Название задачи
module_name:
параметр_модуля: значение
become: yes # (необязательно) Привилегии на уровне задачи
roles: # (необязательно) можно все делать с помощью tasks
- role-name1
- role-name2
post_tasks: # необязательный параметр, перечисление tasks, которые необходимо выполнить после tasks и roles
handlers: # (необязательно) обработчики событий, запускаются, если какая-то task или role обратилась к handler, могут быть сгруппированы через listen
tags: # (необязательно) позволяет группировать roles, tasks и вызывать их запуск отдельно от остальных сущностей
# Минимальный набор указаний для выполнения play: play-name, hosts, task(role)-name
- name: Test play # Имя плея
hosts: all # Целевые хосты
tasks: # Определение блока тасок
- name: Debug massage # Имя таски
debug: # Вызов модуля debug
msg: "Hello from ansible" # Вывод сообщения в консоль
Зарезервированные параметры которые можно применять в play
- any_errors_fatal: true # Когда этот параметр установлен в true, это означает, что любая ошибка (независимо от её типа)
# в процессе выполнения задачи сделает выполнение плейбука неуспешным и вызовет прерывание выполнения плейбука.
- any_errors_fatal: false # По умолчанию - false, что означает, что Ansible будет продолжать
# выполнение плейбука, даже если в процессе выполнения задач возникают ошибки.
- become: yes # Выполнение задачи с привилегиями суперпользователя
- become_user: root # Выполнение задачи от имени пользователя root
- check_mode: yes # это опция в Ansible, которая позволяет вам выполнять задачи в режиме проверки без фактического изменения состояния целевой системы.
# В этом режиме Ansible выполняет все шаги задачи, но не вносит фактических изменений.
- diff: yes # используется для включения вывода разницы (diff) при выполнении задачи, которая изменяет файлы или конфигурацию.
- meta:
force_handlers: true # Этот параметр может использоваться для принудительного выполнения обработчиков (handlers), даже если задачи, вызывающие их, завершились с ошибкой.
- gather_facts # булевая переменная для контроля запуска сбора фактов с хостов
- gather_facts: yes # (по умолчанию): факты будут собраны для всех хостов, указанных в инвентаре, перед выполнением задач в плейбуке. Факты будут доступны в переменной ansible_facts для каждого хоста.
- gather_facts: no # Ansible не будет собирать факты перед выполнением задач. Это может быть полезно, если вам не нужна информация о хостах, и вы хотите ускорить выполнение плейбука.
- ignore_errors: yes # позволяет игнорировать ошибки при выполнении tasks и продолжить выполнение play
- ignore_unreachable: yes # позволяет игнорировать ошибки недоступности хоста и продолжать выполнение play
# Параметр ignore_unreachable полезен, когда вы хотите выполнить плейбук на множестве хостов, но не обязательно требуете, чтобы все они были доступны.
- max_fail_percentage: 15 # определяет максимальный процент задач, которые могут завершиться с ошибкой, прежде чем выполнение плейбука будет прервано.
# max_fail_percentage позволяет более гибко управлять тем, какие ошибки следует считать критичными для выполнения плейбука, и какие можно игнорировать.
- order # позволяет указать порядок сортировки хостов из inventory
- run_once # запустить данный play только на первом хосте из inventory в рамках одного batch
- serial # позволяет определить количество хостов, на которых запускается данный play в рамках одного batch
Tasks
Задачи (Tasks): Задачи представляют собой конкретные действия, которые необходимо выполнить на целевых узлах. Каждая задача имеет имя, модуль Ansible (например, apt, yum, file, service, и т. д.), и параметры для выполнения задачи.
tasks: # Объявление списка tasks
- name: Get Docker version # Произвольное имя для task
ansible.builtin.command: docker --version # Что и как необходимо сделать
register: is_installed # Запись результата в переменную is_installed
notify: # Директива notify позволяет обратиться к handlers, чтобы он был исполнен в конце выполнения всех tasks
- Restart Nginx # Вызов handler Restart Nginx
- name: Get RPM # Произвольное имя для второй task
ansible.builtin.get_url: # Объявление использования module get_url, ниже указание его параметров
url: “https://url_с_нужным_пакетом”
when: # Условия при которых task будет выполняться
- is_installed is failed
Tasks можно принудительно воспроизвести на указанном хосте: - Для того, чтобы определить на каком хосте необходимо выполнить task - нужно использовать delegate_to. - Если действие необходимо делать на localhost, можно использовать инструкцию local_action
Tasks можно и нужно разделять на pre_tasks, tasks и post_tasks: - Разделение группируется по вашей собственной внутренней логике - Если task внутри этих групп вызвала handler, то он выполнится после того, как закончит исполнение последней task из текущей группы - Внутри набора tasks их можно также группировать при помощи group
Ansible не рекомендует ставить на выполнение такси и роли в одном play. Т.е. если в play выполняет роли, то пусть только их и выполняет, дополнительные таски можно разместить в разделах pre_tasks и post_tasks
Blocks of tasks
В Ansible блоки (blocks) используются для группировки нескольких задач в единый логический блок. Это позволяет применять к ним общие действия, такие как обработка исключений или применение общих условий. Блоки могут быть полезны для повышения читаемости и управляемости кода, особенно при работе с большим количеством задач.
- name: Пример использования блоков
hosts: localhost
tasks:
- name: Блок задач
block:
- name: Задача 1
debug:
msg: "Выполняется задача 1"
- name: Задача 2
debug:
msg: "Выполняется задача 2"
# Обработка ошибок, если какая-то задача из блока завершилась неудачно
rescue:
- debug:
msg: "Произошла ошибка при выполнении блока задач"
# Заключительные действия, выполняемые после выполнения блока задач (независимо от успеха или неудачи)
always:
- debug:
msg: "Выполнение блока задач завершено"
# В этом примере:
# Блок block содержит две задачи, которые будут выполнены вместе как единое действие.
# Если хотя бы одна из задач завершится неудачно, будет выполнен блок rescue, который может содержать дополнительные задачи по обработке ошибок.
# Блок always содержит задачи, которые будут выполнены независимо от результата выполнения задач в блоке block.
Как запустить Playbook?
# Первый запуск стоит осуществлять или на тестовом окружении или с флагом --check:
ansible-playbook -i inventory/<inv_file>.yml <playbook_name>.yml --check
# Если были найдены ошибки:
ansible-playbook -i inventory/<inv_file>.yml <playbook_name>.yml --start-at-task <task_name>
# Для запуска исполнения в полуинтерактивном виде:
ansible-playbook -i inventory/<inv_file>.yml <playbook_name>.yml --step
# Полноценный запуск playbook в целевом виде должен выглядеть:
ansible-playbook -i inventory/<inv_file>.yml <playbook_name>.yml
# Запуск плейбука с использованием другого файла инвентаря
ansible-playbook -i my_inventory.ini my_playbook.yml
# Запуск плейбука с передачей дополнительных переменных
ansible-playbook -e "my_var=value" my_playbook.yml
# Запуск плейбука только на определенных хостах
ansible-playbook -l my_host my_playbook.yml
# Запуск плейбука только с задачами, помеченными метками
ansible-playbook -t my_tag my_playbook.yml
# Запуск плейбука в режиме проверки (dry-run)
ansible-playbook --check my_playbook.yml
# В первую очередь, нужно использовать debugger
# Необходимо использовать возможности check
# Организовать запуск на тестовом окружении
# Нужно не забывать про идемпотентность и использовать флаг --diff:
ansible-playbook -i inventory/<inv_file>.yml <playbook_name>.yml --diff
# Тестировать playbook против разного окружения на control node
# Тестировать playbook против разного окружения на managed node
# Активно использовать флаг -vvv
Vars
Переменные в Ansible используются для хранения и передачи данных, которые могут быть использованы в задачах, шаблонах (templates), ролях и других частях автоматизации. Переменные могут быть определены на разных уровнях, и у них есть приоритеты, определяющие, какие значения будут использоваться при выполнении задач.
Основные уровни, на которых могут быть определены переменные:
-
Глобальные переменные (Global Variables): Глобальные переменные определяются в файле
/etc/ansible/ansible.cfg(или в другом конфигурационном файле Ansible). Они применяются ко всем задачам и плеям (plays) на всех хостах и имеют наивысший приоритет. -
Переменные инвентаря (Inventory Variables): Вы можете определять переменные для конкретных хостов или групп хостов в вашем файле инвентаря. Эти переменные могут быть определены как в формате INI, так и в формате YAML.
-
Переменные плейбука (Playbook Variables): Вы можете определять переменные внутри плейбука с помощью ключа
vars. Эти переменные будут применяться только к задачам внутри данного плейбука. -
Групповые переменные (Group Variables): Вы можете определить групповые переменные в каталоге group_vars. Эти переменные применяются ко всем хостам в соответствующей группе.
-
Переменные роли (Role Variables): Роли в Ansible могут иметь свои собственные переменные, определенные в каталоге defaults или vars внутри роли. Эти переменные могут быть использованы только внутри соответствующей роли.
Когда переменные определены на нескольких уровнях, Ansible применяет их в соответствии с приоритетами, и переменные с более высоким приоритетом переопределяют значения переменных с более низким приоритетом. Например, переменные плейбука переопределяют групповые переменные, а глобальные переменные имеют приоритет над всеми остальными.
Уровни приоритезации (от меньшего к большему):
- Значения из командной строки (
-u username); - Значения по умолчанию из roles;
- Значения из файла
inventory; - Значения из файлов
group_vars/all; - Значения из файлов
group_vars/{groupname}; - Переменные из
play; - Значения переменных
roleиз vars; - Экстра-аргументы из командной строки (
-e “user=myuser”).
Handlers
Handlers - это специальные задачи, которые выполняются только в случае изменения состояния системы после выполнения задач. Handlers часто используются для перезапуска служб или выполнения других действий в ответ на изменения конфигурации.
По умолчанию, если задача, вызывающая обработчик, завершилась с ошибкой, обработчик не будет выполнен. Однако, установив параметр force_handlers: true, вы можете заставить Ansible выполнить обработчики, даже если предшествующие задачи завершились с ошибкой.
Handlers используются для проведения одного действия в рамках одного play, например, для рестарта сервиса, после обновления конфигурации.
- Указывается в директиве Play.
- На handler могут ссылаться task, role, pre_task, post_task.
- Вне зависимости от того, сколько раз handler был вызван - он исполнится один раз.
- Если handler вызван в role - он исполнится после всех roles.
- Если handler вызван в tasks любого вида - он исполнится в конце tasks, в рамках которого был вызван.
- Handler, который определён в рамках одного playbook может быть вызван в любом play
handlers: # Объявление списка handlers
- name: restart-prometheus # Произвольное имя для handler
ansible.builtin.service: # Вызов module, обрабатывающего операции с сервисами
name: prometheus # Имя сервиса
state: restarted # Ожидаемый результат работы модуля
listen: “restart monitoring” # Группировка handlers для возможности вызова группы
- name: restart-alertmanager
ansible.builtin.service:
name: alertmanager
state: restarted
listen: “restart monitoring”
Inventory
Inventory (инвентарь) в Ansible - это файл или набор файлов, которые содержат информацию о целевых хостах и их атрибутах, таких как IP-адреса, имена хостов, группы хостов и переменные. Инвентарь используется для определения того, на какие хосты и группы хостов Ansible должен направлять свои задачи и действия.
Инвентарь может быть представлен в различных форматах, таких как INI, YAML или JSON, и может содержать следующую информацию:
- Имена и IP-адреса хостов: Инвентарь должен указывать, на какие хосты следует направлять задачи. Обычно это включает в себя имена хостов или их IP-адреса.
- Группы хостов: Хосты могут быть объединены в группы. Группы могут иметь описательные имена, и вы можете выполнять задачи на всей группе хостов. Группы также могут вложиться в другие группы для создания иерархии.
- Переменные хостов и групп: Вы можете назначать переменные хостам и группам в инвентаре. Эти переменные используются для настройки задач и плейбуков. Например, вы можете определить переменные, такие как ansible_user (пользователь, используемый для подключения) или ansible_ssh_pass (пароль SSH) для хостов.
INI inventary
В этом примере есть две группы хостов (web_servers и db_servers) и каждая группа содержит переменные хостов (ansible_host и ansible_user). Группы также имеют свои собственные переменные (web_var и db_var).
[web_servers]
web1 ansible_host=192.168.1.10 ansible_user=webuser
[db_servers]
db1 ansible_host=192.168.1.11 ansible_user=dbuser
[web_servers:vars]
web_var=web_value
[db_servers:vars]
db_var=db_value
YAML inventary
Это пример структуры файла инвентаря в формате YAML. В этом файле определены группы хостов (group1, group2) и их характеристики, такие как IP-адреса, пользователи для подключения и другие параметры. Каждая группа хостов может также иметь свои собственные групповые переменные (vars).
Обратите внимание, что группы могут вложиться в другие группы, что позволяет создавать иерархию для организации хостов. Глобальные переменные (vars вне блока children) применяются ко всем хостам.
all:
children: # Секция "children" содержит определения групп хостов
group1: # Имя группы
hosts: # Секция "hosts" содержит список хостов в группе
host1:
ansible_host: 192.168.1.10 # IP-адрес или DNS-имя хоста
ansible_user: user1 # Имя пользователя для подключения
ansible_port: 22 # (необязательно) Порт SSH (по умолчанию 22)
ansible_ssh_private_key_file: /путь/к/ключу/id_rsa # (необязательно) Путь к ключу SSH
ansible_ssh_pass: пароль # (необязательно) Пароль SSH (не рекомендуется)
переменная1: значение1 # (необязательно) Дополнительные переменные хоста
host2:
ansible_host: 192.168.1.11
ansible_user: user2
# Дополнительные хосты в группе group1
vars: # (необязательно) Секция "vars" содержит переменные, применяемые к группе
групповая_переменная1: значение1
групповая_переменная2: значение2
group2:
hosts:
host3:
ansible_host: 192.168.1.12
ansible_user: user3
# Дополнительные хосты в группе group2
vars:
групповая_переменная3: значение3
vars: # (необязательно) Глобальные переменные для всех хостов
глобальная_переменная1: значение1
глобальная_переменная2: значение2
Inventary path
Ansible автоматически ищет инвентарь в стандартных местоположениях, но вы также можете явно указать путь к инвентарю, используя опцию -i или --inventory-file при выполнении команд Ansible.
ansible -i inventory.ini web_servers -m ping
# В этой команде Ansible использует инвентарь из файла inventory.ini и выполняет модуль ping на группе хостов web_servers.
После определения инвентаря Ansible можно использовать для выполнения задач на определенных группах хостов. Например, если вы хотите выполнить задачу на хостах из группы web_servers, вы можете использовать следующую команду:
ansible-playbook -i inventory.yml -l web_servers my_playbook.yml
# В этой команде -i используется для указания пути к инвентарю YAML (inventory.yml),
# а -l используется для указания целевой группы хостов (web_servers).
Templates (jinja2)
Templates (шаблоны) - это способ создания и управления файлами конфигурации, которые могут быть динамически сгенерированы в зависимости от переменных и данных из вашей инфраструктуры. Это особенно полезно при настройке приложений или служб, где конфигурационные файлы должны быть настроены на основе конкретных условий на целевых хостах.
Вот как работают шаблоны в Ansible:
- Создание шаблона: Вы создаете файл-шаблон, который содержит текстовое описание конфигурационного файла, в котором вместо конкретных значений используются переменные и выражения Jinja2. Jinja2 - это язык шаблонов, который позволяет вставлять переменные и выполнение логики в текстовых файлах.
- Передача переменных: Вы передаете переменные в шаблон из плейбука Ansible. Эти переменные могут содержать информацию о конфигурации, которую вы хотите применить к хостам.
- Рендеринг шаблона: Ansible занимается рендерингом (заменой) переменных в шаблоне с использованием данных, переданных из плейбука. Результатом является конфигурационный файл, который будет использоваться на целевых хостах.
- Копирование и применение: Закончив рендеринг, Ansible копирует полученный файл-шаблон на целевые хосты и применяет его в соответствии с вашими задачами и плейбуками.
---
- name: Configure Nginx
hosts: web_servers
tasks:
- name: Create Nginx configuration file
template:
src: nginx.conf.j2 # Исходный шаблон
dest: /etc/nginx/nginx.conf # Путь, куда будет скопирован конфигурационный файл
notify:
- Reload Nginx
handlers:
- name: Reload Nginx
service:
name: nginx
state: reloaded
# В этом примере мы используем задачу template для создания конфигурационного файла Nginx.
# Файл nginx.conf.j2 - это шаблон, который может содержать переменные и выражения Jinja2.
# Ansible рендерит этот шаблон, заменяя переменные, и копирует результат в /etc/nginx/nginx.conf на целевых хостах.
Tag
Tag позволяет пометить какую-либо сущность ansible для отдельного исполнения.
Их можно выставлять для:
- Отдельной task.
- Группы tasks.
- Include.
- Play.
- Role.
- Import
Существует два выделенных tags:
- always - выполняется всегда, если явно не указано пропустить.
- never - не выполняется никогда, если явно не указано запустить
Список ключей для использования tags:
- --tags all
- --tags tagged
- --tags untagged
- --tags [tag1, tag2]
- --skip-tags [tag1, tag2]
- --list-tags
- --list-tasks (with --tags or --skip-tags)
Facts
Ansible Facts - это информация о хосте, на котором выполняется автоматизация с помощью Ansible. Эта информация автоматически собирается Ansible и предоставляется в виде переменных, которые можно использовать в плейбуках и ролях. Факты Ansible полезны для:
- Динамической конфигурации: Факты позволяют плейбукам и ролям адаптироваться к хостам на основе их характеристик. Например, вы можете использовать факты, чтобы определить, на какой операционной системе работает хост, и выполнить разные действия в зависимости от этого.
- Универсальности и переносимости: Используя факты, вы можете писать более универсальные и переносимые плейбуки, которые могут работать на разных хостах с разными конфигурациями.
- Определения ресурсов и задач: Факты могут использоваться для определения доступных ресурсов на хосте, таких как диски, память, CPU и т. д., что позволяет плейбукам принимать решения на основе доступных ресурсов.
- Сбора информации: Факты могут быть использованы для сбора информации о хосте, которая затем может быть передана другим системам или использована для отчетности и мониторинга.
- Управления настройками и конфигурацией: Факты могут использоваться для настройки параметров и конфигураций на хосте в зависимости от его характеристик.
Примеры фактов в Ansible включают информацию о версии операционной системы, IP-адресах, физических и логических ядрах CPU, объемах дисков, установленных пакетах, переменных окружения и многом другом.
Факты Ansible доступны в переменной ansible_facts:
ansible_facts['ansible_distribution']: Информация о дистрибутиве операционной системы, например, "Ubuntu" или "CentOS".ansible_facts['ansible_distribution_version']: Версия дистрибутива операционной системы.ansible_facts['ansible_architecture']: Архитектура хоста, например, "x86_64".ansible_facts['ansible_os_family']: Семейство операционных систем, к которому принадлежит хост (например, "Debian" или "RedHat").ansible_facts['ansible_kernel']: Версия ядра операционной системы.ansible_facts['ansible_hostname']: Имя хоста.ansible_facts['ansible_fqdn']: Полное доменное имя (Fully Qualified Domain Name) хоста.ansible_facts['ansible_default_ipv4']: Информация о первом IPv4-интерфейсе хоста, включая IP-адрес, маску подсети и другие атрибуты.ansible_facts['ansible_default_ipv6']: Аналогичная информация для IPv6-интерфейса.ansible_facts['ansible_processor_vcpus']: Количество виртуальных процессоров (vCPUs) на хосте.ansible_facts['ansible_memtotal_mb']: Общее количество оперативной памяти (в мегабайтах) на хосте.ansible_facts['ansible_swaptotal_mb']: Общий объем подкачки (в мегабайтах) на хосте.ansible_facts['ansible_userspace_arch']: Архитектура пространства пользователя (например, "x86_64" или "i686").ansible_facts['ansible_date_time']: Текущее дата и время на хосте.ansible_facts['ansible_interfaces']: Список сетевых интерфейсов на хосте и их характеристики.ansible_facts['ansible_users']: Информация о пользователях на хосте.
В следующем примере мы используем модуль debug для вывода значения факта ansible_distribution. Важно использовать одинарные кавычки внутри скобок для обращения к факту.
Можно заменить 'ansible_distribution' на имя другого факта, к которому вы хотите обратиться, и затем использовать это значение в вашем плейбуке для принятия решений и настройки задач в зависимости от значения факта.
---
- name: Пример обращения к факту
hosts: my_host
tasks:
- name: Вывести значение факта ansible_distribution
debug:
var: ansible_facts['ansible_distribution']
When - условный оператор
В Ansible для применения условных операторов можно использовать модуль when, который позволяет выполнять задачи в зависимости от значений переменных, результатов предыдущих задач и других условий.
- name: Проверка значения переменной
debug:
msg: "Переменная value равна 10"
when: value == 10
- name: Проверка наличия файла
stat:
path: /path/to/file
register: file_info
# Проверка, что файл существует
when: file_info.stat.exists
- name: Проверка условий
debug:
msg: "Значение переменной равно 10 и файл существует"
when: (value == 10) and (file_info.stat.exists)
- name: Проверка условий с использованием фильтра length
debug:
msg: "Список не пустой"
when: my_list | length > 0
- name: Получение списка файлов
find:
paths: /path/to/directory
register: files_list
- name: Проверка наличия файлов
debug:
msg: "Найдены файлы в директории"
when: files_list.files | length > 0
Errors
Методы обработки ошибок в Ansible.
- name: Пример обработки ошибок
block:
- name: Задача 1
command: /path/to/failing/command
rescue:
- name: Обработка ошибок
debug:
msg: "Произошла ошибка при выполнении задачи"
always:
- name: Завершающее действие
debug:
msg: "Выполнение завершено"
- name: Пример генерации ошибки
command: /path/to/failing/command
register: result
failed_when: result.rc != 0
ignore_errors: true
- name: Обработка ошибок
fail:
msg: "Произошла ошибка при выполнении задачи"
when: result is failed
- name: Пример игнорирования ошибок
command: /path/to/failing/command
ignore_errors: true
- name: Пример использования модуля assert
hosts: localhost
tasks:
- name: Проверка значения переменной
assert:
that:
- my_variable == "expected_value"
fail_msg: "my_variable не соответствует ожидаемому значению"
success_msg: "my_variable соответствует ожидаемому значению"
vars:
my_variable: "unexpected_value"
# Модуль assert используется для проверки того, что переменная my_variable равна ожидаемому значению "expected_value".
# Если условие не выполнено (то есть my_variable не равно "expected_value"),
# будет сгенерирована ошибка с сообщением "my_variable не соответствует ожидаемому значению".
# Если условие выполнено (то есть my_variable равно "expected_value"),
# будет выведено сообщение "my_variable соответствует ожидаемому значению".