Перейти к основному содержимому

7.04. Ansible

Разработчику Архитектору Инженеру

Ansible

Что такое Ansible

Ansible — это инструмент автоматизации, предназначенный для описания, развертывания и управления состоянием вычислительной инфраструктуры с помощью кода. Он позволяет систематизировать процессы настройки серверов, развёртывания приложений, обновления программного обеспечения и оркестрации сложных взаимодействий между компонентами распределённых систем. Основная цель Ansible — превратить рутинные операции администрирования в воспроизводимые, декларативные и версионируемые процедуры.

Ansible работает без установки агентов на управляемые узлы. Вместо этого он использует стандартные протоколы удалённого доступа, такие как SSH для Unix-подобных систем или WinRM для Windows. Это делает его легковесным, безопасным и совместимым с широким спектром окружений — от локальных машин до облачных платформ, включая Amazon Web Services, Microsoft Azure и Google Cloud Platform.


Система автоматизации конфигурации, развертывания и управления инфраструктурой

Современные ИТ-инфраструктуры представляют собой сложные экосистемы, состоящие из десятков, сотен или даже тысяч серверов, сетевых устройств, баз данных, микросервисов и внешних зависимостей. Ручное управление такой средой становится не только трудоёмким, но и подверженным ошибкам. Даже незначительное отклонение в конфигурации одного узла может привести к сбоям в работе всего приложения.

Система автоматизации решает эту проблему, предоставляя единый язык описания желаемого состояния инфраструктуры. Этот подход известен как Infrastructure as Code (IaC) — инфраструктура как код. Вместо того чтобы выполнять команды вручную на каждом сервере, администратор описывает требуемую конфигурацию в виде текстовых файлов. Эти файлы можно хранить в системах контроля версий, проверять на соответствие стандартам, тестировать и применять многократно в разных окружениях — от разработки до продакшена.

Ansible реализует IaC через декларативный стиль: пользователь указывает, что должно быть достигнуто, а не как это сделать шаг за шагом. Например, вместо написания скрипта, который проверяет наличие пакета, скачивает его, устанавливает зависимости и запускает службу, достаточно объявить: «Пакет nginx должен быть установлен, и служба nginx должна быть запущена и включена при загрузке». Ansible сам определит текущее состояние системы и выполнит минимальный набор действий для достижения цели.


Цель и архитектура Ansible

Основная цель Ansible — обеспечить простоту, надёжность и масштабируемость в управлении инфраструктурой. Он ориентирован на читаемость, минимизацию зависимостей и быстрое внедрение. Архитектура Ansible построена вокруг нескольких ключевых компонентов:

  • Контрольный узел (Control Node) — это машина, на которой запускается Ansible. Именно с неё отправляются команды и плейбуки к управляемым хостам. Контрольный узел требует установленного Python и самого Ansible, но не нуждается в базе данных, демоне или дополнительных сервисах.

  • Управляемые узлы (Managed Nodes) — это целевые серверы, на которых выполняются задачи. На них не требуется устанавливать специальное ПО, кроме интерпретатора Python (для большинства модулей) и открытого SSH-порта.

  • Модули — это исполняемые единицы, которые выполняют конкретные действия: установка пакетов, управление службами, копирование файлов, работа с облачными API и многое другое. Ansible содержит тысячи встроенных модулей и поддерживает создание собственных.

  • Плейбуки (Playbooks) — это основной способ описания автоматизированных процедур. Они написаны на языке YAML и структурированы как последовательности plays, каждый из которых применяется к определённой группе хостов.

  • Инвентарь (Inventory) — это описание целевых хостов: их IP-адреса, доменные имена, принадлежность к группам, переменные и параметры подключения.

Архитектура Ansible является push-ориентированной: контрольный узел инициирует соединение с управляемыми узлами, передаёт необходимые данные и модули, выполняет задачи и завершает сессию. Такой подход упрощает сетевую настройку и повышает безопасность, так как управляемые узлы не должны инициировать исходящие соединения.


Инвентарь

Инвентарь — это фундамент, на котором строится вся автоматизация в Ansible. Он определяет, с какими машинами будет работать система. Инвентарь может быть представлен в виде простого текстового файла, динамического скрипта или комбинации источников.

Статический инвентарь записывается в формате INI или YAML. Пример в INI-стиле:

[web_servers]
192.168.1.10
192.168.1.11

[db_servers]
192.168.1.20

[production:children]
web_servers
db_servers

В этом примере определены две группы хостов: web_servers и db_servers, а также родительская группа production, которая включает обе. Это позволяет применять одни и те же задачи ко всем серверам в production или только к веб-серверам.

Каждому хосту можно назначить переменные прямо в инвентаре:

[web_servers]
web1 ansible_host=192.168.1.10 ansible_user=deploy
web2 ansible_host=192.168.1.11 ansible_user=deploy

Динамический инвентарь генерируется в реальном времени, например, путём запроса к API облачного провайдера. Ansible предоставляет официальные скрипты для AWS, Azure, GCP и других платформ. Это особенно полезно в средах с постоянно меняющейся инфраструктурой, где серверы создаются и уничтожаются автоматически.

