Модуль 08 — IaC: Terraform / OpenTofu ⭐⭐⭐
Кликать в консоли — это любитель. Профи описывают всю инфру кодом. Воспроизводимость, версионирование, code review для инфры.
Ландшафт инструментов
| Инструмент | Когда |
|---|---|
| Terraform | Стандарт до 2023, сейчас под BSL-лицензией |
| OpenTofu ⭐ | Open-source форк после смены лицензии. Учи его — синтаксис идентичен |
| Pulumi | TS/Python/Go вместо HCL. Растёт, но рынок меньше |
| AWS CDK | Python/TS, генерирует CloudFormation. AWS-only |
| Terragrunt | Wrapper для Terraform/OpenTofu — для масштабирования (DRY) |
| Crossplane | K8s-native IaC. Будущее для GitOps-команд |
| CloudFormation | AWS native YAML. Legacy |
HashiCorp сменил лицензию Terraform на BSL. Linux Foundation запустил OpenTofu — open-source форк. Синтаксис идентичен. На вакансиях ещё долго будет «Terraform», но это синонимы. В новых проектах — часто OpenTofu.
HCL — язык Terraform
Структура проекта
infra/
├── modules/ # переиспользуемые модули
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ └── versions.tf
│ ├── eks/
│ └── rds/
└── envs/
├── dev/
│ ├── main.tf # вызовы модулей
│ ├── backend.tf
│ └── terraform.tfvars
├── staging/
└── prod/
Типичный main.tf
terraform {
required_version = ">= 1.6"
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
backend "s3" {
bucket = "my-tf-state-prod"
key = "envs/prod/terraform.tfstate"
region = "eu-west-1"
dynamodb_table = "tf-lock"
encrypt = true
kms_key_id = "alias/tf-state-key"
}
}
provider "aws" {
region = var.region
default_tags {
tags = {
Environment = var.environment
ManagedBy = "terraform"
Project = "myapp"
}
}
}
variable "environment" {
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Must be dev, staging, or prod."
}
}
locals {
common_tags = {
Environment = var.environment
Owner = "platform-team"
}
}
module "vpc" {
source = "../../modules/vpc"
cidr = "10.0.0.0/16"
azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
tags = local.common_tags
}
module "eks" {
source = "../../modules/eks"
cluster_name = "myapp-${var.environment}"
vpc_id = module.vpc.vpc_id
private_subnets = module.vpc.private_subnet_ids
tags = local.common_tags
}
output "cluster_endpoint" {
value = module.eks.cluster_endpoint
}
Команды
terraform init # инициализация, скачивание провайдеров
terraform fmt -recursive # форматирование
terraform validate # синтаксис
terraform plan # ★ что изменится. ВСЕГДА смотри.
terraform plan -out=tf.plan
terraform apply tf.plan # применить конкретный plan
terraform apply # plan + apply одной командой
terraform destroy # снести (осторожно)
terraform import aws_s3_bucket.b bucket-name # затащить существующий ресурс
terraform state list
terraform state show aws_s3_bucket.b
terraform state mv old_addr new_addr # переименование
terraform state rm aws_s3_bucket.b # удалить из state, не из облака
terraform refresh # синк state с реальностью
terraform output # значения output
State — критическая концепция
- Local state — только для лабораторий
- Remote state — обязательно в команде. S3 + DynamoDB на AWS:
- S3 — хранит state (с versioning, encryption)
- DynamoDB — locks для предотвращения parallel apply
- Terraform Cloud / HCP — managed
В state сохраняется ВСЁ что вернул API, включая пароли БД. Никогда не клади state в публичный git. S3 bucket — приватный, encryption ON, versioning ON, MFA Delete для prod.
Modules
Структура модуля
modules/vpc/
├── main.tf # ресурсы
├── variables.tf # входы
├── outputs.tf # выходы
├── versions.tf # версии terraform и провайдеров
├── README.md # документация (генерируется terraform-docs)
└── examples/ # примеры использования
Источники модулей
- Локальные:
source = "../modules/vpc" - Git:
source = "git::https://github.com/org/repo.git//modules/vpc?ref=v1.0.0" - Registry:
source = "terraform-aws-modules/vpc/aws" - S3, GCS, Mercurial
Pin версии: version = "~> 5.0" разрешает 5.x но не 6.0.
Public registry — сокровищница
registry.terraform.io — тысячи готовых модулей. Особенно: terraform-aws-modules (Anton Babenko) — production-ready модули для AWS.
Стратегии organizing
Workspaces — НЕ для production environments
Workspaces — для лабораторий и временных тестов. Не используй их для prod/dev — будет один state файл, разные namespace, легко перепутать.
Directory per environment ⭐ (рекомендуется)
См. структуру выше. Каждый env — своя директория, свой backend, свой state.
Terragrunt ⭐⭐ (для масштаба)
DRY-структура для десятков environments / regions / accounts. Один terragrunt.hcl в корне, остальное наследуется.
infra/
├── terragrunt.hcl # root config: backend, providers
├── _envcommon/ # общие настройки модулей
└── live/
├── prod/
│ ├── env.hcl # env-specific values
│ ├── eu-west-1/
│ │ ├── vpc/
│ │ │ └── terragrunt.hcl # inputs + include
│ │ └── eks/
│ └── us-east-1/
└── staging/
Тестирование
- terraform fmt — форматирование
- terraform validate — синтаксис
- tflint — линтер на best practices
- tfsec / Checkov / KICS — security сканирование
- terraform test (с TF 1.6+) — встроенные тесты
- Terratest (Go) — интеграционные тесты, поднимает реальную инфру
- OPA / Conftest — policy as code на Rego
Best practices
- Никогда не редактируй ресурсы вручную в облаке после
apply— drift убьёт нервы - Pin версии провайдеров и модулей
- Один state — одна логическая инфра. Не пихай всё в один файл
- terraform plan в CI на каждый PR — обязательно, с комментарием diff
- apply через CI с одобрением, не локально в проде
- No secrets in code — Vault/SSM/env vars (TF_VAR_*)
- for_each вместо count — стабильнее при удалении
- Naming convention единая для всех ресурсов и тегов
- Все ресурсы — с тегами (Environment, Owner, ManagedBy)
- Code review каждого PR с plan-выводом
CI/CD pipeline для Terraform
Стадии:
- fmt check
- validate
- tflint
- tfsec / Checkov
- plan (на PR — комментарий с диффом)
- apply (после merge в main, с approval для prod)
Инструменты автоматизации
- Atlantis ⭐ — open source бот для GitHub/GitLab. Комментарии
atlantis plan,atlantis applyв PR. - Terraform Cloud / HCP — managed, с UI
- Spacelift, Env0, Scalr — managed CI/CD для IaC
- GitHub Actions / GitLab CI — кастомные пайплайны
Drift detection
Drift — расхождение между state и реальностью (кто-то правил руками).
- Регулярный
terraform planбез apply (cron) - driftctl — open source инструмент
- AWS Config — параллельный мониторинг
- Spacelift, env0 — встроенный drift detection
Сертификация
HashiCorp Certified: Terraform Associate (003) — несложная, ценится. Срок действия 2 года.
Чек-лист
- ☐ Пишу модули с входами, выходами, README
- ☐ State в S3 + DynamoDB lock
- ☐ CI/CD c plan-комментариями в PR
- ☐ Знаю различия
countиfor_each - ☐ Использую
tfsecили Checkov - ☐ Понимаю
terraform import - ☐ Сертификация Terraform Associate (опц.)
Источники
- Книга: «Terraform: Up & Running» — Yevgeniy Brikman (3-е изд., 2022)
- Документация: HashiCorp Learn
- OpenTofu: opentofu.org
- Best practices: cloudposse.com
- Anton Babenko — творец AWS modules для community
IaC освоено. Дальше — CI/CD и GitOps.