Что это
CDKTF, генератор HCL из кода. Пишешь на одном из языков:
- TypeScript / JavaScript (основной)
- Python
- Java
- C#
- Go
Запускаешь cdktf synth, на выходе папка cdktf.out/stacks/<stack>/
с обычным HCL (cdk.tf.json). Дальше, terraform init && plan
как обычно (или cdktf deploy, который делает то же самое из CDKTF).
Идея, Terraform-провайдеры остаются те же, state остаётся terraform-state, но HCL пишется кодом.
Минимальный пример (TypeScript)
cdktf init --template=typescript --local
Генерится main.ts:
import { App, TerraformStack } from "cdktf";import { Construct } from "constructs";import { AwsProvider } from "./.gen/providers/aws/provider";import { S3Bucket } from "./.gen/providers/aws/s3-bucket";class MyStack extends TerraformStack { constructor(scope: Construct, name: string) {super(scope, name);
new AwsProvider(this, "aws", { region: "us-east-1" }); new S3Bucket(this, "logs", {bucket: "linuxlab-cdktf-logs",
tags: { ManagedBy: "cdktf" },});
}
}
const app = new App();
new MyStack(app, "main");
app.synth();
Запуск:
cdktf get # подтягивает type-bindings для провайдеров
cdktf synth # генерит HCL в cdktf.out/
cdktf deploy main # apply
Что синтезируется
cdktf.out/stacks/main/cdk.tf.json:
{ "terraform": { "required_providers": {"aws": {...}}},
"provider": { "aws": [{"region": "us-east-1"}]},
"resource": { "aws_s3_bucket": { "logs": {"bucket": "linuxlab-cdktf-logs",
"tags": {"ManagedBy": "cdktf"}}
}
}
}
Это обычный JSON-HCL. Никаких CDKTF-специфик в облаке.
Когда CDKTF оправдан
Программируемая генерация
100 одинаковых stack'ов из CSV:
const tenants = require("./tenants.json");tenants.forEach((tenant: any) => { new TenantStack(app, `tenant-${tenant.id}`, {name: tenant.name,
tier: tenant.tier,
});
});
В HCL это была бы куча terraform.tfvars или for_each, но без типов
и без if'ов на бизнес-логике.
Сложная условная логика
if (config.env === "prod" && config.region.startsWith("eu-")) { new GDPRComplianceModule(this, "gdpr", { ... });}
В HCL, count = ... ? 1 : 0 с кучей условий. На TypeScript, читается.
Переиспользование через классы
class AuditedBucket extends Construct { constructor(scope: Construct, name: string, props: AuditedBucketProps) {super(scope, name);
new S3Bucket(this, "bucket", { /* ... */ }); new S3BucketVersioningA(this, "versioning", { /* ... */ }); new S3BucketPublicAccessBlock(this, "pab", { /* ... */ });}
}
new AuditedBucket(this, "logs", { name: "audit-logs" });Это аналог Terraform-модуля, но с типами и наследованием.
Когда CDKTF, НЕ оправдан
Маленький проект
Один stack, 50 ресурсов, без сложной логики, нативный HCL понятнее и короче. CDKTF добавляет step'ы (init, get, synth, deploy) и build-зависимости (node_modules, 500 MB+).
Команда не знает TypeScript/Python
Reviewer ревьюит и HCL, и TypeScript. Если последнего никто не знает
плохая идея. Reviewing 200-line .ts сложнее, чем .tf.
Хочешь использовать community-modules
Большинство Terraform Registry modules написаны на HCL. Использовать
их из CDKTF можно (TerraformHclModule), но workflow менее естественный.
Структура проекта
my-cdktf/
├── main.ts # entrypoint
├── stacks/
│ ├── network.ts
│ ├── compute.ts
│ └── data.ts
├── constructs/
│ ├── audited-bucket.ts
│ └── vpc-with-flow-logs.ts
├── cdktf.json # язык, providers, build
├── package.json
└── cdktf.out/ # generated HCL (gitignore)
В cdktf.json:
{"language": "typescript",
"app": "npx ts-node main.ts",
"terraformProviders": ["aws@~> 5.60", "random@~> 3.6"],
"terraformModules": [],
"context": {}}
Tests
Тесты, обычные Jest/pytest. CDKTF предоставляет helpers:
import { Testing } from "cdktf";test("bucket has correct name", () => { const synth = Testing.synthScope((scope) => {new MyStack(scope, "test");
});
expect(synth).toHaveResourceWithProperties(S3Bucket, {bucket: "linuxlab-cdktf-logs",
});
});
Это assertion на сгенерированный JSON. Быстро, никакого облака.
Подводные камни
-
cdktf getнужен после смены провайдеров. Type-bindings генерятся локально; добавил новый provider вcdktf.json→cdktf get. Без него TypeScript не видит типы. -
node_modules/тяжёлый. 500-1500 MB на средний проект. В Docker билде CI медленный безnpm ci --omit=dev. -
HCL-generated читать тяжело. Синтезированный JSON неотформатирован под человека; debug через
cdktf synth && cat cdktf.out/.../cdk.tf.json | jq, не самый приятный. -
State files те же. CDKTF не создаёт собственный state; использует
terraform.tfstate. Это плюс (миграция назад в HCL возможна), но означает что remote backend настраивается так же. -
Terraform-фичи не на 1:1.
moved/removed/importблоки в CDKTF поддерживаются, но менее идиоматично. Сложныеdynamicблоки могут потребоватьescapeHatch. -
Не путать с AWS CDK. AWS CDK генерит CloudFormation; CDKTF генерит Terraform. Похожий синтаксис, разный backend.
-
Performance:
cdktf synthна больших проектах, секунды-минуты. На каждом CI-run перегенерация. Для 1000+ ресурсов делается кэширование generated-HCL.