linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
Intro
Lessons
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Уроки
  • How it works
  • База знаний
  • Шпаргалка
  • Capstone
  • Собеседование
home/terraform/lessons/tf-production-01-fmt-validate-tflint

lesson ── terraform-production ── ~14 мин ── 6 шагов

Линтеры, fmt, validate, tflint

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 минут, без регистрации.

запустить sandbox →

stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя

Шаги

  1. 01

    Положи нарочно-нечистый HCL

    bash
    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 положен. Сейчас покажем как линтеры это видят.

  2. 02

    terraform fmt -check ловит беспорядок

    bash
    terraform fmt -check
    echo "exit: $?"

    Должно показать список нечистых файлов и exit 3:

    main.tf
    exit: 3

    -check НЕ исправляет, только репортит. В pre-commit обычно без -check (auto-fix), в CI, с -check (gate). См. tf-fmt.

    Запусти теперь без флага, auto-fix:

    bash
    terraform fmt
    cat main.tf

    Файл выровнен. Никакого ={}=, отступы стабильные.

    ✓ fmt отнормировал HCL. Это и есть его работа.

  3. 03

    Сломай ссылку, пусть validate отловит

    Поменяй output чтобы ссылался на несуществующий атрибут:

    bash
    sed -i 's/aws_s3_bucket\.demo\.bucket/aws_s3_bucket.demo.nonexistent/' main.tf
    cat main.tf

    Validate без облака:

    bash
    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'е через минуту.

    Откатим:

    bash
    sed -i 's/aws_s3_bucket\.demo\.nonexistent/aws_s3_bucket.demo.bucket/' main.tf
    terraform validate

    Должно сказать «Success!».

    ✓ validate подтвердил конфиг. Идём дальше, tflint.

  4. 04

    tflint и его AWS-плагин

    tflint без плагинов проверяет только generic-rules. Для AWS-specifics нужен tflint-ruleset-aws. Конфиг, .tflint.hcl:

    bash
    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-плагин. Теперь запустим проверку.

  5. 05

    tflint находит провайдер-specific проблемы

    Запусти на текущем коде:

    bash
    tflint --no-color
    echo "exit: $?"

    Скорее всего, нет ошибок, HCL простой. Добавим заведомо плохой ресурс, aws_instance с несуществующим типом:

    bash
    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-плагина, она знает все типы.

    Уберём:

    bash
    sed -i '/aws_instance "bad"/,/^}$/d' main.tf
    tflint --no-color && echo "tflint clean"

    ✓ tflint ловит provider-проблемы, которых validate не видит.

    То же самое на OpenTofu

    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 для полной матрицы.

    • → OpenTofu parity
  6. 06

    Все три в одном скрипте

    Канонический lint-pipeline:

    bash
    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.

    Что tflint умеет помимо invalid_type

    Базовые 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).

    Конфиг для обязательных тегов:

    hcl
    rule "aws_resource_missing_tags" {
      enabled = true
      tags    = ["CostCenter", "Environment"]
    }

    Это, gate бизнес-политики на уровне линтера.

    • → terraform fmt
    • → terraform validate
    • → Линтеры в CI

Что ты узнал

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'ы.

концепции

  • · fmt, деформативный (auto-fix локально), но -check режим только проверяет
  • · validate работает после init, может работать без backend
  • · tflint конфигурируется через .tflint.hcl, конкретные правила и provider-plugins

← предыдущий

Свой первый модуль: выноси S3 в reusable

следующий →

CDKTF, Terraform из TypeScript

Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки