Раньше я настраивал серверы вручную. Подключался по SSH, ставил пакеты, открывал порты, копировал ключи, правил конфиги. Повторял это снова и снова — на каждом сервере. Иногда ошибался, забывал шаг, путал порядок. Это был бардак.
Пока однажды не надоело, и я решил нырнуть в Ansible.
Что это вообще такое?
Ansible — это инструмент для автоматизации настройки серверов, написанный на Python. Его особенность в том, что он работает по SSH и не требует установки дополнительных агентов на удалённые машины. Нужен только Python на сервере (а он есть почти везде) и доступ по SSH. Всё.
Ты просто описываешь желаемое состояние машины в виде YAML-файла, а Ansible сам идёт по списку серверов и приводит их к этому состоянию. Хочешь nginx — он поставит nginx. Нужен пользователь без root-доступа — создаст. Нужно скопировать конфиг, перезапустить сервис, выдать права — всё это Ansible умеет делать прямо из коробки.
Важно: Ansible не просто выполняет команды. Он работает декларативно. Ты говоришь: «на сервере должен быть установлен nginx» — а не «установи nginx». Если он уже есть — Ansible ничего не делает. Если нет — устанавливает. Это поведение называется идемпотентностью. Оно критично, когда ты работаешь с десятками или сотнями машин.
Что я больше не делаю вручную
Вот задачи, которые раньше я выполнял руками на каждом сервере. Теперь всё это делает Ansible:
Установка и настройка nginx (конфиги, автозапуск, HTTPS)
Создание пользователей и настройка SSH-доступа
Отключение входа под root и паролей
Установка Docker + docker-compose и запуск контейнеров
Развёртывание k3s (лёгкий Kubernetes)
Настройка файрвола (UFW или iptables: открыть только 22 и 443)
Установка certbot и настройка продления сертификатов
Настройка fail2ban для защиты nginx и SSH
Клонирование репозиториев с GitHub и деплой
Запуск приложений в docker или через systemd
Настройка мониторинга (node_exporter + pushgateway для Prometheus)
Теперь я могу:
Развернуть staging-сервер за 10 минут
Настроить окружение для нового разработчика одной командой
Восстановить сервер по шаблону без лишней суеты
И всё это без логина по SSH. Просто один плейбук.
Как это работает
Если ты впервые слышишь про Ansible, вот из чего он состоит:
Inventory — это список серверов, с которыми Ansible будет работать. Это может быть простой текстовый файл в формате INI или YAML. Здесь ты указываешь адреса, логины и при необходимости параметры подключения.
Playbook — это набор задач. Это главный файл, который говорит Ansible, что именно делать на этих серверах. Устанавливать пакеты, копировать файлы, редактировать конфиги, перезапускать сервисы. Всё это пишется в YAML.
Tasks — это шаги внутри плейбука. Одна задача = одно действие. Например:
установить nginx
,скопировать конфиг
,перезапустить nginx
. Вся магия Ansible крутится вокруг этих шагов.Modules — каждая задача использует модуль. Например, модуль
apt
устанавливает пакеты в Debian/Ubuntu. Модульtemplate
— копирует файл-шаблон и подставляет переменные. Модульservice
управляет службами. Ты просто описываешь, чего хочешь, Ansible подбирает нужные команды.Variables — переменные, которые можно задавать один раз и переиспользовать в разных частях конфигурации. Например, можно задать
app_port: 8080
и потом подставить её в шаблон nginx или docker-команду.Templates — это конфиги с переменными. Ansible берёт такой файл, подставляет туда нужные значения и закидывает его на сервер.
Handlers — специальные задачи, которые запускаются только если что-то изменилось. Например: если конфиг nginx изменился — перезапусти nginx.
Roles — способ разложить всё по папкам, чтобы не лепить весь конфиг в один файл. Каждая роль — как модуль: своя логика, свои переменные, свои шаблоны. Очень удобно.
Минимум, чтобы собрать простой playbook:
1. Создай inventory-файл hosts
с адресами серверов:
[web]
192.168.1.101 ansible_user=ubuntu
192.168.1.102 ansible_user=ubuntu
192.168.1.103 ansible_user=ubuntu
192.168.1.104 ansible_user=ubuntu
[ftp]
192.168.2.101 ansible_user=ubuntu
192.168.2.102 ansible_user=ubuntu
В данном случае есть две группы серверов - web
и ftp
и ко всем ты будешь подключаться от имени пользователя ubuntu
.
В одном инвентарнике можно хранить сколько угодно серверов в разных группах и использовать конкретные группы только при необходимости
2. Напиши базовый playbook site.yml
:
- name: Установка и настройка nginx
hosts: web # группа серверов
become: true # выполнять как root
vars:
domain: example.com # домен для сайта
tasks:
- name: Установить nginx
apt:
name: nginx # название пакета
state: present # должен быть установлен
update_cache: yes # обновить список пакетов?
- name: Создать конфиг
template:
src: nginx.conf.j2 # откуда берём шаблон
dest: /etc/nginx/sites-available/default # куда кладём
- name: Перезапустить nginx
service:
name: nginx # название службы
state: restarted # состояние - перезапущено
3. Добавь шаблон nginx.conf.j2
в папку рядом:
server {
listen 80;
server_name {{ domain }};
location / {
proxy_pass http://127.0.0.1:3000;
}
}
4. Запусти:
ansible-playbook -i hosts site.yml
Это базовый пример. С него удобно начать, чтобы понять, как всё работает. А дальше подключаешь роли, переменные, структуру — и всё это масштабируется под настоящую инфраструктуру.
Роли: как делать красиво
Когда задач становится много, всё в одном плейбуке быстро превращается в кашу. Поэтому Ansible предлагает роли — это как модульные блоки: каждая роль отвечает за свой компонент системы.
Например:
nginx
— всё, что касается веб-сервераdocker
— установка и настройка Dockerfirewall
— открытие нужных портовcertbot
— выписывание и продление TLS-сертификатов
Роль — это папка с определённой структурой:
roles/
nginx/
tasks/main.yml # что нужно сделать
templates/nginx.conf.j2 # шаблоны конфигов
vars/main.yml # переменные по умолчанию
handlers/main.yml # перезапуск сервисов при изменениях
Так ты можешь переиспользовать одну и ту же роль для любых серверов — просто подставляя свои переменные.
Пример site.yml
, который использует роли:
- hosts: webservers
become: true
roles:
- common # базовые настройки: users, timezone, apt update
- firewall # открыть порты
- docker # поставить Docker
- nginx # настроить веб-сервер
- certbot # получить сертификаты
Зачем это удобно:
Код разбит по смыслу — легко читать и искать
Меньше дублирования — роли можно применять повторно
Команда понимает, где что лежит
Можно собирать кастомные окружения просто комбинацией ролей
Если у тебя 5 разных серверов — ты можешь для каждого задать свой список ролей. Всё гибко и чисто. И самое главное — это не мешает масштабироваться.
Как запускать всё это
Чтобы применить плейбук, запускаем команду:
ansible-playbook -i inventories/prod/hosts site.yml
Здесь:
-i inventories/prod/hosts
— путь до файла с инвентарём, то есть список серверовsite.yml
— сам плейбук со всеми задачами
Когда ты запускаешь playbook, Ansible идёт по серверам из списка и выполняет задачи. Если всё уже настроено правильно, он просто скажет «OK» и ничего не будет менять — это и есть идемпотентность.
Если ты хочешь выполнить только конкретную часть плейбука — используй теги.
В плейбуке можно пометить задачи:
- name: Обновить сертификаты
include_tasks: renew_certbot.yml
tags: certbot
Теперь эта часть выполнится только по запросу, не трогая остальное:
ansible-playbook -i inventories/prod/hosts site.yml --tags certbot
Если нужно применить задачи только к одному конкретному серверу — это делается так:
ansible-playbook -i inventories/prod/hosts site.yml -l 192.168.1.10
Флаг -l
(или --limit
) ограничивает запуск только на указанный IP или хостнейм. Удобно для отладки или точечных изменений.
Можно также запускать playbook с повышенным уровнем подробностей:
ansible-playbook -i inventories/prod/hosts site.yml -vvv
Флаг -v
(или -vvv
) показывает, что происходит под капотом, дословно - verbose, то есть многословный - какие команды выполняются, что вернул сервер и т.д.
Шаблоны и переменные
В Ansible шаблоны — это способ создавать конфиги с переменными. Вместо того чтобы писать жёстко заданные значения (IP, домены, порты), ты создаёшь шаблон и говоришь Ansible: «подставь сюда нужные данные сам».
Формат шаблонов — это Jinja2. Он очень похож на обычный текст, только с переменными внутри фигурных скобок: {{ variable_name }}
.
Сначала ты определяешь переменные, которые будут использоваться в шаблоне:
domain: example.com
app_port: 3000
А потом пишешь шаблон, например nginx.conf.j2
, в котором эти переменные будут подставляться:
server {
listen 80;
server_name {{ domain }};
location / {
proxy_pass http://127.0.0.1:{{ app_port }};
}
}
Ansible автоматически подставит нужные значения при копировании шаблона на сервер.
Это удобно:
Один шаблон — много окружений (dev, staging, prod)
Не надо руками править конфиги при каждом деплое
Можно делать более умные шаблоны: с условиями, циклами, дефолтами
Чтобы использовать шаблон в задаче:
- name: Скопировать шаблон nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/default
Ansible сам найдёт файл и перенесёт его на сервер, подставив все нужные значения. Если файл отличается — он заменит, а если нет — оставит как есть.
А если мой проект лежит на GitHub?
Не проблема. Если твой код уже лежит на GitHub, его можно просто и удобно клонировать прямо во время выполнения плейбука. Для этого используется встроенный модуль git
. Он позволяет указать репозиторий, ветку, путь на сервере, и даже ssh-ключ, если репозиторий приватный.
Пример задачи:
- name: Клонировать проект с GitHub
git:
repo: 'git@github.com:me/project.git' # адрес репозитория
dest: /srv/app # путь, куда клонировать
version: main # нужная ветка
accept_hostkey: yes # принять ssh-ключ сервера
key_file: /root/.ssh/id_rsa # приватный ключ для доступа
Что важно:
Убедись, что у пользователя, под которым Ansible подключается, есть доступ к GitHub (обычно через ssh-ключ).
accept_hostkey: yes
— чтобы не споткнуться о подтверждение ключа при первом подключении.
Если ты добавишь такую задачу в роль деплоя — всё будет происходить автоматически.
И да, ты можешь настроить CI (например, GitHub Actions), чтобы при каждом пуше запускался ansible-playbook
. Это даст тебе простой и работающий CI/CD без Jenkins и других тяжеловесов.
Как решать реальные проблемы
Иногда кажется, что автоматизация — это про теоретические примеры. Но вот как Ansible помогает, когда что-то ломается или начинает вести себя странно.
Проблема: сервер не продлевает SSL-сертификаты
Если забыть настроить автоматическое продление, certbot просто перестанет обновлять сертификаты — и сайт начнёт выдавать ошибку. Ansible может заранее поставить задачу в cron:
- name: Настроить автоматическое продление сертификатов
cron:
name: "renew certbot"
job: "certbot renew --quiet"
minute: "0"
hour: "3"
Этот cron будет запускаться каждый день в 03:00 и проверять, нужно ли продлевать.
Проблема: контейнер с приложением не запускается после перезагрузки
Если ты просто вручную запускал docker-контейнеры, после ребута сервера они могут не стартовать. Ansible помогает настроить это один раз, и оно будет работать вечно:
- name: Убедиться, что контейнер запущен
docker_container:
name: myapp
image: myimage:latest
state: started
restart_policy: always
ports:
- "80:80"
Контейнер будет запускаться при каждом старте системы, а если упадёт — перезапустится автоматически.
Как всех обновить?
Иногда нужно обновить софт на всех серверах — например, поставить новую версию Docker, nginx или PostgreSQL. Ansible позволяет делать это централизованно и безопасно.
Ты просто помечаешь нужные задачи тегом, например upgrade
, и потом запускаешь только их:
ansible-playbook -i hosts site.yml --tags upgrade
В плейбуке задача может выглядеть так:
- name: Обновить все пакеты
apt:
upgrade: dist
tags:
- upgrade
Ты можешь сделать отдельную роль для обновлений, где будут задачи вроде:
Проверить доступные обновления
Обновить systemd-сервисы
Перезапустить нужные контейнеры
Перезапустить nginx или базы
Это удобно, потому что ты точно знаешь, что и где обновится. И если что — всегда можно быстро откатиться или перенастроить.
Такой подход особенно выручает, если у тебя десятки серверов и каждый вручную не проверить.
Когда Ansible реально спасает
Бывают ситуации, когда время идёт на минуты, всё падает или горит — и тогда автоматизация действительно выручает.
Когда надо быстро восстановить сервер после падения
Когда нужно за 10 минут развернуть тестовое окружение
Когда в команде множество разработчиков, и надо всем одинаковое окружение
Когда VPS улетела, и ты хочешь восстановиться без боли
Что важно помнить
Ansible — это не про «крутой DevOps». Это про «я не хочу больше делать это руками». Если ты тратишь 30 минут на установку nginx на каждый сервер — ты делаешь это зря. За тебя может сделать YAML и 1 команда в терминале.
Инструмент мощный, но не волшебный. Вот несколько базовых правил:
Проверяй
become: true
, если задача требует прав администратора. Без этого ничего не заработает.Пиши задачи идемпотентно — чтобы повторный запуск ничего не ломал и не делал зря.
Разделяй роли по смыслу: чем они меньше и чище, тем проще поддерживать.
Никогда не храни ключи, токены и пароли в открытом виде. Используй
ansible-vault
— он шифрует секреты.Используй
--check
для dry-run'а перед деплоем, особенно в проде.Если не уверен — проверь на одном сервере с
--limit
.become: true
, если что-то требует sudoИспользуй idempotent задачи — Ansible не должен делать лишнего
Лучше разделить роли: чем мельче и чище — тем легче поддерживать
Никогда не храни ключи и пароли в открытом виде — используй
ansible-vault
P.S. Этот текст не о том, "как надо" или "как правильно". Это то, что сэкономило мне десятки часов и множество нервных клеток. Если поможет ещё кому-то, то я просто буду очень рад.
Комментарии (5)
baldr
22.06.2025 15:49Вопрос - если у меня есть cron-задача и я хочу её временно выключить - как это сделать?
Если на сервер ходит больше одного человека - как организационно это обычно регулируется?
grosm4n Автор
22.06.2025 15:49Задачи в кроне можно временно отключать с флагом disabled: true. Это просто закомментирует строку в crontab, false соответственно раскомментирует
Когда над сервером работают несколько человек, можно подключить AWX: это веб-интерфейс для Ansible, где видно, кто что запустил, какие плейбуки менялись, можно давать права, запускать задачи по расписанию и всё такое.
mluf
22.06.2025 15:49-
hosts: Группа хостов
become: yes
tasks:
-
name: Произвольное имя
ansible.builtin.cron:
name: Имя_задачи_в_cron
user: Имя_пользователя
disabled: true
-
...
Параметр disabled в модуле ansible.builtin.cron отключит задачу "Имя_задачи_в_cron" для пользователя "Имя_пользователя".-
alef13
22.06.2025 15:49Playbook это не набор задач - playbook это набор play. А вот play это уже совокупность задач/ролей и объектов, к которым они применяются.
leonie
так что с бобром