lesson ── terraform-production ── ~14 мин ── 6 шагов
Production-трек начинается с гигиены. Три инструмента, без которых
серьёзная команда не работает: terraform fmt -check (форматирование как
gate), terraform validate (синтаксис и грубые ошибки), tflint
(стиль и provider-specific lints). Все три быстрые, все три должны
быть в pre-commit и CI.
интерактивный sandbox
Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.
stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя
cd /home/student/tf-lint
cat > main.tf <<'EOF'
resource "aws_s3_bucket" "demo"{bucket = "linuxlab-lint-demo"
tags={Owner="student"}}
output "name" {value=aws_s3_bucket.demo.bucket
}
EOF
Файл содержит: лишние пробелы, прижатые скобки, плохие отступы,
tags={...} без пробелов. Чистый антипаттерн.
✓ Грязный HCL положен. Сейчас покажем как линтеры это видят.
terraform fmt -check
echo "exit: $?"
Должно показать список нечистых файлов и exit 3:
main.tf
exit: 3
-check НЕ исправляет, только репортит. В pre-commit обычно без
-check (auto-fix), в CI, с -check (gate). См. tf-fmt.
Запусти теперь без флага, auto-fix:
terraform fmt
cat main.tf
Файл выровнен. Никакого ={}=, отступы стабильные.
✓ fmt отнормировал HCL. Это и есть его работа.
Поменяй output чтобы ссылался на несуществующий атрибут:
sed -i 's/aws_s3_bucket\.demo\.bucket/aws_s3_bucket.demo.nonexistent/' main.tf
cat main.tf
Validate без облака:
terraform init -backend=false -input=false
terraform validate
Должно показать что-то вроде:
Error: Unsupported attribute
on main.tf line N: ...
This object has no argument, nested block, or exported attribute named "nonexistent".
validate понимает schema провайдера и ловит typo. Без него
это всплыло бы только на plan'е через минуту.
Откатим:
sed -i 's/aws_s3_bucket\.demo\.nonexistent/aws_s3_bucket.demo.bucket/' main.tf
terraform validate
Должно сказать «Success!».
✓ validate подтвердил конфиг. Идём дальше, tflint.
tflint без плагинов проверяет только generic-rules. Для AWS-specifics
нужен tflint-ruleset-aws. Конфиг, .tflint.hcl:
cat > .tflint.hcl <<'EOF'
plugin "aws" {enabled = true
version = "0.32.0"
source = "github.com/terraform-linters/tflint-ruleset-aws"
}
rule "terraform_naming_convention" {enabled = true
}
rule "terraform_required_version" {enabled = true
}
EOF
tflint --init
--init подтягивает плагин (это сетевой запрос). Должно сказать
«Installing aws plugin».
✓ tflint поставил AWS-плагин. Теперь запустим проверку.
Запусти на текущем коде:
tflint --no-color
echo "exit: $?"
Скорее всего, нет ошибок, HCL простой. Добавим заведомо плохой
ресурс, aws_instance с несуществующим типом:
cat >> main.tf <<'EOF'
resource "aws_instance" "bad" {ami = "ami-foobar"
instance_type = "t2.bogus"
}
EOF
tflint --no-color
echo "exit: $?"
Должно показать что-то типа aws_instance_invalid_type: "t2.bogus" is an invalid instance type. Это специфика AWS-плагина, она знает
все типы.
Уберём:
sed -i '/aws_instance "bad"/,/^}$/d' main.tf
tflint --no-color && echo "tflint clean"
✓ tflint ловит provider-проблемы, которых validate не видит.
OpenTofu держит CLI и state совместимыми с Terraform по командам
этого шага: миграция обычно проходит через mv .terraform .terraform.bak; tofu init -upgrade. Но при первом переходе
сделай backup state и прогон на feature-branch - расхождения
концентрируются в новых фичах (variables в backend,
state-encryption, OCI registry-backed модули). См.
tf-opentofu-parity для полной матрицы.
Канонический lint-pipeline:
cat > lint.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
echo "==> fmt"
terraform fmt -check -recursive
echo "==> validate"
terraform init -backend=false -input=false -no-color > /dev/null
terraform validate -no-color
echo "==> tflint"
tflint --no-color
echo "All lints passed."
EOF
chmod +x lint.sh
./lint.sh
Любой шаг падает, exit 1, остальные не выполняются. Это базовый lint-job в CI. См. tf-fmt-validate-ci про подключение в pre-commit и GitHub Actions.
✓ Pipeline gate готов. Дальше, pre-commit.
Базовые rules без плагинов:
terraform_deprecated_interpolation, старый ${...} синтаксис.terraform_unused_declarations, variable/output, на которые
никто не ссылается.terraform_naming_convention, конвенция snake_case.terraform_required_version / terraform_required_providers
их отсутствие = warning.AWS-плагин:
aws_instance_invalid_type, aws_db_instance_invalid_type.aws_iam_policy_invalid_principal_format.aws_s3_bucket_name (длина, символы, конвенция).aws_resource_missing_tags, обязательные теги (включается
через config).Конфиг для обязательных тегов:
rule "aws_resource_missing_tags" {enabled = true
tags = ["CostCenter", "Environment"]
}
Это, gate бизнес-политики на уровне линтера.
fmt -check ломается на нечистом форматировании, validate, на синтаксисе и базовой схеме, tflint, на стилистике и provider-best-practices. В CI идут в одном job'е (lint), exit 1 на любом этапе валит весь PR.
команды
terraform fmt -check -recursiveпроверить, что HCL отформатирован. Exit 3 = есть разница.terraform init -backend=false && terraform validateсинтаксис без облака. -backend=false избегает остановки на отсутствии S3.tflint --init && tflint --recursivelint всех директорий. --init подтягивает plugin'ы.концепции