SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-25

Ansible или Terraform: что выбрать для инфраструктуры

Узнайте ключевые различия между Ansible и Terraform. Разбираем, почему Terraform лучше подходит для создания VPS, а Ansible для настройки ПО внутри системы и управления конфигурациями.

Ansible против Terraform в одном предложении

Ansible и Terraform — это не выбор между двумя инструментами для выполнения одной и той же задачи. Terraform описывает, какая инфраструктура должна существовать: серверы, диски, сети, DNS-записи. Ansible описывает состояние внутри уже существующей машины: пакеты, пользователей, конфигурационные файлы, запущенные службы. Terraform создаёт VPS. Ansible превращает этот VPS в веб-сервер.

Оба инструмента декларативны, и оба относятся к категории infrastructure as code (IaC). Реальное различие заключается в том, что они «помнят». Terraform записывает файл состояния (state file), который сопоставляет каждый ресурс в коде с реальным объектом, созданным через API. Благодаря этому он понимает, что удаление пяти строк кода означает необходимость уничтожения одного сервера. Ansible не сохраняет никакой информации между запусками. Он подключается по SSH, проверяет состояние машины и изменяет только то, что не соответствует playbook.

Это единственное различие объясняет всё остальное в данном руководстве, включая причины, по которым попытка объединить обе задачи в одном инструменте приводит к ошибкам.

Что на самом деле делает Terraform

Terraform взаимодействует с API через плагин провайдера. Страница реестра вашего провайдера определяет типы ресурсов, которые вы можете описывать, поэтому сервер на одном хосте и сервер на другом — это разные имена ресурсов с разными аргументами.

resource "cloud_server" "web" {
  name  = "web1"
  image = "ubuntu-24.04"
  type  = "small"
}

output "web_ip" {
  value = cloud_server.web.ipv4_address
}

Замените cloud_server на тип ресурса, указанный в документации вашего провайдера. Блок output — это важная часть данного руководства, так как именно через него адрес передается из Terraform.

terraform init
terraform fmt -check
terraform validate
terraform plan -out=tfplan
terraform apply tfplan

terraform init загружает провайдер и создает файл блокировки. terraform plan выводит разницу между вашим кодом и файлом состояния, завершаясь строкой вида Plan: 1 to add, 0 to change, 0 to destroy.. Читайте эту строку каждый раз. Некоторые аргументы нельзя изменить на месте, и план указывает на это с помощью # forces replacement рядом с атрибутом, за которым следует 1 to add, 0 to change, 1 to destroy. Применение такого плана удаляет сервер и создает новый пустой, из-за чего люди теряют данные, которые считали защищенными.

Сохранение плана в файл и его последующее применение вместо запуска простого terraform apply гарантирует, что выполняется именно то, что вы проверили. В промежутке между двумя командами кто-то другой может изменить инфраструктуру.

terraform.tfstate — это память системы. Потеряете его, и Terraform перестанет распознавать эти серверы как ваши, поэтому следующий запуск apply попытается создать дубликаты. Храните его в удаленном бэкенде, как только команды начинают запускать более одного человека, так как одновременное применение двумя пользователями приводит к следующему:

Error: Error acquiring the state lock

OpenTofu — это форк Terraform с теми же командами и форматом файлов. По состоянию на июль 2026 года все инструкции в этом руководстве работают, если вы введете tofu вместо terraform.

Что на самом деле делает Ansible

Ansible не требует установки агента или API. Он открывает SSH-соединение, копирует небольшой Python-модуль на целевой хост, выполняет его и удаляет. Ansible может настроить всё, к чему у вас есть доступ по SSH с паролем sudo.

- name: Base web server
  hosts: web
  become: true
  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: true

    - name: Ensure nginx is running at boot
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true
ansible -i inventory.ini web -m ansible.builtin.ping
ansible-playbook -i inventory.ini site.yml --check --diff
ansible-playbook -i inventory.ini site.yml

Модуль ping позволяет проверить работу SSH, Python и sudo перед началом отладки playbook. Успешный результат выглядит как web1 | SUCCESS => {"ping": "pong"}. Запуск --check --diff — это ближайший аналог плана выполнения в Ansible: он сообщает, какие изменения будут внесены, не применяя их на практике. Однако задачи, зависящие от предыдущих шагов, могут отображаться некорректно, так как предыдущие изменения фактически не были выполнены.

Каждый запуск завершается сводкой, например ok=6 changed=2 unreachable=0 failed=0. Запустите один и тот же playbook дважды. Второй запуск должен вернуть changed=0. Задача, которая сообщает об изменениях при каждом запуске, не является идемпотентной; обычно это задача command или shell, которую следовало реализовать с помощью штатного модуля. Если вы только начинаете, начните с первого Ansible playbook на одном VPS и постепенно расширяйте его.

