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/kb/Advanced/tf-blue-green-migration

kb/advanced ── Advanced ── advanced

Blue-green миграция legacy в Terraform

Когда legacy-инфра (ClickOps в Console, CloudFormation, Ansible) большая, `terraform import` каждого ресурса, недели работы и риски. Альтернатива: blue-green, поднимаешь параллельную копию через Terraform (green), переключаешь traffic, сносишь legacy (blue). Дороже по cloud-bill (двойная инфра несколько дней), но безопаснее: можешь откатиться, никакого destructive-import'а.

view as markdownaka: terraform-blue-green, terraform-legacy-migration, terraform-side-by-side

Когда blue-green вместо import

terraform import, захват существующего ресурса под управление Terraform. Звучит просто, но на legacy-стеке это:

  • Манипуляции на каждый ресурс. 500 ресурсов = 500 import'ов (даже с import блоком и -generate-config-out).
  • State не отражает поведение, отражает атрибуты на момент import'а. Если HCL и реальность хоть немного разойдутся, плана на drift или destroy.
  • Невидимые dependencies в legacy. CloudFormation-stack может держать stack-internal ссылки, которых ты не знаешь, import их разорвёт.
  • Никакого rollback'а. Сделал import, plan показал destroy, а обратно как? Restore из backup state, надеемся что не было apply.

Blue-green: вместо манипуляций со state'ом, строишь новое рядом. Когда new working, переключаешь, сносишь old.

Когда blue-green:

  • Legacy маленький, до 50 ресурсов, import нормально.
  • Legacy большой, но statefuk (RDS, EBS), blue-green с migration данных дорог.
  • Stateless (web-серверы, Lambda, S3-static), blue-green оптимален.
  • Есть бюджет на параллельную инфру 1-7 дней.
  • Есть способ переключить traffic (DNS, ALB target group, CDN).

Сценарий

Legacy:

VPC (ручной, CloudFormation)
├── 4 EC2 web-servers
├── 1 RDS Postgres
├── ALB
└── Route53 record: api.company.com → ALB

Цель:

VPC (terraform)
├── 4 EC2 web-servers (terraform)
├── 1 RDS Postgres (terraform)
├── ALB (terraform)
└── Route53 record: api.company.com → terraform-ALB

Шаг 1: Создай terraform-stack рядом

Полный mirror legacy через HCL. Но имена ресурсов другие: tf-vpc, tf-alb, etc. Так оба stack'а не дерутся.

bash
terraform apply

Cloud-bill вдвое. Будет неделю.

Шаг 2: Миграция stateful-данных

RDS:

bash
# snapshot legacy DB
aws rds create-db-snapshot --db-instance-identifier legacy-db --db-snapshot-identifier migration-base
# restore в tf-RDS:
aws rds restore-db-instance-from-db-snapshot \
    --db-instance-identifier tf-db \
    --db-snapshot-identifier migration-base

Или logical-replication для zero-downtime. Зависит от сценария.

S3 buckets, пересоздать или aws s3 sync:

bash
aws s3 sync s3://legacy-bucket s3://tf-bucket --exact-timestamps

Шаг 3: Smoke-test green

Внутренний DNS-record tf-api.company.com указывает на tf-ALB. Прогоняешь test suite, проверяешь функциональность.

Шаг 4: Traffic switch

Если используешь Route53 weighted records, постепенно, 10% → 50% → 100%, наблюдая метрики:

hcl
resource "aws_route53_record" "api_legacy" {
  zone_id = data.aws_route53_zone.main.zone_id
  name    = "api.company.com"
  type    = "A"
  weighted_routing_policy { weight = 10 }
  set_identifier = "legacy"
  alias {
    name                   = data.aws_lb.legacy_alb.dns_name
    zone_id                = data.aws_lb.legacy_alb.zone_id
    evaluate_target_health = true
  }
}
resource "aws_route53_record" "api_tf" {
  zone_id = data.aws_route53_zone.main.zone_id
  name    = "api.company.com"
  type    = "A"
  weighted_routing_policy { weight = 90 }
  set_identifier = "tf"
  alias {
    name                   = aws_lb.tf.dns_name
    zone_id                = aws_lb.tf.zone_id
    evaluate_target_health = true
  }
}

Меняешь веса в HCL → apply → traffic смещается.

Шаг 5: Сноси legacy

После N дней мониторинга:

bash
# legacy CloudFormation stack
aws cloudformation delete-stack --stack-name legacy-stack
# или вручную, если ClickOps
aws ec2 terminate-instances --instance-ids i-...
# ...

