SSD Nodes Learn 🎉 VPS від $5.50/міс
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-07

Ansible чи Terraform: що вам потрібно?

Terraform створює VPS, Ansible налаштовує його. Дізнайтеся про реальний поділ, проблеми provisioners, команди передачі та коли достатньо лише 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 завантажує провайдер і записує lock-файл. 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. Якщо її втратити, Terraform більше не знатиме, що ці сервери належать вашій конфігурації, і під час наступного застосування спробує створити дублікати. Щойно команди починає виконувати більше однієї людини, зберігайте стан у віддаленому бекенді. Одночасне застосування змін двома людьми призводить до такого результату:

Error: Error acquiring the state lock

OpenTofu — це форк Terraform із такими самими командами й таким самим форматом файлів. Станом на July 2026 усе в цьому посібнику працює, якщо вводити tofu замість terraform.

Що насправді робить Ansible

Ansible не потребує агента чи API. Він відкриває SSH-з’єднання, копіює невеликий модуль Python на цільовий хост, запускає його та видаляє. Усе, до чого можна підключитися через SSH із паролем sudo, можна налаштувати за допомогою Ansible.

- 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 аналог плану: він показує, що змінилося б, але не вносить змін. Водночас завдання, які залежать від попередніх завдань, можуть неправильно звітувати в check mode, оскільки попередня зміна фактично не відбулася.

Кожен запуск завершується підсумком на кшталт ok=6 changed=2 unreachable=0 failed=0. Запустіть той самий playbook двічі. Під час другого запуску має бути зазначено changed=0. Завдання, яке повідомляє про зміну під час кожного запуску, не є ідемпотентним. Зазвичай це завдання command або shell, для якого слід було використати повноцінний модуль. Якщо ви лише починаєте працювати з Ansible, почніть із першого playbook Ansible на одному VPS і розширюйте його далі.

Де ці два інструменти перетинаються, а де конфліктують

Terraform може виконувати команди на новому сервері за допомогою provisioner remote-exec. У власній документації HashiCorp називає provisioner крайнім засобом. Для цього є вагомі причини.

Provisioner запускається лише під час створення ресурсу. Змініть скрипт — і на наявному сервері нічого не станеться, оскільки з погляду Terraform ресурс уже відповідає коду. Кроки provisioner ніколи не відображаються в terraform plan, тому під час перевірки конфігурації їх не видно. Якщо скрипт завершується з помилкою, Terraform позначає ресурс як пошкоджений, а під час наступного apply знищує та повторно створює сервер, який, імовірно, працював нормально.

Помилка також виникає в невдалий момент. Провайдер повідомляє, що сервер створено, щойно API повертає відповідь про це, тоді як операційна система ще завантажується, а sshd ще не приймає підключення.

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

В Ansible виникає протилежна спокуса. Хмарні модулі можуть створювати сервери, і для кількох машин це працює. Але ви втрачаєте граф залежностей і файл стану. Ansible без проблем створить ресурс, але якщо видалити завдання з playbook, ресурс продовжить працювати, а оплата за нього — нараховуватися, оскільки ніде не зафіксовано, що він належить вам.

З цього випливає таке правило: 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 і на його основі створіть inventory, оскільки -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 не потрібен, принаймні поки що. Terraform виправдовує витрати, коли створення та видалення інфраструктури є регулярним завданням. Якщо ви замовили один VPS через панель керування та плануєте користуватися ним два роки, Terraform описує одноразову операцію й додає файл стану, який не можна втратити.

Використовуйте Terraform, коли часто перебудовуєте середовища, коли staging має точно відповідати production, коли кілька людей змінюють інфраструктуру і перед видаленням будь-яких ресурсів потрібен план, який можна переглянути, або коли ви керуєте не лише серверами, а й DNS-записами, балансувальниками навантаження та правилами firewall, доступними через 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 почав прослуховувати порт. Дочекайтеся доступності порту замість додавання фіксованої паузи. В Ansible для цього є ansible.builtin.wait_for_connection. Запустіть його першим завданням play.

Ключ вузла змінився. Ви знищили та повторно створили сервер, і новий сервер відповідає за тією самою адресою, але має новий ключ.

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 і позначають ресурс як проблемний у разі помилки. Під час наступного apply це планує видалення та повторне створення ресурсу. У Terraform немає аналога модуля, який перевіряє, чи вже встановлено nginx, і нічого не робить, якщо це так. Використовуйте Terraform для створення машини, а потім передайте її Ansible.

Чи може Ansible замінити Terraform?

Для невеликої кількості серверів, які працюють тривалий час, так. В Ansible є cloud-модулі для створення серверів. Якщо ви замовили два VPS і плануєте їх зберегти, цього достатньо. Але ви втрачаєте файл стану та граф залежностей. Якщо видалити завдання з playbook, ресурс продовжить працювати й оплачуватися, оскільки Ansible не записує, що створив його. Terraform запланував би видалення.

Що вивчати спочатку?

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

Як передати нову IP-адресу сервера з Terraform в Ansible?

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

Чому мій playbook завершується помилкою одразу після завершення Terraform?

Провайдер повідомляє, що сервер створено, щойно це підтверджує його API, хоча операційна система ще завантажується. Тому протягом перших секунд SSH відхиляє підключення. Помилка має вигляд UNREACHABLE! з Connection refused. Зробіть ansible.builtin.wait_for_connection першим завданням у play, замість того щоб вгадувати тривалість затримки, оскільки час завантаження залежить від образу та плану.