Когда в очередной раз возникла задача — за два часа поднять десяток однотипных веб-серверов, а через месяц ещё пять таких же, но с парой отличий — стало окончательно ясно: постоянная ручная настройка по SSH давно должна была превратиться в автоматическое развёртывание. Никаких больше копипаст bash-скриптов, потерянных настроек и ночных правок конфигов. Только Infrastructure as Code: описал сервер один раз — и дальше он воспроизводится через Ansible, как только появляется новый хост.
Процесс начинается не с написания YAML, а с того, что мы фиксируем в чек-листе каждую мелочь, которую раньше «и так помнили». Из этого чек-листа рождается структурированная конфигурация, разделённая на роли, переменные и задачи. Ниже — пошаговый путь: от аудита текущих машин и выявления типовых настроек до готового плейбука, который разворачивает стандартный Linux-сервер (Nginx/PHP/MySQL или просто базовую ОС) с учётом безопасности, мониторинга и оптимизации под нагрузку. Получите конкретный чек-лист, рабочие примеры и понимание, как не наступить на привычные грабли при миграции от рутины к автоматизации.
Почему чек-лист — это фундамент автоматизации
Бывает, что инженер сразу садится писать плейбук, не продумав до конца, что именно должно оказаться на каждом сервере. Результат предсказуем: в коде появляются «забытые» настройки, которые потом приходится докручивать руками, а это ломает главный принцип единого источника конфигурации. Ansible не требует агентов на целевых узлах и работает по SSH — за счёт этого его и любят. Но гибкость инструмента требует жёстко заданной структуры входных данных: что ставить, какие порты открыть, куда писать логи.
Чек-лист в контексте IaC — не просто список дел, а матрица требований на все компоненты сервера:
- Базовая ОС: версия ядра, дистрибутив (Ubuntu, CentOS, AstraLinux), архитектура.
- Сетевые настройки: IP-адресация, DNS, прокси, правила firewall.
- Пакеты и сервисы: какой софт должен стоять (Nginx, Docker, Zabbix-agent) и в каком состоянии (запущен, остановлен).
- Безопасность: настройка SSH (отключение root, только ключи), права доступа, план обновлений.
- Мониторинг и логирование: куда пишутся логи, какой агент собирает метрики.
- Оптимизация: параметры ядра, лимиты ресурсов, временная зона.
Однажды на площадке забыли прописать таймзону — вроде мелочь. Но когда через месяц в логах начали расходиться таймстемпы, а Zabbix начал ложно срабатывать по ночам, поиск причины занял несколько часов. Чек-лист исключает такие «сюрпризы».
Чек-лист стандартного сервера (Базовая версия)
Ниже — универсальный каркас для стандартного Linux-сервера. Адаптируйте его под свои задачи: для базы данных добавите настройки swap, буферов и планировщика ввода-вывода; для веб-сервера — параметры worker_processes и keepalive. Но базовый скелет обязан быть зафиксирован.
| Категория | Параметр | Значение / Требование | Примечание |
|---|---|---|---|
| ОС | Дистрибутив | Ubuntu 22.04 / CentOS 8 | Версия должна быть зафиксирована в коде |
| Ядро | Стандартное (LTS) | Не использовать experimental-ядра | |
| Сеть | hostname | Уникальный FQDN | Например, srv-web-01.corp.ru |
| DNS | Резервные серверы | Настройка через /etc/resolv.conf |
|
| Firewall | UFW / iptables | Закрыть все порты, кроме 80, 443, 22 | |
| SSH | Пользователь root | Отключен вход | PermitRootLogin no |
| Ключи | Только SSH-ключи | PasswordAuthentication no |
|
| Port | 22 (или нестандартный) | Смена порта для защиты от сканеров | |
| Пакеты | Обновления | apt update / yum update |
Обновление списка пакетов перед установкой |
| Базовые ПО | git, curl, vim, wget |
Стандартный набор инструментов | |
| Сервисы | Timezone | UTC или локальное | Например, Europe/Moscow |
| NTP | Синхронизация времени | Установка chrony или ntp |
|
| Безопасность | Лицензии | Авто-подтверждение | DEBIAN_FRONTEND=noninteractive |
| Fail2Ban | Включен | Защита от brute-force | |
| Мониторинг | Агент | Zabbix / Prometheus | Установка и настройка конфига |
| Логи | journalctl + роллинг |
Настройка logrotate |
Архитектура шаблона: от инвентаризации до ролей
После того как чек-лист утверждён, проектируем структуру проекта Ansible. Ansible оперирует плейбуком — YAML-файлом, описывающим желаемое состояние узлов. Плейбук состоит из «игр» (plays), каждая из которых выполняет набор задач на конкретной группе хостов.
Ключевые компоненты:
- Inventory (инвентаризация): файл со списком серверов, сгруппированных по ролям (
[web],[db],[monitoring]). - Playbook (site.yml): основной сценарий, который запускает задачи.
- Roles (роли): логические блоки —
base,security,nginx. Позволяют не раздувать один плейбук, а наращивать модули. - Variables (переменные): файлы
varsиhost_varsс конкретными значениями (порт, пользователь, версия ПО).
Структура проекта Ansible
ansible/
├── ansible.cfg
├── inventory/
│ ├── production.ini
│ └── staging.ini
├── playbooks/
│ └── site.yml
├── roles/
│ ├── base/
│ │ ├── tasks/
│ │ │ └── main.yml
│ │ ├── handlers/
│ │ │ └── main.yml
│ │ └── templates/
│ ├── security/
│ │ ├── tasks/
│ │ │ └── main.yml
│ │ └── templates/
│ │ └── sshd_config.j2
│ └── nginx/
│ ├── tasks/
│ │ └── main.yml
│ └── templates/
│ └── nginx.conf.j2
├── host_vars/
│ └── srv-web-01/
│ └── roles.yml
└── group_vars/
└── all.yml
Такая структура легко масштабируется. Новый сервер — просто строка в inventory и, при необходимости, пара уникальных переменных в host_vars. Никакой магии.
Выбор формата инвентаризации
Инвентаризация может быть в простом INI или более структурированном YAML. В корпоративных средах часто хватает INI — его проще читать и быстро поправить.
Пример inventory/production.ini:
[web]
srv-web-01 ansible_host=10.0.1.10 ansible_user=deploy
srv-web-02 ansible_host=10.0.1.11 ansible_user=deploy
[db]
srv-db-01 ansible_host=10.0.2.10 ansible_user=deploy
[all:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_private_key_file=/home/deploy/.ssh/id_rsa
Для облачных платформ (AWS, Yandex.Cloud) изобретать велосипед не нужно — берите динамический инвентори, который сам подтянет хосты из API облака. Это избавляет от постоянного обновления списка IP-адресов вручную, особенно когда инстансы пересоздаются автомасштабированием.
Пошаговая реализация: создание плейбука для базовой настройки
Теперь от проектирования переходим к практике. Напишем плейбук, который закрывает пункты нашего чек-листа: базовые пакеты, hardening SSH, обновления, временная зона.
Шаг 1: Установка Ansible на управляющую машину
Ansible ставится только на control node, на целевые серверы — ничего лишнего.
Ubuntu:
sudo apt update
sudo apt install ansible -y
CentOS:
sudo yum install epel-release -y
sudo yum install ansible -y
Проверим версию:
ansible --version
Шаг 2: Настройка SSH-доступа
Ansible работает по SSH, поэтому на управляющей машине должны быть ключи. Никаких паролей в открытом виде — это сразу исключает риски утечки.
Создаём ключ, если его нет:
ssh-keygen -t ed25519 -C "ansible-control"
Копируем публичный ключ на целевой хост:
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]
Проверяем:
ansible all -m ping -i inventory/production.ini
Если видим SUCCESS — контакт установлен.
Шаг 3: Создание основного плейбука (site.yml)
Создаём playbooks/site.yml:
---
- name: Configure standard server
hosts: all
become: true
vars:
admin_user: "deploy"
admin_public_key: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
timezone: "Europe/Moscow"
packages:
- git
- curl
- vim
- wget
- htop
- unzip
tasks:
- name: Update apt cache (Debian)
apt:
update_cache: yes
when: ansible_os_family == "Debian"
- name: Install base packages
package:
name: "{{ packages }}"
state: present
- name: Set timezone
timezone:
name: "{{ timezone }}"
- name: Ensure admin user exists
user:
name: "{{ admin_user }}"
groups: sudo
shell: /bin/bash
password: "{{ admin_password | password_hash('sha512') }}"
createhome: yes
- name: Add authorized key for admin
authorized_key:
user: "{{ admin_user }}"
state: present
key: "{{ admin_public_key }}"
Здесь admin_password — переменная, которую мы зашифруем через Ansible Vault, чтобы пароль никогда не лежал в репозитории в чистом виде.
Шаг 4: Использование ролей для модульности
Раздувать один YAML-файл до бесконечности — путь к хаосу. Вынесем безопасность в отдельную роль.
Структура роли roles/security/tasks/main.yml:
---
- name: Disable root login and password auth
lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
with_items:
- { regexp: '^PermitRootLogin', line: 'PermitRootLogin no' }
- { regexp: '^PasswordAuthentication', line: 'PasswordAuthentication no' }
notify: restart sshd
А в site.yml подключаем роль:
---
- name: Configure standard server
hosts: all
become: true
roles:
- base
- security
Такой подход позволяет включать/отключать компоненты по необходимости: не нужен Nginx — убираем роль nginx из списка.
Шаг 5: Переменные и спецификация серверов
Разные серверы требуют своих параметров: порт Nginx, лимиты worker процессов. Для этого создаём host_vars/srv-web-01/roles.yml:
---
nginx_port: 8080
worker_connections: 2048
В шаблоне роли используем переменные Jinja2:
server {
listen {{ nginx_port }};
...
}
Меняете конфигурацию только через переменные, не трогая код плейбука.
Чек-лист безопасности: от SSH до firewall
Безопасность — обязательная часть любого стандартного сервера. В базовом чек-листе мы перечислили ключевые моменты, теперь смотрим на реализацию в коде.
1. Настройка SSH
Минимальный набор:
- Запрет входа root (
PermitRootLogin no). - Отключение парольной аутентификации (
PasswordAuthentication no). - Ограничение списка пользователей (
AllowUsers admin webadmin). - Смена порта (если ушли с 22, не забудьте отразить
ansible_portв инвентаризации).
Задача в roles/security/tasks/main.yml через шаблон:
- name: Deploy sshd config
template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: 0644
validate: '/usr/sbin/sshd -t -f %s'
notify: restart sshd
Шаблон sshd_config.j2:
Port {{ ansible_port | default(22) }}
PermitRootLogin no
PasswordAuthentication no
AllowUsers {{ allowed_ssh_users | join(' ') }}
2. Firewall (UFW)
Для Debian/Ubuntu:
- name: Enable UFW and allow SSH
ufw:
rule: allow
port: "{{ ansible_port | default('22') }}"
proto: tcp
3. Fail2Ban
- name: Install and start fail2ban
apt:
name: fail2ban
state: present
- name: Ensure fail2ban is running
service:
name: fail2ban
state: started
enabled: yes
4. Обновления системы
Не надо надеяться на ручной apt update раз в месяц. В плейбуке мы обновляем кеш перед установкой пакетов, а для автоматического применения патчей безопасности можно добавить unattended-upgrades:
- name: Install unattended-upgrades
apt:
name: unattended-upgrades
state: present
- name: Enable automatic security updates
debconf:
name: "unattended-upgrades"
question: "unattended-upgrades/enable_auto_updates"
value: "true"
vtype: "boolean"
Типичные ошибки и как их избежать
При миграции от ручного управления к шаблонам попадаются грабли, о которые больно споткнуться. Разберём, что чаще всего идёт не так.
1. Отсутствие проверки зависимостей
Если вы ставите пакет, который требует Python, а его нет — playbook упадёт с неочевидной ошибкой. Всегда проверяйте необходимые компоненты:
- name: Ensure python3 is present
raw: test -e /usr/bin/python3 || (apt update && apt install -y python3)
register: python_check
changed_when: python_check.rc != 0
2. Использование паролей в коде
Никаких admin_password: "secret" в незашифрованных файлах. Ansible Vault решает проблему:
ansible-vault encrypt_string 'secret' --name 'admin_password'
Затем вставляете зашифрованную строку в плейбук или отдельный vars-файл.
3. Неправильная обработка ошибок
По умолчанию Ansible не останавливается при ошибке одной задачи. Иногда это нужно, но часто приводит к каскадным сбоям. Контролируйте поведение:
- name: Check nginx config
command: nginx -t
register: nginx_check
failed_when: "'test failed' in nginx_check.stderr"
4. Забывание о временной зоне и NTP
Как только логи начинают писаться в разнобой, аудит превращается в детектив. NTP и таймзона — первые задачи в базовой роли, иначе любой инцидент замедлится.
5. Отсутствие тестирования
Не применяйте плейбук сразу на всей production-группе. Сначала --check, потом на одном тестовом хосте.
Валидация и тестирование шаблона
Прежде чем запускать плейбук на боевых серверах, убедитесь, что он делает именно то, что вы задумали.
1. Сухой запуск (Dry Run)
ansible-playbook playbooks/site.yml -i inventory/production.ini --check --diff
Покажет, что изменится, без реального воздействия на систему.
2. Запуск на ограниченной группе
ansible-playbook playbooks/site.yml -i inventory/production.ini --limit srv-web-01
3. Проверка подключения
ansible all -m ping -i inventory/production.ini
4. Проверка состояния сервисов
ansible web -m service -a "name=nginx state=started" -i inventory/production.ini
5. Автоматическое тестирование
Для серьёзных проектов подключайте Molecule — он разворачивает роли в изолированных контейнерах и проверяет корректность конфигураций до того, как они попадут на реальное железо.
Интеграция с облачными средами и гибридными архитектурами
Сегодня серверы живут и в облаках, и на своих стойках. Ansible гибко объединяет и то, и другое. Динамический инвентори для Yandex.Cloud, например, автоматически подтягивает список виртуалок:
ansible-inventory -i inventory/yandex.oci.yml --list
Для гибридных сред удобно комбинировать несколько инвентаризаций:
ansible-playbook playbooks/site.yml -i inventory/production.ini -i inventory/cloud.ini
Такой подход избавляет от ручного добавления хостов при автомасштабировании и позволяет применять единые политики конфигурации как в on-prem, так и в облаке.
Чек-лист для финальной проверки шаблона
Перед тем, как закрыть задачу, пробегитесь по этому списку:
- Инвентаризация: Все серверы перечислены, группы корректны.
- SSH: Доступ только по ключам, root отключён, пароли запрещены.
- Пакеты: Базовый софт установлен, обновления применены.
- Сервисы: NTP, Timezone, Firewall работают.
- Переменные: Пароли зашифрованы (Vault), чувствительные данные не в открытом виде.
- Тестирование: Плейбук прогнан в
--check, ошибки обработаны. - Мониторинг: Агент установлен, логи ротируются.
- Документация: Есть README с описанием переменных и инструкцией по запуску.
FAQ: Часто задаваемые вопросы
- Можно ли использовать Ansible для Windows-серверов?
- Да, Ansible поддерживает Windows через WinRM. Потребуется настроить соответствующие подключения и убедиться, что PowerShell и .NET Framework нужных версий присутствуют. По умолчанию весь инструментарий заточен под Linux, но Windows тоже автоматизируется.
- Как обновить шаблон, если изменилась версия ПО?
- Обновите переменную с версией в
vars/main.ymlилиhost_vars/. Не редактируйте сам плейбук — код должен быть независим от данных. При следующем запуске Ansible сам подтянет нужный пакет. - Что делать, если плейбук не работает на конкретном сервере?
- Используйте
--limitдля изоляции проблемного хоста, добавьте--diffи-vvvдля детального вывода. Часто проблема кроется в устаревшем ключе SSH или несовпадении версий Python. - Как защитить переменные с паролями?
- Обязательно Ansible Vault. Шифруйте чувствительные строки или целые файлы. При запуске указываете пароль от vault или файл-ключ.
- Можно ли применить один шаблон для разных дистрибутивов?
- Да, через условия
when: ansible_os_family == "Debian"и т.д. Роль базовой настройки сама определит, какие менеджеры пакетов использовать. - Как откатить изменения, если плейбук применился некорректно?
- Ansible сам по себе не хранит историю и не умеет откатывать. Для инфраструктурных объектов используйте Terraform, а в самом Ansible — делайте резервные копии конфигураций до применения любых изменений (модуль
copyсbackup: yes).
Вывод
Описать стандартный сервер в виде шаблона — это первый кирпичик в фундаменте инженерии надёжности. Начинается всё с чек-листа, в котором зафиксировано каждое требование, а заканчивается плейбуком, разворачивающим сервер без единого ручного входа.
Главные принципы, которые стоит запомнить:
- Чек-лист — без него шаблон будет дырявым.
- Модульность: роли делают код читаемым и повторно используемым.
- Переменные: не зашивайте данные в код, выносите их в
varsиhost_vars. - Тестирование:
--checkи Molecule — ваши лучшие друзья. - Безопасность: SSH, firewall и Fail2Ban — не опциональные дополнения, а обязательная часть.
Когда серверов переваливает за сотню, рутина начинает душить. Шаблонизация — это способ не просто сэкономить время, а перейти от тушения ночных пожаров к осознанному проектированию надёжных систем, где ручные правки конфигов больше не нужны. И с этого начинается путь от классического админа к SRE-инженеру, который автоматизирует всё, включая собственные задачи.
