Select environment:
Plan/apply in customer_apps_tf: # module.silo.module.aurora.aws_security_group_rule.rds_cluster_sg_rules[8] will be created + resource "aws_security_group_rule" "rds_cluster_sg_rules" { + cidr_blocks = [ + "xx.xx.xx.xx/xx", + "xx.xx.xx.xx/xx", ] + from_port = {FROM_PORT} + id = (known after apply) + protocol = "tcp" + security_group_id = "sg-id" + self = false + source_security_group_id = (known after apply) + to_port = {TO_PORT} + type = "ingress" }
Run in old:
tf state show [OLD_MODULE_PATH].module.service_dns.aws_route53_record.main_migrated[0]
Run in both:
tf init
tf state pull > state.tfstate

Run in new:
tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].aws_iam_policy_attachment.sqs_queues' '[NEW_MODULE_PATH].aws_iam_policy_attachment.sqs_queues' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.secrets_rds' '[NEW_MODULE_PATH].module.secret_rds' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.sqs' '[NEW_MODULE_PATH].module.sqs' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.string_parameters' '[NEW_MODULE_PATH].module.parameters' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_cloudwatch_log_group.logging' '[NEW_MODULE_PATH].module.service.aws_cloudwatch_log_group.logging' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_cloudwatch_log_subscription_filter.ecs_service_to_shipper' '[NEW_MODULE_PATH].module.service.aws_cloudwatch_log_subscription_filter.ecs_service_to_shipper' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_cloudwatch_metric_alarm.cpu_util_alarm' '[NEW_MODULE_PATH].module.service.aws_cloudwatch_metric_alarm.cpu_util_alarm' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_cloudwatch_metric_alarm.cpu_util_alert' '[NEW_MODULE_PATH].module.service.aws_cloudwatch_metric_alarm.cpu_util_alert' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_cloudwatch_metric_alarm.max_cpu_util_alarm' '[NEW_MODULE_PATH].module.service.aws_cloudwatch_metric_alarm.max_cpu_util_alarm' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_cloudwatch_metric_alarm.max_cpu_util_alert' '[NEW_MODULE_PATH].module.service.aws_cloudwatch_metric_alarm.max_cpu_util_alert' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_cloudwatch_metric_alarm.memory_util_alert' '[NEW_MODULE_PATH].module.service.aws_cloudwatch_metric_alarm.memory_util_alert' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_ecr_repository.module' '[NEW_MODULE_PATH].module.service.aws_ecr_repository.module' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_ecr_lifecycle_policy.policy' '[NEW_MODULE_PATH].module.service.aws_ecr_lifecycle_policy.policy' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_iam_role.task' '[NEW_MODULE_PATH].module.service.aws_iam_role.task' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_iam_role_policy.cw_access' '[NEW_MODULE_PATH].module.service.aws_iam_role_policy.cw_access' tf state mv -state=../../../[OLD_REPO_NAME]/[ENV]/env-[ENV]/state.tfstate -state-out=state.tfstate '[OLD_MODULE_PATH].module.service.aws_iam_role_policy.task' '[NEW_MODULE_PATH].module.service.aws_iam_role_policy.task'

