DevOps
Ansible и Configuration Management
В 2015 OpenAI запускает первый GPU-кластер на 100 машин. Чтобы за день поставить CUDA, PyTorch, мониторинг и SSH-ключи на каждую - один Ansible playbook. Без него - пять инженеров и неделя. Сегодня Anthropic, Mistral и DeepSeek делают то же самое: GPU-парк держится на YAML.
- **Red Hat купил Ansible за 150 млн долларов** в 2015 - один из крупнейших exit'ов в DevOps
- **NASA использует Ansible** для управления научными инструментами на разных континентах
- **Cisco и Juniper** интегрировали Ansible как стандарт автоматизации сетевого оборудования
- **ML-инфраструктура:** Anthropic, OpenAI, Mistral оформляют деплой инференса на GPU-парк через Ansible-роли
Playbooks: YAML, который умеет администрировать
2012 год. Michael DeHaan смотрит на Puppet и Chef и хочет блевать. Оба требуют агента на каждой машине, оба несут свой DSL, оба - монстры. Он пишет Ansible за вечера. Идея: ssh + Python на удалённой стороне (он там и так есть) + YAML с описанием 'что должно быть'. Всё. Через три года Red Hat покупает компанию за 150 млн долларов.
Playbook - YAML-файл с *желаемым состоянием*. Не 'выполни эту команду', а 'этот пакет должен быть установлен'. Не 'sed -i по конфигу', а 'эта строка должна присутствовать в файле'. Декларативность - то же ядро, что в Terraform, Kubernetes manifests, или declare в Stable Diffusion pipeline. Описывается конечная точка, движок сам думает, как её достичь.
Каждый task запускает один module - готовый Python-скрипт на стороне target'а. Modules делают всё: устанавливают пакеты, копируют файлы, перезапускают сервисы, дёргают AWS API. Стандартная коллекция - 3000+ модулей. Один YAML может развернуть LLM-инференс на 100 GPU-машинах за пять минут.
**Agentless - ключевое преимущество:** не нужно ставить ничего на удалённые хосты. Достаточно ssh-доступа и Python (на любой современной Linux он уже есть). Это то же преимущество, что у serverless function над Kubernetes: меньше движущихся частей - меньше точек отказа.
Что отличает Ansible от Puppet и Chef архитектурно?
Roles: организация плейбуков по принципу LoRA-адаптеров
Когда playbook вырастает до 500 строк, начинается боль. Те же задачи копируются между проектами. Конфиги путаются с tasks, переменные с handlers. Role - стандартная структура папок, которая режет playbook на переиспользуемые части. Один раз написал nginx-роль, применяешь во всех проектах.
Структура жёсткая: `tasks/main.yml` - что делать, `defaults/main.yml` - переменные по умолчанию, `templates/` - Jinja2-шаблоны, `handlers/main.yml` - реакции на изменения, `files/` - статические файлы. Та же логика модульности, что в LoRA-адаптерах: базовая модель не трогается, поверх накладываются роли под задачу.
Ansible Galaxy - публичный реестр ролей. 30 тысяч готовых ролей: nginx, kafka, postgres, monitoring, kubernetes. Сообщество vmware, geerlingguy, jeff-geerling - стандарт де-факто. Это как Hugging Face для девопса: качай чужое, применяй своё.
**Variable precedence:** в Ansible 22 уровня переопределения переменных - от defaults до CLI extra-vars. Звучит безумно, но решает реальную задачу: env-specific override без копипасты. Та же логика, что в Hydra-config или OmegaConf у ML-инженеров - наследование и переопределение слоями.
Какой главный смысл выделения ролей в Ansible?
Inventory: карта мира из YAML
Ansible должен знать, к каким машинам ходить. Inventory - список хостов, сгруппированный по ролям. Самый простой формат - INI-файл с группами в квадратных скобках, более продвинутый - YAML с группами групп и переменными. Современные проекты держат inventory в Git вместе с playbook'ами.
Dynamic inventory - inventory, который генерируется скриптом. AWS-плагин обходит EC2 API, возвращает список инстансов с тегами как группами. Kubernetes-плагин - pods как hosts. Это позволяет не вести список вручную: облако само рассказывает, что у него есть. Та же логика service discovery в Kubernetes - реестр живёт в одном месте, потребители опрашивают.
Группы могут вкладываться. `[production:children]` объединяет `webservers`, `dbservers`, `cache`. Переменные на уровне группы наследуются всеми её хостами. На уровне хоста - переопределяются. Это даёт environment-specific конфиг (dev/staging/prod) без дублирования.
**ansible-vault:** чувствительные переменные (пароли БД, API-ключи) шифруются AES-256 прямо в Git-репозитории. Master-ключ хранится отдельно (vault password file или из CI-секрета). Это решает старую боль: код в Git, секреты не в Git, но связаны логически. То же решение, что sealed-secrets в k8s или SOPS у Mozilla.
Зачем нужен dynamic inventory вместо статического?
Идемпотентность: запусти десять раз, ничего не сломается
Самое важное свойство Ansible: запуск одного и того же playbook'а второй раз ничего не должен изменить, если состояние уже желаемое. Это идемпотентность. Без неё инфраструктура - карточный домик: каждый запуск может что-то добавить, удалить или сломать.
Каждый module знает, как проверить текущее состояние перед действием. `apt: name=nginx state=present` сначала проверяет, установлен ли пакет. Если да - skip. Если нет - install. Возвращает `changed: false` или `changed: true`. Та же логика, что в diffusion DDIM с deterministic sampling: одинаковые входы дают одинаковые выходы независимо от числа шагов.
Команды через `shell` и `command` модули - анти-паттерн именно из-за идемпотентности. Они выполняют команду всегда. Поэтому есть `creates`/`removes` - условия пропуска. И есть правило: использовать специализированный module всегда, когда он есть. `file:` вместо `chmod`. `git:` вместо `git clone`. `lineinfile:` вместо `sed`.
**Idempotency check на CI:** профи запускают playbook дважды подряд - первый делает изменения, второй должен вернуть `changed: 0`. Если второй запуск что-то меняет - в playbook есть скрытый дрейф, его чинят до merge. Та же практика, что в Terraform: plan дважды, ожидается no-op.
Идемпотентность - просто 'не падает при повторном запуске'
Идемпотентность - 'второй запуск возвращает 0 изменений, потому что состояние уже сошлось к желаемому'
Не падать - слабое требование. Стабильное состояние требует, чтобы каждый module проверял текущее состояние и пропускал работу, если изменения не нужны. Тогда playbook становится reference state, и любой дрейф ловится через `--check` в CI. Без этого инфраструктура - набор костылей, который работает только при первом прогоне
Какой запуск playbook'а правильно отражает идемпотентность?
Связанные темы
Куда Ansible ведёт дальше:
- Docker и контейнеризация — Ansible часто разворачивает Docker-хосты и оркестрирует docker-compose deploy
- CI/CD pipelines — Ansible как один из шагов CI - применить изменения после успешного тестирования
- Linux internals — Ansible живёт на ssh, systemd, apt/yum - фундамент Linux в каждой задаче
- Observability stack — Раскатка node_exporter, fluent-bit, OpenTelemetry collector - классический Ansible-сценарий
Ключевые идеи
- Ansible - agentless: ssh + Python на target'е, никаких демонов
- Playbook - декларативный YAML с желаемым состоянием, не императивные команды
- Roles - стандартная структура для переиспользования, аналог LoRA-адаптеров для инфры
- Inventory - карта мира с группами и переменными, dynamic из cloud API
- Идемпотентность - запусти десять раз, второй и далее возвращают 0 изменений
Вопросы для размышления
- Когда выбрать Ansible, а когда Terraform для одной задачи?
- Где провести границу между Ansible-ролями и Docker-образами в собственной инфре?
- Как обеспечить идемпотентность для задач, которые принципиально мутирующие (миграции БД, например)?
Связанные уроки
- devops-01 — Базовый Linux нужен - Ansible живёт на ssh и shell-командах
- devops-04 — Docker-хосты часто разворачиваются через Ansible playbook'ы
- devops-08 — CI/CD-пайплайны запускают Ansible как один из шагов
- os-19-containers — Контейнеры решают тот же класс задач, но через изоляцию вместо конфигурации
- sd-22-observability — Установка node_exporter, fluent-bit на парк машин - типовой Ansible-сценарий
- aie-44-ai-backend-node — Деплой LLM-инференса на GPU-парк часто оформляется как Ansible-роль
- os-21-linux-internals