Раньше я настраивал серверы вручную. Подключался по 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 — установка и настройка Docker

  • firewall — открытие нужных портов

  • 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)


  1. leonie
    22.06.2025 15:49

    так что с бобром


  1. baldr
    22.06.2025 15:49

    Вопрос - если у меня есть cron-задача и я хочу её временно выключить - как это сделать?

    Если на сервер ходит больше одного человека - как организационно это обычно регулируется?


    1. grosm4n Автор
      22.06.2025 15:49

      Задачи в кроне можно временно отключать с флагом disabled: true. Это просто закомментирует строку в crontab, false соответственно раскомментирует

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


    1. mluf
      22.06.2025 15:49

      • hosts: Группа хостов

        become: yes

        tasks:

        • name: Произвольное имя

          ansible.builtin.cron:

          name: Имя_задачи_в_cron

          user: Имя_пользователя

          disabled: true

      ...
      Параметр disabled в модуле ansible.builtin.cron отключит задачу "Имя_задачи_в_cron" для пользователя "Имя_пользователя".


  1. alef13
    22.06.2025 15:49

    Playbook это не набор задач - playbook это набор play. А вот play это уже совокупность задач/ролей и объектов, к которым они применяются.