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-intermediate-12-multi-env-layout

lesson ── terraform-intermediate ── ~18 мин ── 6 шагов

Multi-env: workspaces vs директории

Один и тот же сервис нужен в dev, stage, prod. Как разложить код, чтобы не дублировать HCL? Два подхода:

  1. Workspaces, один HCL, переключаешь terraform workspace. Простой, но опасный (легко сделать apply не в тот env).
  2. Directory per env, envs/dev/, envs/prod/. Каждый env, свой root с своим backend, общий код в модуле.

В этом уроке сделаешь оба, поймёшь tradeoff'ы.

▶ интерактивный sandbox

Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.

запустить sandbox →

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

Шаги

  1. 01

    Вариант 1: workspaces

    bash
    cd /home/student/tf-envs/workspaces-style
    cat > main.tf <<'EOF'
    resource "random_id" "suffix" {
      byte_length = 4
    }
    locals {
      env = terraform.workspace
    }
    resource "aws_s3_bucket" "demo" {
      bucket = "linuxlab-${local.env}-${random_id.suffix.hex}"
      tags = {
        Environment = local.env
      }
    }
    output "current_workspace" {
      value = terraform.workspace
    }
    EOF
    terraform init

    Создай два workspace:

    bash
    terraform workspace new dev
    terraform workspace new prod
    terraform workspace list

    Звёздочка указывает активный.

    Workspaces, это отдельные state'ы в одном backend. При local backend state живёт в terraform.tfstate.d/<workspace>/. При S3, с разными key.

    ✓ Два workspace созданы. Каждый: свой state.

  2. 02

    Apply в обоих workspace'ах

    Переключи на dev и применит:

    bash
    terraform workspace select dev
    terraform workspace show
    terraform apply -auto-approve
    terraform output current_workspace

    Должно создаться: бакет с именем linuxlab-dev-<hash>.

    Переключи на prod:

    bash
    terraform workspace select prod
    terraform workspace show
    terraform apply -auto-approve
    terraform output current_workspace

    Создался другой бакет: linuxlab-prod-<hash>. State у этих двух workspaces разные, поэтому каждый создаёт свой ресурс.

    Проверь:

    bash
    aws --endpoint-url=http://localstack:4566 s3 ls

    Видишь оба бакета, linuxlab-dev-... и linuxlab-prod-....

    ✓ Workspaces изолировали state: два разных бакета из одного HCL.

  3. 03

    Опасность workspaces: apply не в тот env

    Главная проблема workspaces, легко перепутать активный.

    Сценарий: ты работаешь в dev, переключился в prod чтобы посмотреть что-то, забыл переключиться обратно. Делаешь terraform apply, применил dev-изменения к prod-state.

    Защита, precondition на data-source external который проверяет workspace:

    hcl
    check "workspace_match" {
      assert {
        condition     = terraform.workspace != "default"
        error_message = "Apply на 'default' workspace запрещён: выбери dev/stage/prod."
      }
    }

    Это часть «защитного пояса». В большой команде workspaces для prod, не используются, чтобы исключить эту ошибку. Для feature-branch экспериментов в локальном dev, ок.

    Возвращайся в dev:

    bash
    terraform workspace select dev

    ✓ Опасность понятна. В проде: directory style.

  4. 04

    Вариант 2: общий модуль для dirs-style

    bash
    mkdir -p /home/student/tf-envs/dirs-style/modules/app
    cat > /home/student/tf-envs/dirs-style/modules/app/main.tf <<'EOF'
    resource "random_id" "suffix" {
      byte_length = 4
    }
    resource "aws_s3_bucket" "demo" {
      bucket = "linuxlab-${var.env}-${random_id.suffix.hex}"
      tags = {
        Environment = var.env
      }
    }
    output "bucket_arn" {
      value = aws_s3_bucket.demo.arn
    }
    EOF
    cat > /home/student/tf-envs/dirs-style/modules/app/variables.tf <<'EOF'
    variable "env" {
      type = string
      validation {
        condition     = contains(["dev", "stage", "prod"], var.env)
        error_message = "env must be dev, stage, or prod."
      }
    }
    EOF

    Это переиспользуемый модуль app. Принимает env, создаёт бакет с правильным именем.

    Теперь env-roots:

    ✓ Модуль app описан. Теперь: root'ы по средам.

  5. 05

    Root'ы dev и prod

    bash
    cat > /home/student/tf-envs/dirs-style/envs/dev/main.tf <<'EOF'
    module "app" {
      source = "../../modules/app"
      env    = "dev"
    }
    output "bucket_arn" {
      value = module.app.bucket_arn
    }
    EOF
    cat > /home/student/tf-envs/dirs-style/envs/prod/main.tf <<'EOF'
    module "app" {
      source = "../../modules/app"
      env    = "prod"
    }
    output "bucket_arn" {
      value = module.app.bucket_arn
    }
    EOF

    Применяем dev:

    bash
    cd /home/student/tf-envs/dirs-style/envs/dev
    terraform init
    terraform apply -auto-approve
    terraform output bucket_arn

    Применяем prod:

    bash
    cd /home/student/tf-envs/dirs-style/envs/prod
    terraform init
    terraform apply -auto-approve
    terraform output bucket_arn

    У каждого env, свой .terraform/, свой state. Невозможно случайно применить dev-конфиг к prod, для этого надо физически перейти в другую директорию.

    ✓ Два env-root'а, каждый со своим state. Изоляция железная.

    То же самое на 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

    Сравни два подхода

    Перейди в один из env-root'ов:

    bash
    cd /home/student/tf-envs/dirs-style/envs/dev
    terraform state list

    Видишь:

    module.app.aws_s3_bucket.demo
    module.app.random_id.suffix

    Сравнение:

    АспектWorkspacesDirectory-per-env
    HCL дублируетсяНетМинимум (root тонкий, всё в module)
    Backend dublироватьНет, одинДа (каждый env свой backend)
    Случайно apply не в тот envЛегкоСложно. Нужно cd
    Расхождение между envНевозможно, один HCLВозможно (хорошо или плохо?)
    Сложность на стартеНизкаяСредняя
    Production-scaleНе рекомендованСтандарт

    В реальной работе: workspaces, для коротких экспериментов, dirs-per-env, для всего серьёзного. Многие компании используют Terragrunt для управления dirs-style (см. advanced-трек).

    См. tf-workspace про workspace детали и tf-init-backends про backend per env.

    ✓ Intermediate-трек закрыт. Дальше: production.

    Когда workspaces: единственный вариант

    Несмотря на всё сказанное, workspaces всё ещё полезны:

    • Short-lived feature branches. Тестируешь PR-feature в изолированном state, сносишь после merge. Дublировать directory ради 2 дней, overkill.
    • Один-два разработчика на проекте. Сложность directory-style даёт ROI на 5+ человек. Один, workspace проще.
    • Близкие envs. Если dev и prod должны быть бит-в-бит одинаковы, workspace гарантирует это (один HCL). Directory-style теоретически позволяет drift.

    Антипаттерн: workspaces для разделения customer'ов («tenant per workspace»). На сотне tenant'ов state-операции (refresh, plan) на одном backend становятся медленными, риски смешения растут. Для multi-tenant, directory-style или multi-account.

    • → terraform workspace
    • → Init и backend конфигурация

Что ты узнал

Workspaces, лёгкие, один HCL, переключатель в state. Подходят для feature-branch экспериментов или близких env. Directory layout, тяжелее на старте, но безопаснее и масштабируемее. Production обычно использует directory-per-env с общим модулем.

команды

  • terraform workspace new devсоздать workspace
  • terraform workspace select prodпереключить активный
  • terraform workspace showкакой сейчас активен: критично перед apply
  • cd envs/prod && terraform applydirectory style: env = директория

концепции

  • · workspace.name доступен в HCL как terraform.workspace
  • · Без явной проверки workspace легко применить prod-план думая что это dev
  • · Directory style + общий module: production-default

← предыдущий

Дебаг. TF_LOG, граф, чтение чужой ошибки

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