Run in both:
tf state push state.tfstate
Run in new:
tf import -var [ECS_MIGRATION] [NEW_MODULE_PATH].module.service_dns.aws_route53_record.weighted_main_migration[0] [R53_ID]
Run in new:
tf plan -out plan.tfplan -var [ECS_MIGRATION]
Terraform will perform the following actions: # module.applications.module.checkout.module.service.aws_alb_listener_rule.host_rule[0] will be created + resource "aws_alb_listener_rule" "host_rule" # module.applications.module.checkout.module.service.aws_alb_target_group.main[0] will be created + resource "aws_alb_target_group" "main" { + arn = (known after apply) + arn_suffix = (known after apply) + connection_termination = false + deregistration_delay = "30" + id = (known after apply) + ip_address_type = (known after apply) + lambda_multi_value_headers_enabled = false + load_balancing_algorithm_type = "round_robin" + name = (known after apply) + port = {PORT} + preserve_client_ip = (known after apply) + protocol = "HTTP" + protocol_version = (known after apply) + proxy_protocol_v2 = false + slow_start = 0 + target_type = "ip" + vpc_id = "{VPC_ID}" + target_failover { + on_deregistration = (known after apply) + on_unhealthy = (known after apply) } } # module.applications.module.checkout.module.service.aws_ecs_service.fargate[0] will be created + resource "aws_ecs_service" "fargate" { + cluster = "{CLUSTER_ARN}" + deployment_maximum_percent = 200 + deployment_minimum_healthy_percent = 100 + desired_count = 0 + enable_ecs_managed_tags = false + enable_execute_command = false + health_check_grace_period_seconds = 200 + iam_role = (known after apply) + id = (known after apply) + launch_type = "FARGATE" + name = "checkout-alpha" + platform_version = "1.4.0" + propagate_tags = "SERVICE" + scheduling_strategy = "REPLICA" + task_definition = "{TASK_DEFINITION_ARN}" + triggers = (known after apply) + wait_for_steady_state = false + deployment_controller { + type = "ECS" } + load_balancer { + container_name = "checkout-alpha" + container_port = {PORT} + target_group_arn = (known after apply) } + network_configuration { + assign_public_ip = false + security_groups = (known after apply) + subnets = [ + "subnet-01", + "subnet-02", ] } } # module.applications.module.checkout.module.service_dns.aws_route53_record.weighted_main_migration[0] will be updated in-place ~ resource "aws_route53_record" "weighted_main_migration" { id = "{ID}" name = "checkout.app" + set_identifier = "main_migration" # (5 unchanged attributes hidden) + weighted_routing_policy { + weight = 100 } # (1 unchanged block hidden) } # module.applications.module.checkout.module.service_dns.aws_route53_record.weighted_new_migration[0] will be created + resource "aws_route53_record" "weighted_new_migration" { + allow_overwrite = (known after apply) + fqdn = (known after apply) + id = (known after apply) + name = "checkout.app" + set_identifier = "new_migration" + type = "A" + zone_id = "{ZONE_ID}" + alias { + evaluate_target_health = false + name = "{DNS_NAME}" + zone_id = "{ZONE_ID}" } + weighted_routing_policy { + weight = 0 } }
tf apply plan.tfplan
Start service in new cluster, test:
curl http://[APP_NAME].app.[ENV].company.com/monitoring
Run in new:
tf plan -out plan.tfplan -var [ECS_MIGRATION]
Terraform will perform the following actions: # module.applications.module.checkout.module.service_dns.aws_route53_record.weighted_main_migration[0] will be updated in-place ~ resource "aws_route53_record" "weighted_main_migration" { id = "{ID}" name = "checkout.app" # (6 unchanged attributes hidden) ~ weighted_routing_policy { ~ weight = 70 -> 0 } # (1 unchanged block hidden) } # module.applications.module.checkout.module.service_dns.aws_route53_record.weighted_new_migration[0] will be updated in-place ~ resource "aws_route53_record" "weighted_new_migration" { id = "{ID}" name = "checkout.app" # (6 unchanged attributes hidden) ~ weighted_routing_policy { ~ weight = 30 -> 100 } # (1 unchanged block hidden) } Plan: 0 to add, 2 to change, 0 to destroy.
tf apply plan.tfplan
Run in new (clean after 100% move):
tf state mv [NEW_MODULE_PATH].module.service_dns.aws_route53_record.weighted_new_migration[0] [NEW_MODULE_PATH].module.service_dns.aws_route53_record.main_migrated[0] tf import [NEW_MODULE_PATH].module.service.aws_ecs_task_definition.main[0] [TASK_DEFINITION_ARN]
Run in new:
tf plan -out plan.tfplan -target [NEW_MODULE_PATH].module.service_dns.aws_route53_record.weighted_main_migration[0]
Terraform will perform the following actions: # module.applications.module.checkout.module.service_dns.aws_route53_record.weighted_main_migration[0] will be destroyed # (because index [0] is out of range for count) - resource "aws_route53_record" "weighted_main_migration" { - fqdn = "{FQDN}" -> null - id = "{ID}" -> null - name = "checkout.app" -> null - records = [] -> null - set_identifier = "main_migration" -> null - ttl = 0 -> null - type = "A" -> null - zone_id = "{ZONE_ID}" -> null - alias { - evaluate_target_health = false -> null - name = "{DNS_NAME}" -> null - zone_id = "{ZONE_ID}" -> null } - weighted_routing_policy { - weight = 0 -> null } } Plan: 0 to add, 0 to change, 1 to destroy.
tf apply plan.tfplan

Run in new:
tf plan -out plan.tfplan
Terraform will perform the following actions: # module.applications.module.checkout.module.service_dns.aws_route53_record.main_migrated[0] will be updated in-place ~ resource "aws_route53_record" "main_migrated" { id = "{ID}" name = "checkout.app" - set_identifier = "new_migration" -> null # (5 unchanged attributes hidden) - weighted_routing_policy { - weight = 100 -> null } # (1 unchanged block hidden) }
tf apply plan.tfplan
Run in old:
tf state rm [OLD_MODULE_PATH].module.service.aws_ecs_task_definition.main[0] tf state rm [OLD_MODULE_PATH].module.service.aws_security_group.task[0] tf state rm [OLD_MODULE_PATH].module.service.aws_security_group_rule.permit_all_lb_egress_fargate[0] tf state rm [OLD_MODULE_PATH].module.service.aws_security_group_rule.permit_all_task_egress[0] tf state rm [OLD_MODULE_PATH].module.service.aws_security_group_rule.permit_container_port_alb[0] tf state rm [OLD_MODULE_PATH].module.service.aws_security_group_rule.permit_vpn_to_task[0] tf state rm [OLD_MODULE_PATH].module.service_dns.aws_route53_record.main_migrated[0]
Run in old:
tf plan -out plan.tfplan
Terraform will perform the following actions: # module.applications.module.checkout[0].module.service.aws_alb_listener_rule.host_rule[0] will be destroyed # module.applications.module.checkout[0].module.service.aws_alb_target_group.main[0] will be destroyed # module.applications.module.checkout[0].module.service.aws_ecs_service.fargate[0] will be destroyed
tf apply plan.tfplan

Congratulations: all steps are finished!