Python asyncio + aiohttp: пишем высоконагруженный HTTP-клиент правильно
Infrastructure as Code давно стал стандартом, но выбор инструмента по-прежнему вызывает споры. Terraform с его HCL — проверенный лидер. Pulumi предлагает писать инфраструктуру на TypeScript, Python или Go — без нового языка. Разберём, чем они отличаются на практике и когда какой выбрать.
Философия: декларативный HCL vs настоящий код
Terraform использует HCL (HashiCorp Configuration Language) — декларативный DSL, где вы описываете желаемое состояние:
resource "aws_instance" "api" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.medium"
tags = {
Name = "api-server"
Environment = var.environment
}
}
resource "aws_security_group" "api" {
name = "api-sg"
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
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"),
},
});
const sg = new aws.ec2.SecurityGroup("api-sg", {
ingress: [{
fromPort: 443,
toPort: 443,
protocol: "tcp",
cidrBlocks: ["0.0.0.0/0"],
}],
});
На простых примерах разница минимальна. Она проявляется при сложной логике: циклы, условия, динамическая генерация ресурсов. В 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):
# Managed backend (по умолчанию)
pulumi login
# Self-hosted S3
pulumi login s3://myorg-pulumi-state
# Локально (для экспериментов)
pulumi login --local
Pulumi Cloud автоматически шифрует секреты, управляет блокировками и показывает историю изменений в UI. Но это зависимость от 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"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
enable_nat_gateway = true
}
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,
})
);
}
}
// Использование
const network = new VpcStack("prod", {
cidr: "10.0.0.0/16",
azs: ["eu-west-1a", "eu-west-1b"],
privateSubnets: ["10.0.1.0/24", "10.0.2.0/24"],
});
Преимущество Pulumi: наследование, дженерики, интерфейсы — всё, что даёт язык. Terraform modules ограничены плоской структурой variables/outputs.
Тестирование
Terraform — тестирование через внешние инструменты:
terraform validate— синтаксис.terraform plan— предпросмотр изменений.terratest(Go) — интеграционные тесты, реально создающие ресурсы.terraform test(встроенный с 1.6) — assertions на plan output.
Pulumi — тесты на родном языке:
import * as pulumi from "@pulumi/pulumi";
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 instanceType = await new Promise<string>((resolve) =>
instance.instanceType.apply(resolve)
);
expect(instanceType).toBe("t3.medium");
});
it("should tag all resources with environment", async () => {
// Policy test: все ресурсы должны иметь тег Environment
});
});
Unit-тесты Pulumi работают без реального создания ресурсов (mocking). Это быстрее и дешевле, чем terratest, который поднимает реальную инфраструктуру.
Экосистема: providers, registry, community
┌────────────────┬──────────────────┬──────────────────┐
│ │ Terraform │ Pulumi │
├────────────────┼──────────────────┼──────────────────┤
│ Providers │ 4000+ (registry) │ 150+ native + │
│ │ │ все TF providers │
│ Registry │ registry.terraform.io │ pulumi.com/registry │
│ Язык │ HCL │ TS, Python, Go, │
│ │ │ C#, Java, YAML │
│ GitHub Stars │ ~43k │ ~22k │
│ Вакансии │ Значительно больше│ Растёт │
│ Документация │ Обширная │ Хорошая │
└────────────────┴──────────────────┴──────────────────┘
Ключевой момент: Pulumi может использовать любой Terraform provider через bridge. Это значит, что экосистема провайдеров фактически общая. Но native Pulumi providers (AWS, Azure, GCP, Kubernetes) дают лучший developer experience с автодополнением и типизацией.
Когда что выбрать
Выбирайте Terraform, если:
- Команда уже знает HCL и имеет наработанные модули.
- Нужна максимальная стабильность и предсказуемость (Terraform зрелее).
- Инфраструктура относительно простая — стандартные ресурсы без сложной логики.
- Важен найм — специалистов по Terraform на рынке значительно больше.
Выбирайте Pulumi, если:
- Команда — разработчики, которые не хотят учить ещё один DSL.
- Инфраструктура сложная: динамическая генерация ресурсов, условная логика, абстракции.
- Нужны полноценные unit-тесты без поднятия реальных ресурсов.
- Стек уже на TypeScript/Python — единый язык для приложения и инфраструктуры.
- Важна типизация и автодополнение в IDE.
Вывод
Terraform — проверенный стандарт с огромной экосистемой и предсказуемым поведением. Pulumi — современная альтернатива для команд, которые хотят писать инфраструктуру на знакомом языке с полноценным тестированием. Оба инструмента решают одну задачу, но подходят разным командам. Если начинаете с нуля и команда сильна в TypeScript — попробуйте Pulumi. Если нужна стабильность и широкий найм — Terraform остаётся безопасным выбором.