Где инструменты пересекаются и где они конфликтуют

Terraform может выполнять команды на новом сервере с помощью провизионера remote-exec. В документации HashiCorp провизионеры названы крайним средством. На это есть веские причины.

Провизионер запускается только в момент создания ресурса. Если изменить скрипт, на существующем сервере ничего не произойдет, так как с точки зрения Terraform ресурс уже соответствует коду. Шаги провизионера никогда не отображаются в terraform plan, поэтому при проверке изменений вы их не увидите. Если скрипт завершится с ошибкой, Terraform пометит ресурс как поврежденный (tainted), и при следующем запуске apply сервер, который, вероятно, был исправен, будет удален и создан заново.

Сбой также может произойти в неудачный момент. Провайдер сообщает о создании сервера сразу после ответа API, в то время как операционная система еще загружается, а sshd еще не слушает порт.

Error: remote-exec provisioner error
timeout - last error: dial tcp 203.0.113.10:22: connect: connection refused

У Ansible есть обратное искушение. Облачные модули могут создавать серверы, и для небольшого количества машин это работает. Но вы теряете граф зависимостей и файл состояния. Ansible без проблем создаст ресурс, но если удалить задачу из плейбука, ресурс продолжит работать и за него будут списываться средства, так как нигде не зафиксировано, что он принадлежит вам.

Правило, которое из этого следует: пусть Terraform управляет объектами, которые создаются и удаляются через API, а Ansible управляет всем, что находится внутри загруженной операционной системы.

Передача управления: успешная реализация

Передача управления — это граница, а не интеграция. Terraform завершает работу, публикует адрес и останавливается. Ansible начинает работу с этого адреса.

terraform apply -auto-approve
terraform output -raw web_ip
printf '[web]\n%s ansible_user=root\n' "$(terraform output -raw web_ip)" > inventory.ini
ansible -i inventory.ini web -m ansible.builtin.ping
ansible-playbook -i inventory.ini site.yml

terraform output -raw выводит одно значение без кавычек и без JSON-обёртки, что требуется при использовании подстановки команд в shell. Для нескольких серверов используйте terraform output -json и формируйте инвентарь на его основе, так как -raw обрабатывает только одну строку, число или логическое значение.

Шаг ping между двумя инструментами стоит сохранить. Он позволяет отделить ситуацию «Terraform выдал неверный адрес» от ситуации «в моём playbook есть ошибка», поскольку при запуске playbook сразу после создания сервера эти проблемы выглядят идентично.

Чтение состояния Terraform в качестве инвентаря Ansible

Если вы не хотите создавать файл инвентаря вручную, коллекция cloud.terraform позволяет считывать состояние напрямую.

ansible-galaxy collection install cloud.terraform

Создайте файл terraform.yml рядом с вашим playbook:

plugin: cloud.terraform.terraform_provider
project_path: /home/deploy/infra
ansible-inventory -i terraform.yml --graph
ansible-playbook -i terraform.yml site.yml

Перед использованием учтите два момента. Плагин выполняет terraform show в директории project_path, поэтому она должна быть предварительно инициализирована, иначе плагин завершится с ошибкой. Кроме того, он не создает хосты автоматически на основе ресурсов сервера: он считывает ресурсы ansible_host и ansible_group, которые вы объявляете в коде Terraform с помощью провайдера Ansible. В ansible-inventory --graph ничего не появится, пока вы их не добавите.

Обычный сгенерированный файл инвентаря проще отлаживать, и он работает с любым провайдером. Использование плагина становится оправданным, когда инвентарь вырастает до размеров, превышающих несколько машин, а ручное редактирование начинает приводить к опечаткам. Это тот же этап, на котором управление несколькими серверами Linux с одной управляющей машины превращается из привычки в полноценный рабочий процесс.

Действительно ли вам нужен Terraform?

Большинству читателей этого текста он не нужен, по крайней мере пока. Terraform окупает затраты на его внедрение, когда создание и удаление инфраструктуры становится повторяющейся задачей. Если вы арендовали один VPS через панель управления и планируете использовать его два года, Terraform лишь описывает действие, которое выполняется один раз, и создает файл состояния, который нельзя потерять.

Используйте Terraform, когда вы часто пересобираете окружения, когда staging должен в точности соответствовать production, когда несколько человек вносят изменения в инфраструктуру и вам нужен план для проверки перед удалением ресурсов, или когда вы управляете не только серверами, но и DNS-записями, балансировщиками нагрузки и правилами межсетевого экрана через API провайдера.