Инвентарь может быть задан явно через флаг -i при запуске команды, либо использоваться по умолчанию из файла /etc/ansible/hosts.


Плейбуки

Плейбук — это сердце Ansible. Это файл в формате YAML, который описывает последовательность действий, применяемых к определённым хостам. Плейбук состоит из одного или нескольких plays. Каждый play определяет:

  • Целевые хосты (через параметр hosts);
  • Переменные, доступные в рамках play;
  • Последовательность задач (tasks);
  • Обработчики (handlers);
  • Роли (roles), если используются.

Пример простого плейбука:

---
- name: Настройка веб-сервера
hosts: web_servers
become: yes
tasks:
- name: Установка Nginx
apt:
name: nginx
state: present
- name: Запуск службы Nginx
service:
name: nginx
state: started
enabled: yes

Этот плейбук применяется ко всем хостам из группы web_servers. Он повышает привилегии до root (become: yes), устанавливает пакет nginx и гарантирует, что служба запущена и включена при старте системы.

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


Шаблонизация

Шаблонизация позволяет генерировать конфигурационные файлы динамически, подставляя в них значения переменных, фактов о системе или результаты выполнения других задач. Ansible использует шаблонизатор Jinja2, популярный в экосистеме Python.

Файлы шаблонов имеют расширение .j2 и размещаются в каталоге templates внутри проекта или роли. Например, шаблон nginx.conf.j2 может содержать:

server {
listen {{ nginx_port }};
server_name {{ server_name }};

location / {
root {{ document_root }};
index index.html;
}
}

В плейбуке этот шаблон копируется на целевой сервер с помощью модуля template:

- name: Развертывание конфигурации Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/default
notify: Перезапуск Nginx

Переменные nginx_port, server_name и document_root могут быть определены в инвентаре, в самом плейбуке, в групповых переменных или получены из фактов (например, ansible_default_ipv4.address). Такой подход обеспечивает гибкость: один и тот же шаблон работает в разных окружениях — dev, staging, production — без изменения кода.


Ansible Vault

Чувствительные данные, такие как пароли, токены API, закрытые ключи, не должны храниться в открытом виде в репозиториях. Ansible Vault решает эту проблему, позволяя шифровать отдельные файлы или переменные внутри YAML-документов.

Команда ansible-vault create secret.yml создаёт новый зашифрованный файл. Команда ansible-vault encrypt_string 'my_secret' генерирует зашифрованную строку, которую можно вставить прямо в плейбук:

vars:
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439653236336462626566653063336164636135393732353639623561303231306366376135306439

При запуске плейбука с зашифрованными данными требуется указать пароль: либо вручную через --ask-vault-pass, либо через файл с помощью --vault-password-file. Ansible автоматически расшифровывает данные перед выполнением задач.

Vault обеспечивает соответствие требованиям безопасности и позволяет хранить всю конфигурацию в одном месте, не нарушая принципов Infrastructure as Code.


AWX и Red Hat Ansible Automation Platform

AWX — это свободный, открытый веб-интерфейс и REST API для управления Ansible. Он предоставляет графический дашборд для запуска плейбуков, просмотра истории выполнений, управления инвентарями, учётными данными и расписаниями. AWX особенно полезен в командах, где несколько человек участвуют в эксплуатации инфраструктуры.

AWX включает:

  • Проекты — привязка к Git-репозиториям с плейбуками;
  • Инвентари — управление статическими и динамическими источниками;
  • Шаблоны заданий — предопределённые конфигурации запуска;
  • Учётные данные — безопасное хранение SSH-ключей, паролей, токенов;
  • Расписания — автоматический запуск плейбуков по времени;
  • Аудит и логирование — полная история всех операций.

Red Hat Ansible Automation Platform — это коммерческая версия, основанная на AWX, с поддержкой, расширенными функциями безопасности, интеграцией с корпоративными системами и возможностью масштабирования в крупных организациях.

Оба решения превращают Ansible из командной утилиты в полноценную платформу автоматизации, пригодную для enterprise-сред.


Роли

Роли — это механизм структурирования и повторного использования кода в Ansible. Когда проекты растут, плейбуки становятся громоздкими и трудно поддерживаемыми. Роли позволяют разбить логику на модульные, самодостаточные компоненты, каждый из которых отвечает за конкретную функцию: установку веб-сервера, настройку базы данных, развёртывание приложения и так далее.

Стандартная структура роли выглядит так:

roles/
└── webserver/
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
│ └── nginx.conf.j2
├── files/
├── vars/
│ └── main.yml
├── defaults/
│ └── main.yml
└── meta/
└── main.yml
  • tasks/main.yml — основной список задач, выполняемых ролью.
  • handlers/main.yml — обработчики, вызываемые через notify.
  • templates/ — шаблоны конфигурационных файлов.
  • files/ — статические файлы, копируемые на целевые узлы.
  • vars/main.yml — переменные с высоким приоритетом, специфичные для роли.
  • defaults/main.yml — значения по умолчанию, которые можно переопределить.
  • meta/main.yml — метаданные: зависимости от других ролей, поддерживаемые платформы.

