Когда 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'а не дерутся.
terraform apply
Cloud-bill вдвое. Будет неделю.
Шаг 2: Миграция stateful-данных
RDS:
# 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:
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%, наблюдая метрики:
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 дней мониторинга:
# 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-имена:
moved {from = aws_lb.tf
to = aws_lb.main
}
Apply, moved декларативно переименовывает, без пересоздания.
Migration данных, варианты
| Тип данных | Способ |
|---|---|
| RDS / Aurora | snapshot-restore, или logical-replication для zero-downtime |
| DynamoDB | DynamoDB Streams + Lambda на новую таблицу |
| S3 | aws s3 sync или S3 Replication-rules |
| EBS | snapshot + create-volume |
| EFS | DataSync или 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.