I try AWS CodeDeploy for ECS Blue/Green Deployment.
I use terraform to definition codedeploy.
this below my terraform code.
resource "aws_codedeploy_app" "ecs_dev" {
compute_platform = "ECS"
name = "code-deploy-ecs-${local.env}"
}
resource "aws_codedeploy_deployment_group" "ecs_dev" {
app_name = aws_codedeploy_app.ecs_dev.name
deployment_config_name = "CodeDeployDefault.ECSAllAtOnce"
deployment_group_name = "ecs-dev"
service_role_arn = aws_iam_role.code_deploy_ecs.arn
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE"]
}
deployment_style {
deployment_option = "WITH_TRAFFIC_CONTROL"
deployment_type = "BLUE_GREEN"
}
blue_green_deployment_config {
deployment_ready_option {
action_on_timeout = "CONTINUE_DEPLOYMENT"
}
terminate_blue_instances_on_deployment_success {
action = "TERMINATE"
termination_wait_time_in_minutes = 10
}
}
ecs_service {
cluster_name = "cluster-name"
service_name = "ecs-dev"
}
load_balancer_info {
target_group_pair_info {
prod_traffic_route {
listener_arns = "listener_arn" # created from aws console
}
# green
target_group {
name = "green-target-group" # created from aws console
}
# blue
target_group {
name = aws_lb_target_group.blue.name
}
}
}
}
resource "aws_lb_target_group" "blue" {
name = "blue-target-group"
port = 80
protocol = "HTTP"
vpc_id = "ecs-vpc"
target_type = "instance"
health_check {
interval = 30
timeout = 5
healthy_threshold = 5
unhealthy_threshold = 2
protocol = "HTTP"
port = "traffic-port"
path = each.value.health_check_path
}
}
When I successfully configured CodeDeploy itself and deployed a new task in ECS, the following error occurred.
The ELB could not be updated due to the following error: Primary taskset target group is not behind any rule for listener
What this means is not clear to me. If there is any other information you would like to know, I will provide it.
Thank you for your time.
The target group for the ECS blue/green deployment should be attached to some load balancer, so add a listener and rule for the target group. In my case, I have added the listener with a fixed port by data
and attach the target group by add a rule.
# Code Deploy
resource "aws_codedeploy_app" "new" {
compute_platform = "ECS"
name = local.name_code_deploy
}
resource "aws_codedeploy_deployment_group" "new" {
app_name = aws_codedeploy_app.new.name
deployment_group_name = local.name_deployment_group
deployment_config_name = "CodeDeployDefault.ECSAllAtOnce"
service_role_arn = "arn:${var.partition}:iam::${var.account}:role/AWSCodeDeployRoleForECS"
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE"]
}
blue_green_deployment_config {
deployment_ready_option {
action_on_timeout = "CONTINUE_DEPLOYMENT"
}
terminate_blue_instances_on_deployment_success {
action = "TERMINATE"
termination_wait_time_in_minutes = 0
}
}
deployment_style {
deployment_option = "WITH_TRAFFIC_CONTROL"
deployment_type = "BLUE_GREEN"
}
ecs_service {
cluster_name = data.aws_ecs_cluster.default.cluster_name
service_name = aws_ecs_service.new.name
}
load_balancer_info {
target_group_pair_info {
prod_traffic_route {
listener_arns = [data.aws_lb_listener.default.arn]
}
target_group {
name = aws_lb_target_group.blue.name
}
target_group {
name = aws_lb_target_group.green.name
}
}
}
}
# ECS Service
resource "aws_ecs_service" "new" {
name = local.name_ecs_service
cluster = data.aws_ecs_cluster.default.id
desired_count = var.service_count
deployment_controller {
type = "CODE_DEPLOY"
}
enable_ecs_managed_tags = true
enable_execute_command = true
launch_type = "FARGATE"
scheduling_strategy = "REPLICA"
health_check_grace_period_seconds = 120
load_balancer {
target_group_arn = aws_lb_target_group.green.arn # Blue/Green Check!
container_name = local.name_ecs_container
container_port = var.task_port
}
network_configuration {
subnets = var.subnets_web
security_groups = [
aws_security_group.ecs_service.id
]
assign_public_ip = false
}
propagate_tags = "SERVICE"
task_definition = aws_ecs_task_definition.new.family
lifecycle {
ignore_changes = [
task_definition,
desired_count
]
}
}
# ELB Listener
resource "aws_lb_target_group" "blue" {
name = local.name_tg_blue
port = var.task_port
protocol = "HTTP"
target_type = "ip"
vpc_id = data.aws_vpc.default.id
health_check {
enabled = true
path = var.alb_health_path
healthy_threshold = 2
unhealthy_threshold = 3
}
}
resource "aws_lb_target_group" "green" {
name = local.name_tg_green
port = var.task_port
protocol = "HTTP"
target_type = "ip"
vpc_id = data.aws_vpc.default.id
health_check {
enabled = true
path = var.alb_health_path
healthy_threshold = 2
unhealthy_threshold = 3
}
}
resource "aws_lb_listener_rule" "new" {
listener_arn = data.aws_lb_listener.default.arn
action {
type = "forward"
target_group_arn = aws_lb_target_group.green.arn # Blue/Green Check!
}
condition {
host_header {
values = var.alb_domain
}
}
}
# Other resources
data "aws_vpc" "default" {
id = var.vpc_id
}
data "aws_ecs_cluster" "default" {
cluster_name = var.cluster_name
}
data "aws_lb" "default" {
name = var.alb_front_name
}
data "aws_lb_listener" "default" {
load_balancer_arn = data.aws_lb.default.arn
port = var.listener_port
}