Пример использования роли в плейбуке:

---
- name: Развертывание веб-приложения
hosts: webservers
roles:
- webserver
- common
- monitoring

Каждая роль применяется последовательно ко всем хостам из группы webservers. Это позволяет собирать сложные конфигурации из простых, тестируемых блоков. Роли можно публиковать в Ansible Galaxy — централизованном каталоге сообщества, где тысячи разработчиков делятся готовыми решениями для PostgreSQL, Docker, Kubernetes, Jenkins и многих других технологий.


Обработчики

Обработчики — это особый вид задач, которые выполняются только в ответ на явный сигнал. Они полезны для действий, которые должны происходить после изменения состояния системы, но не при каждом запуске плейбука. Например, перезапуск веб-сервера требуется только тогда, когда его конфигурационный файл был изменён.

Обработчик объявляется в секции handlers и вызывается из задачи с помощью директивы notify:

tasks:
- name: Обновление конфигурации Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Перезапуск Nginx

handlers:
- name: Перезапуск Nginx
service:
name: nginx
state: reloaded

Важно: имя в notify должно точно совпадать с именем обработчика. Ansible собирает все вызовы обработчиков за время выполнения плейбука и запускает их в конце каждого play, даже если обработчик был вызван несколько раз — он выполнится только один раз. Это предотвращает избыточные перезапуски служб и повышает эффективность.


Переменные и приоритеты

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

  1. Файлов group_vars/ и host_vars/ — автоматически загружаются при совпадении имени группы или хоста.
  2. Секции vars в плейбуке — локальные переменные для конкретного play.
  3. Файлов, подключённых через vars_files — удобно для вынесения конфигураций в отдельные документы.
  4. Ролей: defaults/ (низкий приоритет) и vars/ (высокий приоритет).
  5. Командной строки через флаг -e — самый высокий приоритет, используется для быстрого переопределения.

Пример:

# group_vars/webservers.yml
nginx_port: 8080
document_root: /var/www/html

# playbook.yml
- hosts: webservers
vars:
server_name: example.com
tasks:
- name: Развертывание шаблона
template:
src: site.conf.j2
dest: /etc/nginx/sites-available/default

В шаблоне site.conf.j2 можно использовать все три переменные: две из group_vars и одну из vars.

Ansible также автоматически собирает факты — информацию о системе: операционная система, IP-адреса, объём памяти, количество ядер и многое другое. Эти факты доступны как переменные (ansible_os_family, ansible_default_ipv4.address) и позволяют писать адаптивные плейбуки, работающие на разных платформах.


Факты и адаптивная автоматизация

Факты (facts) — это данные, собранные Ansible с управляемых узлов перед выполнением задач. Они позволяют принимать решения на основе реального состояния системы. Например:

- name: Установка пакетного менеджера
apt:
name: nginx
state: present
when: ansible_os_family == "Debian"

- name: Установка пакетного менеджера
yum:
name: nginx
state: present
when: ansible_os_family == "RedHat"

Этот подход обеспечивает кроссплатформенность без дублирования логики. Сбор фактов можно отключить (gather_facts: no), если они не нужны, чтобы ускорить выполнение.


Лучшие практики

  1. Идемпотентность — каждая задача должна быть безопасной для многократного запуска. Ansible гарантирует это через проверку текущего состояния перед изменением.
  2. Читаемость — используйте осмысленные имена задач, группируйте связанные действия, избегайте «магических» значений.
  3. Модульность — выносите повторяющуюся логику в роли, а не копируйте блоки кода.
  4. Безопасность — храните секреты в Vault, не коммитьте пароли в Git.
  5. Тестирование — используйте ansible-lint для проверки стиля, molecule для интеграционного тестирования ролей.
  6. Версионирование — весь код Ansible должен находиться под контролем версий, как и любой другой программный проект.

Пример: полный цикл автоматизации в AWS

Представим, что нужно развернуть масштабируемое веб-приложение в облаке AWS. Процесс может включать:

  1. Подготовка инфраструктуры — создание EC2-инстансов, VPC, security groups через модули amazon.aws.ec2, amazon.aws.ec2_vpc_net и другие.
  2. Настройка ОС — обновление пакетов, установка зависимостей, настройка времени и локали.
  3. Развёртывание приложения — копирование артефактов, настройка reverse proxy, запуск службы.
  4. Мониторинг и логирование — установка агентов CloudWatch или Prometheus.
  5. Очистка — удаление временных ресурсов после завершения.

Всё это можно описать в одном или нескольких плейбуках, используя динамический инвентарь для автоматического обнаружения новых инстансов. После первого запуска инфраструктура полностью воспроизводима: достаточно выполнить команду ansible-playbook deploy.yml, и система придет в заданное состояние.