Terraform vs Pulumi: IaC-инструменты — HCL или настоящий код
Infrastructure as Code давно стал стандартом, но выбор инструмента по-прежнему вызывает споры. Terraform с его HCL — проверенный лидер. Pulumi предлагает писать инфраструктуру на TypeScript, Python или Go — без нового языка. Разберём, чем они отличаются на практике и когда какой выбрать.
Философия: декларативный HCL vs настоящий код
Terraform использует HCL — декларативный DSL, где вы описываете желаемое состояние:
resource "aws_instance" "api" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.medium"
tags = {
Name = "api-server"
Environment = var.environment
}
}
Pulumi позволяет использовать обычный язык программирования:
import * as aws from "@pulumi/aws";
const api = new aws.ec2.Instance("api", {
ami: "ami-0c55b159cbfafe1f0",
instanceType: "t3.medium",
tags: {
Name: "api-server",
Environment: config.require("environment"),
},
});
На простых примерах разница минимальна. Она проявляется при сложной логике: циклы, условия, динамическая генерация ресурсов. В HCL это for_each, count, dynamic блоки — работает, но читается тяжело. В Pulumi — обычный for, if, функции.
State management
Terraform хранит state в файле terraform.tfstate. Для команды нужен remote backend:
terraform {
backend "s3" {
bucket = "myorg-terraform-state"
key = "production/api.tfstate"
region = "eu-west-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
Вы сами управляете S3-бакетом, DynamoDB для блокировок, шифрованием. State содержит чувствительные данные — нужна строгая политика доступа.
Pulumi предлагает managed backend (Pulumi Cloud) из коробки или self-hosted (S3, Azure Blob, GCS). Pulumi Cloud автоматически шифрует секреты и управляет блокировками. Но это зависимость от SaaS — для некоторых команд стоп-фактор.
Модули и переиспользование
Terraform modules — директории с .tf файлами, параметризованные через variables:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.5.0"
name = "production"
cidr = "10.0.0.0/16"
azs = ["eu-west-1a", "eu-west-1b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
}
Pulumi использует обычные классы и функции:
class VpcStack {
public vpc: aws.ec2.Vpc;
public privateSubnets: aws.ec2.Subnet[];
constructor(name: string, opts: VpcOptions) {
this.vpc = new aws.ec2.Vpc(`${name}-vpc`, {
cidrBlock: opts.cidr,
enableDnsHostnames: true,
});
this.privateSubnets = opts.azs.map((az, i) =>
new aws.ec2.Subnet(`${name}-private-${i}`, {
vpcId: this.vpc.id,
cidrBlock: opts.privateSubnets[i],
availabilityZone: az,
})
);
}
}
Преимущество Pulumi: наследование, дженерики, интерфейсы. Terraform modules ограничены плоской структурой variables/outputs.
Тестирование
Terraform: terraform validate (синтаксис), terraform plan (предпросмотр), terratest (Go, интеграционные тесты с реальными ресурсами), terraform test (встроенный с 1.6, assertions на plan).
Pulumi — unit-тесты на родном языке без создания ресурсов:
import { describe, it, expect } from "vitest";
describe("API infrastructure", () => {
it("should use t3.medium instance type", async () => {
const instance = new aws.ec2.Instance("test", {
instanceType: "t3.medium",
ami: "ami-xxx",
});
const type = await new Promise<string>(resolve =>
instance.instanceType.apply(resolve)
);
expect(type).toBe("t3.medium");
});
});
Unit-тесты Pulumi работают через mocking — быстрее и дешевле, чем terratest с реальной инфраструктурой.
Экосистема
┌────────────────┬──────────────────┬──────────────────┐
│ │ Terraform │ Pulumi │
├────────────────┼──────────────────┼──────────────────┤
│ Providers │ 4000+ (registry) │ 150+ native + │
│ │ │ все TF providers │
│ Язык │ HCL │ TS, Python, Go, │
│ │ │ C#, Java, YAML │
│ GitHub Stars │ ~43k │ ~22k │
│ Вакансии │ Значительно больше│ Растёт │
└────────────────┴──────────────────┴──────────────────┘
Pulumi может использовать любой Terraform provider через bridge — экосистема провайдеров фактически общая. Но native Pulumi providers дают лучший DX с автодополнением и типизацией.
Когда что выбрать
Terraform:
- Команда уже знает HCL и имеет наработанные модули.
- Инфраструктура стандартная, без сложной логики.
- Важен найм — специалистов по Terraform на рынке больше.
- Нужна максимальная зрелость и предсказуемость.
Pulumi:
- Команда разработчиков, не желающих учить DSL.
- Сложная инфраструктура: динамическая генерация, абстракции.
- Нужны unit-тесты без реальных ресурсов.
- Стек на TypeScript/Python — единый язык для приложения и инфраструктуры.
Вывод
Terraform — проверенный стандарт с огромной экосистемой. Pulumi — современная альтернатива для команд, которые хотят писать инфраструктуру на знакомом языке с полноценным тестированием. Если начинаете с нуля и команда сильна в TypeScript — попробуйте Pulumi. Если нужна стабильность и широкий найм — Terraform остаётся безопасным выбором.