mcpField
A
aws-ecs-codedeploy-blue-green

aws-ecs-codedeploy-blue-green

github.com/mizchi云与 DevOps41640 次安装1 周前更新
代码仓库

关于 aws-ecs-codedeploy-blue-green

这份参考指南介绍 AWS ECS 蓝绿部署模式,包括 ALB 加权路由和 CodeDeploy,涵盖流量切换、基础设施配置、基于告警的回滚及常见配置问题。

主要功能

  1. 01通过 ALB 权重切换流量
  2. 02配置 CodeDeploy 蓝绿部署
  3. 03使用 CloudWatch 告警回滚
  4. 04说明 Terraform 漂移注意事项

适用场景

  1. 01向 ECS 目标组进行金丝雀发布
  2. 02继续使用现有 CodeDeploy 流水线
  3. 03告警触发时回滚部署

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mizchi/skills --skill aws-ecs-codedeploy-blue-green

安装后在 Claude Code 中输入/aws-ecs-codedeploy-blue-green确认已加载。

附带文件README.md

详细介绍

AWS ECS 蓝绿部署

建议:ALB 原生加权路由(首选)

CodeDeploy 会额外引入 IAM 角色、appspec.json 配置和独立的控制平面。对于大多数 ECS 蓝绿部署需求,ALB 加权目标组可以用更少的配置实现相同效果。

工作原理

定义两个目标组(蓝色/绿色),并使用单条监听器规则按权重拆分流量:

resource "aws_lb_target_group" "blue" {
  name        = "myapp-blue"
  port        = 8080
  protocol    = "HTTP"
  vpc_id      = var.vpc_id
  target_type = "ip"

  health_check {
    path                = "/health"
    interval            = 15
    healthy_threshold   = 2
    unhealthy_threshold = 3
  }
}

resource "aws_lb_target_group" "green" {
  # identical to blue
  name = "myapp-green"
  # ...
}

resource "aws_lb_listener_rule" "weighted" {
  listener_arn = aws_lb_listener.main.arn
  priority     = 100

  condition {
    path_pattern { values = ["/*"] }
  }

  action {
    type = "forward"
    forward {
      target_group {
        arn    = aws_lb_target_group.blue.arn
        weight = 100
      }
      target_group {
        arn    = aws_lb_target_group.green.arn
        weight = 0
      }
      stickiness {
        enabled  = true
        duration = 300  # keep users on the same TG during rollout
      }
    }
  }
}
流量切换流程
# Canary: send 10% to green
aws elbv2 modify-rule --rule-arn <rule-arn> \
  --actions '[{"Type":"forward","ForwardConfig":{"TargetGroups":[{"TargetGroupArn":"<blue-arn>","Weight":90},{"TargetGroupArn":"<green-arn>","Weight":10}]}}]'

# Full cutover
aws elbv2 modify-rule --rule-arn <rule-arn> \
  --actions '[{"Type":"forward","ForwardConfig":{"TargetGroups":[{"TargetGroupArn":"<blue-arn>","Weight":0},{"TargetGroupArn":"<green-arn>","Weight":100}]}}]'

# Rollback: flip back to blue
aws elbv2 modify-rule --rule-arn <rule-arn> \
  --actions '[{"Type":"forward","ForwardConfig":{"TargetGroups":[{"TargetGroupArn":"<blue-arn>","Weight":100},{"TargetGroupArn":"<green-arn>","Weight":0}]}}]'

或者通过 Terraform 更新权重并执行 apply。无需 appspec、无需 CodeDeploy IAM 角色,也无需独立的控制平面。

何时改用 CodeDeploy
  • 团队已有 CodeDeploy 流水线,并希望继续使用
  • 需要由 CloudWatch 告警触发自动回滚,且不想编写自定义脚本
  • 需要用于迁移/冒烟测试步骤的钩子(BeforeInstall、AfterInstall、AfterAllowTraffic)

CodeDeploy ECS 蓝绿部署(参考)

关键但不易察觉的要点:lifecycle.ignore_changes

使用 CodeDeploy 管理 ECS 蓝绿部署时,CodeDeploy 会动态切换 ALB 监听器的 default_action.target_group_arn,在蓝色和绿色目标组之间切换。如果不在 OpenTofu/Terraform 中抑制此变更,之后每次执行 tofu plan 都会显示偏差,并试图恢复原来的目标组——每次部署都会与 CodeDeploy 相互冲突。

解决方法:始终为监听器添加 lifecycle.ignore_changes:

resource "aws_lb_listener" "bg_demo" {
  load_balancer_arn = aws_lb.main.arn
  port              = 8080
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.bg_demo_blue.arn  # initial state only
  }

  # CodeDeploy swaps default_action.target_group_arn between blue and green.
  # Without this, tofu plan constantly shows drift.
  lifecycle {
    ignore_changes = [default_action]
  }
}
完整模式
两个目标组(蓝色和绿色)
resource "aws_lb_target_group" "bg_demo_blue" {
  name        = "myapp-blue"
  port        = 8080
  protocol    = "HTTP"
  vpc_id      = var.vpc_id
  target_type = "ip"

  health_check {
    path                = "/health"
    interval            = 15
    healthy_threshold   = 2
    unhealthy_threshold = 3
  }

  deregistration_delay = 10  # short for faster deployments
}