Ограничьтесь использованием Ansible, если серверов мало и они работают долго, а ежедневный вопрос звучит как «правильно ли настроен этот сервер», а не «существует ли этот сервер». Один playbook для первичной настройки сервера выполняет те же задачи, что и первые десять минут работы с новым VPS, но с преимуществом: он будет работать точно так же на следующем сервере.

Порядок обучения следует из этого принципа. Ansible приносит пользу уже на первом сервере. Terraform начинает окупаться на третьем пересобранном окружении.

Что нарушается при передаче управления

Сервер не готов. Terraform завершается успешно, а Ansible сразу выдает ошибку.

fatal: [web1]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 203.0.113.10 port 22: Connection refused", "unreachable": true}

API вернул адрес до того, как sshd начал прослушивание порта. Дождитесь открытия порта вместо добавления фиксированной задержки через sleep. В Ansible для этого есть ansible.builtin.wait_for_connection, выполните его как первую задачу в play. Когда один и тот же playbook применяется к группе хостов, а не к одной новой машине, заранее определите что должно происходить, если один из хостов остается недоступным, так как Ansible исключает такой хост из дальнейшего выполнения, и информация об этом будет только в итоговой строке.

Изменился ключ хоста. Вы удалили и заново создали сервер, и новый сервер отвечает по тому же адресу с новым ключом.

Host key verification failed.

Удалите устаревшую запись с помощью ssh-keygen -R 203.0.113.10. Это происходит постоянно, если Terraform выполняет пересборку инфраструктуры, поэтому лучше избегать частых пересозданий на машинах, где хранятся данные.

Sudo завершается с ошибкой. fatal: [web1]: FAILED! => {"msg": "Missing sudo password"} означает, что become: true требует пароль на этом хосте. Либо настройте sudo без пароля для пользователя, под которым выполняется развертывание, либо используйте флаг --ask-become-pass.

Terraform пытается удалить то, что вы не меняли. План показывает изменения, которые вы не вносили. Это означает, что реальная инфраструктура разошлась с кодом, обычно из-за того, что кто-то изменил настройки в веб-панели провайдера. Запустите terraform plan -refresh-only, чтобы увидеть разницу, а затем решите, что неверно: код или текущий ресурс. Никогда не применяйте деструктивный план, если не можете объяснить каждую его строку.

Ansible сообщает об изменениях при каждом запуске. Задача shell без проверки creates или when выполняется безусловно. Это не просто косметическая проблема: вы больше не сможете использовать changed=0 как сигнал того, что сервер находится в требуемом состоянии.

FAQ

Может ли Terraform заменить Ansible?

Нет, если речь идет о настройке внутри сервера. Terraform может вызывать скрипты через provisioner remote-exec, но они выполняются только при создании ресурса, не отображаются в terraform plan и помечают ресурс как поврежденный при сбое, что приводит к его удалению и пересозданию при следующем запуске. В Terraform нет аналога модуля, который проверяет, установлен ли уже nginx, и ничего не делает, если это так. Используйте Terraform для создания машины, а затем передавайте управление Ansible.

Может ли Ansible заменить Terraform?

Для небольшого количества серверов с длительным сроком службы — да. У Ansible есть облачные модули для создания серверов, и если вы арендуете два VPS и используете их постоянно, этого достаточно. Вы теряете файл состояния и граф зависимостей: если удалить задачу из playbook, ресурс продолжит работать и потреблять средства, так как Ansible не фиксирует факт его создания. Terraform в такой ситуации запланировал бы удаление.

Что изучать в первую очередь?

Ansible, если у вас уже есть серверы. Он окупается на первой же машине, не требует ничего, кроме SSH, и эти навыки применимы к серверу, который вы настроили вручную. Terraform окупается позже, когда вы начинаете многократно пересобирать окружения или управлять ресурсами провайдера помимо серверов, например, DNS-записями и правилами межсетевого экрана.

Как передать IP нового сервера из Terraform в Ansible?

Объявите output в коде Terraform, а затем считайте его после применения конфигурации. terraform output -raw web_ip выводит чистое значение для подстановки в оболочке, а terraform output -json выдает все выходные данные сразу, если хостов несколько. Запишите их в файл инвентаризации или установите коллекцию cloud.terraform и укажите ansible-inventory -i terraform.yml --graph на каталог проекта.

Почему мой playbook завершается с ошибкой сразу после завершения работы Terraform?

Провайдер сообщает о создании сервера сразу после ответа API, в то время как операционная система еще загружается, поэтому в первые секунды соединение по SSH отклоняется. Ошибка выглядит как UNREACHABLE! с Connection refused. Сделайте ansible.builtin.wait_for_connection первой задачей в play, вместо того чтобы угадывать время ожидания, так как время загрузки зависит от образа и тарифного плана.