С нуля до Junior DevOps в 2026 году. Часть 7.1 Ansible: автоматизация настройки серверов

от автора

В предыдущих статьях мы познакомились с 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

Назначение

ansible.builtin.apt

управление пакетами Debian/Ubuntu

ansible.builtin.dnf

управление пакетами систем семейства RHEL/Fedora

ansible.builtin.package

абстракция над пакетным менеджером

ansible.builtin.service

управление службами

ansible.builtin.copy

копирование файлов

ansible.builtin.file

управление файлами и каталогами

ansible.builtin.template

создание файлов из Jinja2-шаблонов

ansible.builtin.user

управление пользователями

ansible.builtin.git

работа с Git-репозиториями

community.docker.docker_container

управление 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 будет делать четыре вещи:

  1. устанавливать Nginx;

  2. создавать конфигурацию из Jinja2-шаблона;

  3. перезапускать Nginx при изменении конфигурации;

  4. гарантировать, что сервис запущен и включён в автозагрузку.


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 и отмечает, в какой версии появились новые возможности.

Ansible Documentation


2. Ansible Getting Started

Если официальная документация кажется слишком большой, начать лучше с отдельного Quick Start: установка Ansible → создание проекта → Inventory → первый Playbook.

Start automating with Ansible


3. LabEx

LabEx предлагает интерактивные лабораторные задания по Ansible, где можно изучать инструмент непосредственно через терминал браузера. Это удобно для тех, кто хочет не просто читать про Inventory, Playbook, Modules и Roles, а сразу выполнять команды и проверять результат.

LabEx


4. Ansible for DevOps — Jeff Geerling

Один из наиболее полезных ресурсов именно для DevOps-практики. Книга начинается с базовых понятий, а затем переходит к Playbook, развёртыванию приложений, Docker и работе с инфраструктурой. Автор регулярно обновляет электронную версию; исходный текст книги также доступен открыто.

Ansible for DevOps


5. Ansible Galaxy

Ansible Galaxy — User Guide — официальный каталог, где можно находить, устанавливать и публиковать Ansible Roles и Collections. В документации есть поиск ролей и коллекций, установка конкретных версий, requirements.yml и управление зависимостями.

Ansible Galaxy

Отдельно стоит посмотреть Ansible Galaxy Developer Guide, если читатель захочет создавать и публиковать собственные Roles или Collections.


6. ansible-lint

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

Ansible Lint


7. Molecule

Molecule — фреймворк для тестирования Ansible Roles, Playbooks и Collections. Он позволяет создавать тестовые сценарии и проверять автоматизацию на контейнерах, виртуальных машинах и других системах, доступных Ansible.

Molecule


Заключение

В следующей статье мы покажем, как Terraform и Ansible работают вместе, настроим Dynamic Inventory, автоматизируем развёртывание Docker и Docker Compose, а также интегрируем Ansible с GitHub Actions и другими CI/CD-системами, чтобы построить полноценный процесс автоматизации инфраструктуры.

ссылка на оригинал статьи https://habr.com/ru/articles/1068460/