resource "aws_lb_target_group" "bg_demo_green" {
  # identical to blue
  name = "myapp-green"
  # ...
}
CodeDeploy 应用和部署组
resource "aws_iam_role" "codedeploy_ecs" {
  name = "myapp-codedeploy-ecs"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{ Effect = "Allow", Principal = { Service = "codedeploy.amazonaws.com" }, Action = "sts:AssumeRole" }]
  })
}

resource "aws_iam_role_policy_attachment" "codedeploy_ecs" {
  role       = aws_iam_role.codedeploy_ecs.name
  policy_arn = "arn:aws:iam::aws:policy/AWSCodeDeployRoleForECS"
}

resource "aws_codedeploy_app" "app" {
  compute_platform = "ECS"
  name             = "myapp"
}

resource "aws_codedeploy_deployment_group" "app" {
  app_name              = aws_codedeploy_app.app.name
  deployment_group_name = "myapp-dg"
  service_role_arn      = aws_iam_role.codedeploy_ecs.arn

  deployment_style {
    deployment_option = "WITH_TRAFFIC_CONTROL"
    deployment_type   = "BLUE_GREEN"
  }

  blue_green_deployment_config {
    deployment_ready_option {
      action_on_timeout = "CONTINUE_DEPLOYMENT"  # auto-shift, no manual confirmation
    }
    terminate_blue_instances_on_deployment_success {
      action                           = "TERMINATE"
      termination_wait_time_in_minutes = 5  # give blue tasks 5 min to finish in-flight requests
    }
  }

  # Traffic shift configs:
  # CodeDeployDefault.ECSCanary10Percent5Minutes  — 10% for 5 min, then 100%
  # CodeDeployDefault.ECSLinear10PercentEvery1Minutes — 10% per minute (10 min total)
  # CodeDeployDefault.ECSAllAtOnce               — immediate 100%
  deployment_config_name = "CodeDeployDefault.ECSCanary10Percent5Minutes"

  ecs_service {
    cluster_name = aws_ecs_cluster.main.name
    service_name = aws_ecs_service.app.name
  }

  load_balancer_info {
    target_group_pair_info {
      prod_traffic_route {
        listener_arns = [aws_lb_listener.bg_demo.arn]  # listener ARN, not rule ARN
      }
      target_group { name = aws_lb_target_group.bg_demo_blue.name }
      target_group { name = aws_lb_target_group.bg_demo_green.name }
    }
  }

  auto_rollback_configuration {
    enabled = true
    events  = ["DEPLOYMENT_FAILURE", "DEPLOYMENT_STOP_ON_ALARM"]
  }

  alarm_configuration {
    enabled = true
    alarms  = [aws_cloudwatch_metric_alarm.blue_5xx.alarm_name, aws_cloudwatch_metric_alarm.green_5xx.alarm_name]
  }
}
用于自动回滚的 CloudWatch 告警

设置 DEPLOYMENT_STOP_ON_ALARM 后,CodeDeploy 会在金丝雀阶段监控这些告警。如果任一告警触发,部署就会停止并回滚。

resource "aws_cloudwatch_metric_alarm" "blue_5xx" {
  alarm_name          = "myapp-blue-5xx"
  metric_name         = "HTTPCode_Target_5XX_Count"
  namespace           = "AWS/ApplicationELB"
  statistic           = "Sum"
  period              = 60
  evaluation_periods  = 1
  threshold           = 1   # production: use 5-10 to reduce false positives
  comparison_operator = "GreaterThanOrEqualToThreshold"
  treat_missing_data  = "notBreaching"
  dimensions = {
    LoadBalancer = aws_lb.main.arn_suffix
    TargetGroup  = aws_lb_target_group.bg_demo_blue.arn_suffix
  }
}

# identical for green
部署触发器(appspec.json)

CodeDeploy 需要一个指向新任务定义的 appspec.json。该文件在部署时传入,不由 Terraform 管理:

{
  "version": 1,
  "Resources": [{
    "TargetService": {
      "Type": "AWS::ECS::Service",
      "Properties": {
        "TaskDefinition": "<NEW_TASK_DEF_ARN>",
        "LoadBalancerInfo": {
          "ContainerName": "app",
          "ContainerPort": 8080
        }
      }
    }
  }]
}
aws deploy create-deployment \
  --application-name myapp \
  --deployment-group-name myapp-dg \
  --revision revisionType=AppSpecContent,appSpecContent={content="$(cat appspec.json)"}
常见问题
  • prod_traffic_route.listener_arns 必须是监听器 ARN,而不是监听器规则 ARN。 在此处使用规则 ARN 会导致 CodeDeploy 静默失败,或报出令人困惑的错误。
  • 蓝色和绿色目标组的运行状况检查配置必须完全一致。 healthy_threshold/unhealthy_threshold 值不一致会导致某个 TG 始终被视为运行状况不佳。
  • 蓝绿部署期间,不应更改 aws_ecs_service 上的 desired_count。 部署期间,CodeDeploy 会独立管理任务数量。
  • 生产环境的 CloudWatch 告警阈值:threshold 应设为 5–10,而不是 1。金丝雀窗口期间出现单个偶发的 5xx 错误,就可能导致生产环境回滚。

评论

支持 Markdown