Если уверен, можно сразу. Если хочешь подождать, пусть месяц работает «как есть, на 0% веса». Минус, cost.

Шаг 6: Cleanup tf-

Префиксы tf- были временные. Переименуй в production-имена:

hcl
moved {
  from = aws_lb.tf
  to   = aws_lb.main
}

Apply, moved декларативно переименовывает, без пересоздания.

Migration данных, варианты

Тип данныхСпособ
RDS / Aurorasnapshot-restore, или logical-replication для zero-downtime
DynamoDBDynamoDB Streams + Lambda на новую таблицу
S3aws s3 sync или S3 Replication-rules
EBSsnapshot + create-volume
EFSDataSync или rsync
Secretsвручную (Secrets Manager не клонируется автоматически)

Для каждого, свой подход. Stateful, самая дорогая часть миграции.

Rollback

Главное преимущество blue-green: blue ещё жив пока ты не сделал step 5.

  • Smoke-test зафейлился? Откатываем DNS-вес обратно на legacy.
  • Что-то странное в prod-нагрузке? Откатываем DNS-вес.
  • Терраформ-state corrupt'нулся? Worst case, destroy terraform-stack, восстанавливай legacy как было.

terraform import такой роскоши не даёт: после import + apply ты в Terraform; rollback, это destroy всё что Terraform создал, восстановить через CloudFormation/manual.

Когда blue-green, плохая идея

  • Один global ресурс. Например, IAM-role с конкретным ARN'ом blue-green «новой ролью» не работает; ARN другой, потребители не знают про новый.
  • Inteсточение через external DNS / external systems. Если кто-то из-вне хардкодит твой ALB-DNS-name, blue-green не помогает.
  • Sticky sessions stateful. Если session-state в memory приложения, переключение traffic середине дня == разрыв сессий пользователей.

Подводные камни

  • Cost. Двойная инфра неделю, может быть тысячи $. Заложи бюджет заранее.

  • DNS-TTL. Если legacy-record имеет TTL 24h, switch видит через 24h максимум. Снизь TTL заранее (24h до switch'а) до 60s.

  • External integrations. Сторонние сервисы (webhooks, partners, monitoring) могут хардкодить старые URLs. Audit всех integration'ов ДО switch'а.

  • Stateful-data drift. RDS-snapshot → restore, данные на момент snapshot'а. Между snapshot и cutover в legacy могут писаться новые данные. Решение: short-window cutover или logical-replication.

  • Internal services могут хардкодить IP'шки. Internal-ALB создаётся с разными IP. Сервисы, использующие конкретный IP (не DNS-name), не переключатся.

  • Не путать с stack-replication. Blue-green, НЕ копирование state'а. Это создание новой инфры с нуля через HCL. State'ы независимы.

  • Terraform не помогает с миграцией данных. HCL умеет создать RDS-restore из snapshot'а, но не управляет logical-replication. Это отдельная работа DBA.

§ команды

bash
aws rds create-db-snapshot --db-instance-identifier X --db-snapshot-identifier mig-base

Сделать snapshot legacy DB перед миграцией.

bash
aws s3 sync s3://legacy s3://terraform-managed --exact-timestamps

Скопировать S3-content в новый bucket.

bash
dig @8.8.8.8 api.company.com

Проверить traffic после switch'а, на какой ALB resolве.

bash
terraform apply -var=traffic_weight_legacy=0

Постепенный switch через variable weight.

§ см. также

  • tf-state-importИмпорт: захват существующего ресурса под TerraformИмпорт = «этот ресурс уже создан в облаке, начни им управлять». Старый способ: `terraform import <адрес> <cloud_id>`, ресурс в HCL надо написать руками. Новый (TF 1.5+): `import` блок прямо в HCL, plan показывает что будет, apply закрепляет. Импорт **не пишет HCL**, это твоя работа.
  • tf-moved-blockmoved блок: переименование без destroy`moved { from = ..., to = ... }` в HCL декларативно говорит Terraform: «этот ресурс раньше был по одному адресу, теперь по другому, в облаке тот же». Plan покажет «move», не «destroy + create». Появился в TF 1.1. Замена ручному `terraform state mv`, оставляет след в git, повторяется у всех в команде, видно в diff.
  • tf-large-scale-stateБольшой state, иерархия, blast-radius, namingОдин state на 5000 ресурсов = боль: refresh минуты, lock-contention, любой apply трогает всё. Решение, иерархия state'ов: network/iam отдельно, apps отдельно, между ними `terraform_remote_state`. Blast-radius, критерий разделения. Naming для бакетов и lock-таблиц предсказуемая структура.
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки