Agentless: магия без агентов

Урок 2 - разбираемся, как Ansible управляет серверами без единого агента.

«Лучший агент - это тот, которого не нужно устанавливать, обновлять и охранять».

Многие инструменты управления конфигурацией (Puppet, Chef, Salt в классическом режиме) работают по схеме «агент». На каждый сервер ставится демон, он постоянно крутится, ходит на центральный сервер за инструкциями. Это мощно, но дорого: агента надо установить, настроить, обновлять, следить за его безопасностью - на каждой машине. Ansible пошёл другим путём - agentless, без агента.

Как это работает

Ansible использует то, что и так есть на каждом Linux-сервере: SSH и Python. Когда ты запускаешь playbook, control node подключается к целевому хосту по SSH, копирует туда крошечный Python-модуль, выполняет его, забирает результат в формате JSON и удаляет временный файл. Никакого постоянно работающего процесса на сервере не остаётся.

   CONTROL NODE                         MANAGED HOSTS
  (твоя машина)
  +-------------+      SSH (22)        +-------------+
  | playbook    | ----------------->  | web1        |
  | inventory   |                      |  python3    |
  | ansible     | ----------------->  +-------------+
  +-------------+      SSH (22)        +-------------+
        |          ----------------->  | web2        |
        |                              |  python3    |
        |                              +-------------+
        v          SSH (22)            +-------------+
   модуль на Python -----------------> | db1         |
   копируется, run, JSON назад         |  python3    |
                                       +-------------+

Обрати внимание: стрелки идут только в одну сторону - от control node к хостам. Серверы не ходят никуда сами, не открывают входящих соединений к управляющему узлу. Это упрощает сетевую модель и фаервол.

Как работает под капотом

Под капотом Ansible для каждого хоста делает примерно следующее: устанавливает SSH-соединение (часто переиспользуя его через ControlPersist для скорости), сериализует нужный модуль вместе с аргументами, передаёт его на хост, запускает интерпретатором Python, читает stdout как JSON-результат со статусом (ok, changed, failed) и подчищает за собой. Именно поэтому единственное требование к управляемому хосту - наличие Python и доступ по SSH.

Симулируем логику исполнения модуля на хосте маленькой Python-моделью. Это не настоящий Ansible, но точно отражает идею «модуль возвращает структурированный статус».

# Логика "модуля" на хосте: получает желаемое состояние,
# возвращает структурированный результат как настоящий Ansible-модуль.
def package_module(name, installed_packages, state="present"):
    is_installed = name in installed_packages
    if state == "present" and not is_installed:
        installed_packages.add(name)
        return {"changed": True, "msg": f"package {name} installed"}
    if state == "absent" and is_installed:
        installed_packages.discard(name)
        return {"changed": True, "msg": f"package {name} removed"}
    # уже в нужном состоянии - ничего не делаем
    return {"changed": False, "msg": f"{name} already {state}"}

host_state = {"curl"}  # что уже стоит на сервере
print(package_module("nginx", host_state))  # changed: True
print(package_module("nginx", host_state))  # changed: False (повтор)
print(package_module("curl",  host_state))  # changed: False

Попробуй сам ▶ Запусти и посмотри: первый вызов вернул changed: True, а повторный - changed: False. Это и есть идемпотентность в зачатке: модуль сначала проверяет состояние, потом решает, нужно ли действие.

Частые ошибки

  • Искать «агента Ansible». Его нет и не должно быть. Если кто-то предлагает «поставить ansible на каждый сервер» - это недоразумение. Ansible ставится только на control node.
  • Забыть про Python на хосте. Очень минималистичные образы (например, голый Alpine) могут не иметь Python - тогда либо ставят его первым шагом через raw-модуль, либо используют специальный интерпретатор.
  • Открывать лишние порты. Раз связь идёт только по SSH от control node, входящие соединения к серверам со стороны Ansible не нужны.

Best practices

  • Используй SSH-ключи, а не пароли. Это и безопаснее, и удобнее для автоматизации.
  • Заведи отдельного пользователя для Ansible с правом sudo там, где нужно повышение прав.
  • Не плоди агентов: простота agentless-модели - это фича, не недостаток.

В реальной работе

Agentless-модель особенно выручает в гетерогенной среде, где соседствуют разные дистрибутивы и версии. Тебе не нужно собирать и поддерживать пакет агента под каждую ОС, следить за совместимостью его версий и обновлять его по всему парку машин - достаточно того, что на хосте уже есть. Минус подхода в том, что Ansible работает «по требованию»: он не следит за серверами постоянно, как агентные системы, а приводит их в порядок только в момент запуска. Поэтому в зрелых командах playbook'и гоняют регулярно по расписанию или из CI, чтобы дрейф конфигурации не накапливался между ручными запусками.

Итоги

Ansible не требует агентов: он работает по обычному SSH, временно копируя на хост Python-модули и забирая структурированный результат. Это упрощает безопасность, сеть и эксплуатацию. Дальше познакомимся с установкой и первой командой.

Проверьте себя
1. Что нужно установить на управляемый сервер, чтобы Ansible им управлял?
AДемон ansible-agent
BНичего особого: достаточно SSH-доступа и Python
CDocker и Kubernetes
DСпециальный плагин ядра
2. В какую сторону идут соединения при работе Ansible?
AОт серверов к control node
BВ обе стороны постоянно
CОт control node к управляемым хостам по SSH
DЧерез центральный облачный брокер