В предыдущих статьях мы познакомились с Terraform и научились описывать инфраструктуру как код. Terraform может создать виртуальную машину, сеть, диски и другие ресурсы в облаке. Но создание сервера — только начало.
После запуска виртуальной машины на ней ещё нет необходимого приложения, пользователей, конфигурационных файлов и настроенных служб. Всё это можно установить и настроить вручную, подключившись к серверу по SSH. Проблема появляется, когда серверов становится больше одного.
Одним из наиболее распространённых инструментов для этой задачи является Ansible.
В этой статье разберём Ansible от базовых принципов до его использования в современной инфраструктуре. Начнём с архитектуры Control Node и Managed Nodes, разберём подключение по SSH, Inventory, YAML-синтаксис, Modules, Playbooks и Ad-hoc-команды. Отдельно рассмотрим один из ключевых принципов Ansible — идемпотентность.
Затем перейдём к организации более крупных проектов: Roles, Variables, Jinja2, Handlers, Facts, условия when, циклы, include_tasks и import_tasks. Разберём Ansible Vault для работы с секретами и Ansible Galaxy для использования готовых ролей и коллекций.
Что понадобится
Для выполнения примеров потребуется:
-
компьютер с Linux, macOS или Windows (через WSL);
-
установленный Ansible;
-
одна или несколько виртуальных машин с Linux;
-
доступ по SSH;
-
базовые знания командной строки Linux.
Для экспериментов подойдут виртуальные машины в VirtualBox, Multipass, Vagrant, Docker (через SSH), Minikube или сайты по типу labex.io
Что такое Ansible
Ansible — инструмент автоматизации и управления конфигурацией серверов. С его помощью можно автоматизировать:
-
установку программ;
-
создание пользователей;
-
настройку SSH;
-
изменение конфигурационных файлов;
-
управление службами;
-
обновление пакетов;
-
развёртывание приложений;
-
настройку серверов и сетевого оборудования.
Вместо того чтобы вручную выполнять десятки команд на каждом сервере, необходимые действия можно описать в Playbook. Например:
ansible-playbook nginx.yml
Одна команда может настроить сразу десятки серверов. Главное преимущество такого подхода — воспроизводимость. Если завтра понадобится новый сервер, не нужно вспоминать все команды. Достаточно применить тот же Playbook.
Ansible и Configuration as Code
Ansible позволяет описывать конфигурацию инфраструктуры в виде кода. В частности, вместо:
sudo apt install nginxsudo systemctl enable nginxsudo systemctl start nginx
можно описать желаемое состояние:
- name: Install Nginx ansible.builtin.apt: name: nginx state: present- name: Start Nginx ansible.builtin.service: name: nginx state: started enabled: true
Теперь эта конфигурация может храниться в Git, проходить Code Review и использоваться повторно. Это превращает настройку серверов из набора ручных действий в управляемый процесс.
Архитектура Ansible
Ansible использует относительно простую архитектуру. В её основе находятся два типа узлов:
-
Control Node — машина, с которой запускается Ansible;
-
Managed Nodes — серверы, которыми управляет Ansible.
Для Linux-подключения обычно используется SSH. Упрощённо схема выглядит так:
Control Node │ │ SSH ┌───────────┼───────────┐ Managed Managed Managed Node 1 Node 2 Node 3
Теперь рассмотрим эти компоненты подробнее.
Control Node
Control Node — компьютер или сервер, на котором установлен Ansible и с которого запускаются команды и Playbook. Это может быть:
-
компьютер DevOps-инженера;
-
виртуальная машина;
-
сервер автоматизации;
-
GitHub Actions Runner;
-
GitLab Runner;
-
Jenkins;
-
другой CI/CD-сервер.
Важно понимать, что Ansible не обязательно должен работать на отдельном физическом сервере. Control Node может находиться на обычном Linux-компьютере, виртуальной машине или в CI/CD-окружении.
Managed Nodes
Managed Nodes — серверы, которыми управляет Ansible. К примеру:
web-01web-02db-01monitoring-01
На них Ansible выполняет необходимые операции. Для Linux-серверов обычно требуется:
-
SSH-доступ;
-
Python для большинства стандартных модулей.
При этом сам Ansible на управляемый сервер устанавливать не требуется.
Почему Ansible называют Agentless
Одна из наиболее известных особенностей Ansible — agentless architecture, то есть архитектура без постоянно работающего агента на управляемом сервере. Некоторые системы управления конфигурацией используют специальное программное обеспечение, которое необходимо установить на каждый сервер. Упрощённо это выглядит так:
Control Server▼Agent▼Server
Ansible использует другой подход:
Control Node││ SSH▼Managed Node
На сервере не требуется устанавливать постоянно работающий Ansible Agent. Это упрощает первоначальную настройку и обслуживание инфраструктуры. Однако термин agentless не означает, что на сервере вообще не выполняется никакой дополнительный код. Во время выполнения задач Ansible передаёт необходимые модули на удалённый узел и запускает их там.
SSH — основной транспорт
При работе с Linux Ansible обычно использует SSH для подключения к серверам. Упрощённо процесс можно представить следующим образом:
web-01web-02db-01monitoring-01
К примеру, Ansible получает задачу:
- name: Install Nginx ansible.builtin.apt: name: nginx state: present
Подключается к серверу, выполняет необходимый модуль и получает результат. Для Windows-серверов используется другой механизм подключения — в частности, WinRM.
Inventory — список серверов
Ansible должен знать, какими серверами ему управлять. Для этого используется Inventory. Самый простой вариант:
192.168.1.10192.168.1.11192.168.1.12
Но в реальных проектах серверы обычно группируют по назначению. Например:
[web]192.168.1.10192.168.1.11[database]192.168.1.20[monitoring]192.168.1.30
Теперь можно выполнить команду только на веб-серверах:
ansible web -m ping -i inventory.ini
Или на всех серверах:
ansible all -m ping -i inventory.ini
YAML Inventory
Inventory можно описывать не только в формате INI, но и в YAML. Для примера:
all: children: web: hosts: web01: ansible_host: 192.168.1.10 web02: ansible_host: 192.168.1.11 database: hosts: db01: ansible_host: 192.168.1.20
Modules
Module — это готовая функциональность Ansible для выполнения определённого действия. Вместо того чтобы самостоятельно писать shell-скрипты, можно использовать стандартные модули.
|
Module |
Назначение |
|---|---|
|
|
управление пакетами Debian/Ubuntu |
|
|
управление пакетами систем семейства RHEL/Fedora |
|
|
абстракция над пакетным менеджером |
|
|
управление службами |
|
|
копирование файлов |
|
|
управление файлами и каталогами |
|
|
создание файлов из Jinja2-шаблонов |
|
|
управление пользователями |
|
|
работа с Git-репозиториями |
|
|
управление Docker-контейнерами |
В современных Playbook рекомендуется указывать полное имя модуля с namespace, ansible.builtin.apt. Для модулей, которые относятся к сторонним коллекциям, namespace будет другим — к примеру community.docker.
Например, установить Nginx:
- name: Install Nginx ansible.builtin.apt: name: nginx state: present
Создать пользователя:
- name: Create deploy user ansible.builtin.user: name: deploy state: present
Запустить службу:
- name: Start Nginx ansible.builtin.service: name: nginx state: started
В современных Playbook рекомендуется использовать полные имена модулей с пространством имён ansible.builtin.
Playbook — сценарий автоматизации
Playbook — YAML-файл, содержащий описание автоматизации. Он состоит из Play, а внутри Play находятся Tasks. Упрощённая структура:
Playbook│├── Play │ ││ ├── Task│ │ └── Module│ ├── Task│ │ └── Module
Play определяет, на каких хостах выполняются задачи, а Task описывает конкретную операцию. Для выполнения операции Task обычно вызывает определённый Module. Для примера, создадим nginx.yml:
---- name: Configure web servers hosts: web become: true tasks: - name: Install Nginx ansible.builtin.apt: name: nginx state: present - name: Start Nginx ansible.builtin.service: name: nginx state: started enabled: true
Запускаем:
ansible-playbook -i inventory.ini nginx.yml
Ansible найдёт группу web, подключится к серверам и последовательно выполнит задачи.
Facts
При запуске Play Ansible по умолчанию собирает сведения о Managed Node. Эти данные называются Facts. Ansible может получить:
-
имя хоста;
-
операционную систему и её версию;
-
архитектуру процессора;
-
объём памяти;
-
количество процессорных ядер;
-
сетевые интерфейсы и IP-адреса.
Полученные данные доступны в Playbook как переменные:
{{ ansible_hostname }}{{ ansible_distribution }}{{ ansible_memtotal_mb }}
Facts позволяют писать Playbook, которые адаптируются к характеристикам конкретного сервера. Если сбор Facts не нужен, его можно отключить:
gather_facts: false
Ad-hoc команды
Не всегда нужно создавать отдельный Playbook. Если необходимо быстро выполнить одну операцию, можно использовать Ad-hoc command. Для примера:
ansible all -m ping -i inventory.ini
Команда проверит доступность всех серверов. Получить информацию о времени работы:
ansible web -m ansible.builtin.command -a "uptime" -i inventory.ini
Получить подробную информацию о Managed Node можно с помощью модуля ansible.builtin.setup, который собирает Ansible Facts.
ansible all -m ansible.builtin.setup -i inventory.ini
Ad-hoc команды особенно полезны для:
-
быстрой диагностики;
-
проверки подключения;
-
разовых операций;
-
экспериментов во время обучения.
Но для повторяемой настройки инфраструктуры лучше использовать Playbook.
Идемпотентность
При работе с Ansible важно понимать понятие идемпотентности. Идея заключается в том, что повторное выполнение одной и той же задачи не должно приводить к ненужным изменениям. Например:
- name: Install Nginx ansible.builtin.apt: name: nginx state: present
Если Nginx уже установлен, Ansible не будет устанавливать его заново. То же самое касается многих других модулей. Это одно из ключевых отличий декларативного подхода от простого набора shell-команд.
Ansible и Terraform
После знакомства с Ansible закономерно возникает вопрос:
Если Terraform уже умеет автоматизировать инфраструктуру, зачем нужен ещё один инструмент?
Ответ заключается в том, что Terraform и Ansible решают разные задачи. Terraform в первую очередь отвечает за создание и изменение инфраструктурных ресурсов. Ansible — за настройку уже существующих систем.
Например, Terraform может создать:
Virtual MachineNetwork DiskLoad BalancerDatabaseKubernetesCluster
После этого Ansible может выполнить:
Install Docker▼Create Users▼Configure SSH▼Install Nginx▼Copy Configuration▼Deploy Application
Roles, Templates, Variables и Ansible Galaxy
Представьте, что вам необходимо автоматически настроить десять серверов. На каждом нужно создать пользователей, установить Docker, настроить Nginx, скопировать конфигурационные файлы, добавить SSH-ключи и запустить необходимые службы. Все эти действия можно описать в одном Playbook, но уже через несколько недель такой файл превратится в сотни строк YAML-кода, который сложно читать, сопровождать и повторно использовать.
Именно поэтому в крупных проектах Ansible строится вокруг ролей (Roles). Роль объединяет связанные задачи, шаблоны, переменные и файлы в единую структуру, позволяя повторно использовать готовые компоненты. В этой статье мы познакомимся с Roles, шаблонами Jinja2, переменными, фактами, условиями и циклами, Ansible Vault.
Почему один большой Playbook — плохая идея?
На первых этапах обучения кажется удобным хранить все задачи в одном файле.
---- hosts: all become: true tasks: - ... - ...
Пока задач десять или двадцать, такой подход работает. Однако в реальных проектах Playbook может содержать сотни задач:
-
создание пользователей;
-
настройка SSH;
-
установка Docker;
-
установка Nginx;
-
настройка Firewall;
-
установка PostgreSQL;
-
настройка резервного копирования;
-
мониторинг;
-
логирование.
В результате появляется огромный файл, в котором сложно ориентироваться. Любое изменение становится рискованным, а повторное использование отдельных частей практически невозможно. Поэтому в Ansible появился механизм Roles — стандартный способ организации больших проектов.
Что такое Role?
Role — это самостоятельный модуль автоматизации, объединяющий задачи, переменные, шаблоны и другие ресурсы для выполнения одной конкретной функции. Например:
-
роль
nginxотвечает только за установку и настройку Nginx; -
роль
docker— за установку Docker; -
роль
users— за создание пользователей; -
роль
postgresql— за развёртывание базы данных.
Главная идея проста: одна роль — одна задача.
Структура роли
Каждая роль имеет стандартную структуру каталогов.
roles/└── nginx/ ├── tasks/ │ └── main.yml ├── handlers/ │ └── main.yml ├── defaults/ │ └── main.yml ├── vars/ │ └── main.yml ├── templates/ │ └── nginx.conf.j2 ├── files/ ├── meta/ ├── tests/ └── README.md
Такую структуру понимает любой разработчик Ansible, поэтому переход между проектами значительно упрощается.
tasks
Каталог tasks содержит основной сценарий выполнения роли. Именно здесь описываются действия:
-
установка пакетов;
-
запуск служб;
-
копирование файлов;
-
создание пользователей.
Например:
- name: Install Nginx ansible.builtin.apt: name: nginx state: present- name: Start service ansible.builtin.service: name: nginx state: started
handlers
Некоторые действия должны выполняться только после изменения конфигурации. Например, если шаблон конфигурационного файла изменился, необходимо перезапустить Nginx. Для этого используются обработчики (Handlers).
---- name: Restart nginx service: name: nginx state: restarted
Handler вызывается через notify и запускается только при необходимости.
defaults
Каталог defaults содержит значения переменных по умолчанию. Например:
nginx_port: 80worker_processes: auto
Эти значения легко переопределить в Inventory или Playbook, поэтому именно здесь рекомендуется хранить параметры, которые могут отличаться в разных окружениях.
vars
Каталог vars также предназначен для хранения переменных, но с более высоким приоритетом. Обычно сюда помещают значения, которые редко изменяются. Например:
nginx_package: nginx
На практике рекомендуется использовать defaults для настраиваемых параметров, а vars — только тогда, когда действительно необходимо зафиксировать значение.
templates
Практически любая служба использует конфигурационные файлы. Если просто копировать их модулем copy, придётся хранить отдельную версию для каждого сервера. Вместо этого применяется модуль template, который использует шаблоны Jinja2. Например:
server { listen {{ nginx_port }}; server_name {{ server_name }};}
Во время выполнения Ansible заменит переменные их фактическими значениями.
files
Если файл не содержит переменных, проще использовать каталог files. Например:
-
статические HTML-страницы;
-
сертификаты;
-
изображения;
-
архивы;
-
скрипты.
Модуль copy просто перенесёт эти файлы на удалённый сервер.
Jinja2
Jinja2 — это шаблонизатор, позволяющий динамически формировать конфигурационные файлы. Кроме переменных он поддерживает:
-
условия;
-
циклы;
-
фильтры;
-
математические операции;
-
преобразование строк.
Именно благодаря Jinja2 одна конфигурация может использоваться для десятков серверов.
Variables
Переменные позволяют избежать жёстко заданных значений.
http_port: 80
или
docker_version: 27.1
Использование переменных делает Playbook универсальным и легко настраиваемым.
Conditionals (when)
Иногда задача должна выполняться только при определённых условиях. К примеру:
- name: Install Nginx on Debian-based systems ansible.builtin.apt: name: nginx state: present when: ansible_os_family == "Debian"
Условие when не требует конструкции {{ }}: Ansible вычисляет выражение непосредственно как условие. Если сервер работает под Ubuntu или Debian, задача будет выполнена. Для других систем её можно заменить альтернативной.
Loops
Часто требуется выполнить одинаковую операцию несколько раз. В частности, создать нескольких пользователей.
- name: Create users user: name: "{{ item }}" loop: - alice - bob - deploy
Вместо трёх одинаковых задач используется один цикл.
Include и Import
Большие Playbook удобно разбивать на части. Для этого используются:
-
import_tasks— статически подключает файл с задачами; -
include_tasks— динамически подключает файл во время выполнения.
Разница особенно важна при использовании условий, циклов и переменных. Такой подход делает проект значительно более структурированным.
Ansible Vault
Конфигурация часто содержит секретные данные:
-
пароли;
-
API-ключи;
-
SSH-ключи;
-
токены;
-
сертификаты.
Хранить их в открытом виде нельзя. Для защиты используется Ansible Vault. Шифрование файла:
ansible-vault encrypt secrets.yml
Редактирование:
ansible-vault edit secrets.yml
Запуск Playbook:
ansible-playbook site.yml --ask-vault-pass
Ansible Vault шифрует содержимое файлов с секретами, поэтому зашифрованные данные можно хранить в Git без публикации самих секретов в открытом виде. При этом пароль или другой механизм, используемый для расшифровки Vault, необходимо хранить отдельно и защищать от утечки. В CI/CD вместо передачи пароля непосредственно в Playbook обычно используют защищённые переменные и секреты CI-системы.
Ansible Galaxy
Необязательно писать каждую роль и каждый компонент самостоятельно. Ansible Galaxy предоставляет каталог контента Ansible, включая готовые роли и коллекции.
Коллекции могут содержать:
-
модули;
-
плагины;
-
роли;
-
другие компоненты Ansible.
К примеру, роль можно установить командой:
ansible-galaxy role install geerlingguy.docker
После этого роль можно сразу использовать в проекте. А коллекции устанавливаются через:
ansible-galaxy collection install <collection>
Перед использованием стороннего контента в production стоит проверить его источник, поддержку, зависимости и историю обновлений.
Практический проект
Представим, что необходимо автоматически подготовить новый веб-сервер. Структура проекта:
1. Структура проекта
ansible-project/├── inventory/│ └── hosts.yml├── playbook.yml└── roles/ └── nginx/ ├── defaults/ │ └── main.yml ├── handlers/ │ └── main.yml ├── tasks/ │ └── main.yml └── templates/ └── nginx.conf.j2
Здесь Role будет делать четыре вещи:
-
устанавливать Nginx;
-
создавать конфигурацию из Jinja2-шаблона;
-
перезапускать Nginx при изменении конфигурации;
-
гарантировать, что сервис запущен и включён в автозагрузку.
2. Переменные Role
roles/nginx/defaults/main.yml:
nginx_package: nginxnginx_service: nginxnginx_port: 80nginx_server_name: "_"
Здесь находятся значения по умолчанию. При необходимости их можно переопределить из Inventory или Playbook.
3. Tasks
roles/nginx/tasks/main.yml:
---- name: Install Nginx ansible.builtin.apt: name: "{{ nginx_package }}" state: present update_cache: true- name: Deploy Nginx configuration ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/sites-available/default owner: root group: root mode: "0644" notify: Restart Nginx- name: Ensure Nginx is enabled and started ansible.builtin.service: name: "{{ nginx_service }}" state: started enabled: true
Здесь используется уже знакомый нам модуль template. Он берёт файл из каталога templates/, подставляет значения переменных и создаёт итоговый конфигурационный файл на Managed Node.
4. Handler
roles/nginx/handlers/main.yml:
---- name: Restart Nginx ansible.builtin.service: name: "{{ nginx_service }}" state: restarted
Handler вызывается только тогда, когда соответствующая Task сообщает об изменении:
notify: Restart Nginx
Например, если конфигурационный файл уже находится в нужном состоянии, template не изменит его и Nginx перезапускаться не будет. Это один из практических примеров идемпотентности Ansible.
5. Jinja2 Template
roles/nginx/templates/nginx.conf.j2:
server { listen {{ nginx_port }}; server_name {{ nginx_server_name }}; location / { return 200 "Hello from Ansible!\n"; add_header Content-Type text/plain; }}
Здесь:
{{ nginx_port }}{{ nginx_server_name }}
— переменные Jinja2, значения которых Ansible возьмёт из defaults/main.yml или из места, где эти переменные были переопределены.
6. Playbook
Теперь Role можно подключить из обычного Playbook:
---- name: Configure web servers hosts: web become: true roles: - nginx
Playbook при этом становится очень коротким. Вся логика настройки Nginx находится внутри Role.
7. Переопределение переменных
Например, для другого сервера можно изменить порт:
---- name: Configure web servers hosts: web become: true vars: nginx_port: 8080 nginx_server_name: example.com roles: - nginx---- name: Configure web servers hosts: web become: true vars: nginx_port: 8080 nginx_server_name: example.com roles: - nginx
Теперь та же Role установит и настроит Nginx, но будет использовать:
port = 8080server_name = example.com
Это хорошо показывает главное преимущество Roles: один набор автоматизации можно повторно использовать с разными параметрами.
Где изучать Ansible
Для дальнейшего изучения лучше всего использовать несколько источников:
1. Официальная документация Ansible
Главный источник для изучения Ansible. Здесь есть Getting Started, документация по Playbook, Inventory, Modules, Roles, Variables и другим компонентам. Документация поддерживает актуальные версии Ansible и отмечает, в какой версии появились новые возможности.
2. Ansible Getting Started
Если официальная документация кажется слишком большой, начать лучше с отдельного Quick Start: установка Ansible → создание проекта → Inventory → первый Playbook.
3. LabEx
LabEx предлагает интерактивные лабораторные задания по Ansible, где можно изучать инструмент непосредственно через терминал браузера. Это удобно для тех, кто хочет не просто читать про Inventory, Playbook, Modules и Roles, а сразу выполнять команды и проверять результат.
4. Ansible for DevOps — Jeff Geerling
Один из наиболее полезных ресурсов именно для DevOps-практики. Книга начинается с базовых понятий, а затем переходит к Playbook, развёртыванию приложений, Docker и работе с инфраструктурой. Автор регулярно обновляет электронную версию; исходный текст книги также доступен открыто.
5. Ansible Galaxy
Ansible Galaxy — User Guide — официальный каталог, где можно находить, устанавливать и публиковать Ansible Roles и Collections. В документации есть поиск ролей и коллекций, установка конкретных версий, requirements.yml и управление зависимостями.
Отдельно стоит посмотреть Ansible Galaxy Developer Guide, если читатель захочет создавать и публиковать собственные Roles или Collections.
6. ansible-lint
Ansible Lint — статический анализатор для Ansible Playbooks, Roles и Collections. Он помогает находить распространённые ошибки, соблюдать рекомендуемые практики и поддерживать единый стиль кода.
7. Molecule
Molecule — фреймворк для тестирования Ansible Roles, Playbooks и Collections. Он позволяет создавать тестовые сценарии и проверять автоматизацию на контейнерах, виртуальных машинах и других системах, доступных Ansible.
Заключение
В следующей статье мы покажем, как Terraform и Ansible работают вместе, настроим Dynamic Inventory, автоматизируем развёртывание Docker и Docker Compose, а также интегрируем Ansible с GitHub Actions и другими CI/CD-системами, чтобы построить полноценный процесс автоматизации инфраструктуры.
ссылка на оригинал статьи https://habr.com/ru/articles/1068460/