Terraform vs Ansible: когда что использовать
“Terraform или Ansible?” — один из самых частых вопросов, которые мне задают. И ответ почти всегда: “Оба”. Это не конкуренты, а инструменты для разных задач, которые отлично работают вместе. Давайте разберёмся, где проходит граница.
Философия: декларативный vs процедурный
Terraform — декларативный. Вы описываете желаемое состояние инфраструктуры, а Terraform сам вычисляет, что нужно сделать, чтобы его достичь. Создать сервер, удалить диск, изменить DNS-запись — всё это Terraform решает сам на основе разницы между текущим и целевым состоянием.
Ansible — преимущественно процедурный, хотя многие модули идемпотентны. Вы описываете последовательность шагов: установи пакет, скопируй файл, перезапусти сервис. Ansible выполняет их по порядку.
На практике это означает: Terraform знает, что “сервер уже существует” и не будет его пересоздавать. Ansible знает, что “nginx уже установлен” и не будет его переустанавливать. Но Terraform мыслит целиком инфраструктурой, а Ansible — задачами на конкретной машине.
# Terraform: "Хочу сервер с такими параметрами"
resource "hcloud_server" "web" {
name = "web-01"
server_type = "cx22"
image = "ubuntu-24.04"
location = "fsn1"
ssh_keys = [hcloud_ssh_key.default.id]
public_net {
ipv4_enabled = true
ipv6_enabled = true
}
}
resource "hcloud_rdns" "web" {
server_id = hcloud_server.web.id
ip_address = hcloud_server.web.ipv4_address
dns_ptr = "web-01.example.com"
} # Ansible: "Настрой этот сервер так"
- name: Configure web server
hosts: web_servers
become: true
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
- name: Deploy nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/default
notify: Restart nginx
- name: Ensure nginx is running
ansible.builtin.systemd:
name: nginx
state: started
enabled: true Видите разницу? Terraform создаёт ресурс в облаке. Ansible настраивает то, что уже существует.
Terraform: провижининг инфраструктуры
Terraform блестяще справляется с облачными ресурсами:
- Виртуальные машины — Hetzner, AWS, DigitalOcean, любой провайдер
- Сети — VPC, подсети, firewall rules, load balancers
- DNS — записи в Cloudflare, Route53, любом DNS-провайдере
- Хранилище — S3-бакеты, блочные диски, managed databases
- Managed-сервисы — Kubernetes кластеры, managed PostgreSQL, Redis
Ключевая фича — state. Terraform хранит текущее состояние инфраструктуры в файле terraform.tfstate. Это позволяет ему точно знать, что существует, что изменилось и что нужно удалить:
$ terraform plan
# hcloud_server.web will be updated in-place
~ resource "hcloud_server" "web" {
~ server_type = "cx22" -> "cx32"
# (6 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy. terraform plan — одна из лучших вещей в Terraform. Вы видите, что произойдёт, до того как оно произойдёт. Никаких сюрпризов.
Но state — это и ахиллесова пята. Потеряли tfstate — Terraform больше не знает о вашей инфраструктуре. Поэтому state всегда хранят в remote backend (S3, Consul, Terraform Cloud), никогда локально.
Ansible: конфигурация и управление
Ansible — мастер конфигурации уже существующих серверов:
- Установка и настройка софта — пакеты, конфиги, сервисы
- Управление пользователями — аккаунты, SSH-ключи, sudo
- Деплой приложений — git pull, docker compose up, systemd restart
- Оркестрация — выполнение задач на группах серверов в определённом порядке
- Ad-hoc команды — быстрые одноразовые действия на всём парке серверов
Ansible stateless — он не хранит состояние. Каждый запуск подключается к серверу, проверяет текущее состояние и приводит его к желаемому. Это и плюс (нечего терять), и минус (нет полной картины инфраструктуры).
# Полноценная роль для настройки сервера
- name: Harden SSH
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
- { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
- { regexp: '^#?Port ', line: 'Port 6622' }
notify: Restart sshd Где они пересекаются
Зона перекрытия существует, и это нормально:
- Terraform может выполнять скрипты через
provisioner "remote-exec", но это антипаттерн. Provisioners — escape hatch, не основной инструмент. - Ansible может создавать облачные ресурсы через модули
amazon.aws.ec2_instance,hetzner.hcloud.serverи подобные. Работает, но без state-файла вы не увидите полную картину.
Моё правило: если ресурс имеет lifecycle в облаке (создаётся, изменяется, удаляется через API провайдера) — это Terraform. Если речь о конфигурации внутри сервера — это Ansible.
Реальный рабочий процесс
Вот как это выглядит на практике в моих проектах:
Шаг 1: Terraform создаёт инфраструктуру.
# main.tf
resource "hcloud_server" "app" {
name = "app-01"
server_type = "cx22"
image = "ubuntu-24.04"
location = "fsn1"
ssh_keys = [hcloud_ssh_key.deploy.id]
}
resource "cloudflare_record" "app" {
zone_id = var.cloudflare_zone_id
name = "app"
content = hcloud_server.app.ipv4_address
type = "A"
proxied = false
}
# Генерируем inventory для Ansible
resource "local_file" "ansible_inventory" {
content = yamlencode({
all = {
hosts = {
app-01 = {
ansible_host = hcloud_server.app.ipv4_address
ansible_port = 22
ansible_user = "root"
}
}
}
})
filename = "${path.module}/../ansible/inventory/generated.yml"
} Шаг 2: Ansible настраивает сервер.
cd ansible
ansible-playbook -i inventory/generated.yml playbooks/setup.yml Terraform даже генерирует inventory-файл для Ansible — полная автоматизация. После terraform apply можно сразу запускать плейбук.
Сравнение по критериям
| Критерий | Terraform | Ansible |
|---|---|---|
| Основная задача | Provisioning | Configuration |
| Подход | Декларативный | Процедурный (с идемпотентностью) |
| Язык | HCL | YAML |
| Состояние | Хранит в tfstate | Stateless |
| Агент | Нет (API-вызовы) | Нет (SSH) |
| Планирование | terraform plan | --check --diff |
| Облачные ресурсы | Основная специализация | Возможно, но неудобно |
| Конфигурация ОС | Через provisioners (плохо) | Основная специализация |
| Кривая обучения | Средняя (HCL, state) | Низкая (YAML, SSH) |
| Сообщество модулей | Terraform Registry | Ansible Galaxy |
Управление состоянием
Это фундаментальное различие, и оно влияет на всё.
Terraform с tfstate:
# State хранится удалённо
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "eu-central-1"
}
}
# Можно посмотреть текущие ресурсы
$ terraform state list
hcloud_server.app
hcloud_server.vpn
cloudflare_record.app
cloudflare_record.vpn
# Можно импортировать существующие ресурсы
$ terraform import hcloud_server.legacy 12345678 Ansible без state:
# Ansible просто подключается и проверяет
$ ansible all -m ansible.builtin.setup --limit app-01
# Получаем facts: ОС, IP, диски, память...
# Для "инвентаризации" -- ad-hoc команды
$ ansible all -m ansible.builtin.shell -a "systemctl list-units --state=running" Когда что использовать
Используйте Terraform, когда:
- Создаёте серверы, сети, DNS, бакеты, базы данных
- Нужна полная картина инфраструктуры (state)
- Работаете с несколькими облачными провайдерами
- Хотите
planперед применением изменений
Используйте Ansible, когда:
- Настраиваете софт на серверах (пакеты, конфиги, сервисы)
- Деплоите приложения
- Нужны ad-hoc команды на группе серверов
- Управляете пользователями, SSH-ключами, firewall-правилами на уровне ОС
Используйте оба, когда:
- У вас production-инфраструктура любого масштаба. Terraform создаёт, Ansible настраивает. Это не усложнение — это правильное разделение ответственности.
Итого
Спор “Terraform vs Ansible” — ложная дихотомия. Это как спорить, что лучше: молоток или отвёртка. У каждого инструмента своя зона ответственности, и вместе они покрывают весь жизненный цикл инфраструктуры: от создания VPS в облаке до настройки последнего конфига на сервере.
Начните с того, что болит: если у вас уже есть серверы и нужно их настраивать — начните с Ansible. Если вы часто создаёте и удаляете облачные ресурсы — начните с Terraform. Рано или поздно вам понадобятся оба.