I am using terraform, to deploy blue-green for a ECS service failing with The ELB could not be updated due to the following error: Primary taskset target group must be behind listener arn:aws:elasticloadbalancing:eu-west-1:12345674865:listener-rule/app/alb/123/456/789.
Since there are multiple ecs service I deploy, I therefore have modules and these are called from service directory.
I have modules for
code-depoly
resource "aws_codedeploy_app" "ecs" {
compute_platform = "ECS"
name = "${var.service_name}-ecs-app"
}
resource "aws_codedeploy_deployment_config" "config_deploy" {
deployment_config_name = "${var.service_name}-ecs-app"
compute_platform = "ECS"
traffic_routing_config {
type = "AllAtOnce"
}
}
resource "aws_codedeploy_deployment_group" "ecs" {
app_name = aws_codedeploy_app.ecs.name
deployment_group_name = "${var.app_name}-dg"
deployment_config_name = aws_codedeploy_deployment_config.config_deploy.deployment_config_name
service_role_arn = aws_iam_role.codedeploy.arn
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 = 1
}
}
ecs_service {
cluster_name = var.cluster_name
service_name = var.service_name
}
deployment_style {
deployment_option = "WITH_TRAFFIC_CONTROL"
deployment_type = "BLUE_GREEN"
}
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE"]
}
load_balancer_info {
target_group_pair_info {
prod_traffic_route {
listener_arns = [var.listener_arn]
}
target_group {
name = var.target_group_blue
}
target_group {
name = var.target_group_green
}
}
}
}
resource "aws_iam_role" "codedeploy" {
name = "rol-codedeploy-${var.service_name}"
assume_role_policy = data.aws_iam_policy_document.assume_by_codedeploy.json
}
resource "aws_iam_role_policy" "codedeploy" {
name = "pol-codedeploy-${var.service_name}"
role = aws_iam_role.codedeploy.name
policy = data.aws_iam_policy_document.codedeploy.json
}
resource "local_file" "appspec_yaml" {
content = templatefile("${path.module}/appspec.yaml.tftpl", {
code_deploy_app_name = aws_codedeploy_app.ecs.name
code_deploy_group_name = aws_codedeploy_deployment_group.ecs.deployment_group_name
task_def_arn = var.task_definition
container_port = var.container_port
})
filename = "${path.module}/appspec.yaml"
}
}
ecs_service_blue_green
resource "aws_ecs_service" "blue_green" {
count = var.create_blue_green ? 1 : 0
name = var.name
cluster = var.cluster
force_new_deployment = var.force_new_deployment
wait_for_steady_state = var.wait_for_steady_state
# Use latest active revision
task_definition = var.task_definition
propagate_tags = "TASK_DEFINITION"
desired_count = var.desired_count
deployment_minimum_healthy_percent = var.deployment_minimum_healthy_percent
deployment_maximum_percent = var.deployment_maximum_percent
health_check_grace_period_seconds = try(var.health_check_grace_period_seconds, 10)
scheduling_strategy = "REPLICA"
launch_type = try(var.launch_type, null)
/* deployment_circuit_breaker {
rollback = false
enable = false
} */
deployment_controller {
type = var.deployment_controller
}
network_configuration {
subnets = var.subnets
security_groups = var.security_groups
assign_public_ip = var.assign_public_ip
}
dynamic "load_balancer" {
for_each = var.load_balancer
content {
container_name = lookup(load_balancer.value, "container_name", null)
target_group_arn = lookup(load_balancer.value, "target_group_arn", null)
container_port = lookup(load_balancer.value, "container_port", null)
}
}
dynamic "service_registries" {
for_each = var.service_registries
content {
registry_arn = lookup(service_registries.value, "registry_arn", null)
container_name = lookup(service_registries.value, "container_name", null)
container_port = lookup(service_registries.value, "container_port", null)
port = lookup(service_registries.value, "port", null)
}
}
dynamic "capacity_provider_strategy" {
for_each = var.capacity_provider_strategy
content {
capacity_provider = try(capacity_provider_strategy.value.capacity_provider, null)
weight = try(capacity_provider_strategy.value.weight, null)
base = lookup(capacity_provider_strategy.value, "base", null)
}
}
tags = merge(
{
"Name" = var.name
},
var.tags,
var.ecs_service_tags,
)
timeouts {
create = try(var.timeouts.create, null)
update = try(var.timeouts.update, null)
delete = try(var.timeouts.delete, null)
}
lifecycle {
ignore_changes = [capacity_provider_strategy, desired_count, task_definition, load_balancer ]
}
}
Service creation
locals{
tg_routing = {
blue = 80
green = 8080
}
default_tg_routing = {
blue = 80
}
target_group = var.create_blue_green ? local.tg_routing : local.default_tg_routing
deployment_controller = var.create_blue_green ? "CODE_DEPLOY" : "ECS"
module "service" {
source = "../../modules/ecs-service"
create_blue_green = var.create_blue_green
depends_on = [module.target_groups]
name = "${local.name}-service-01"
cluster = var.cluster_arn
task_definition = aws_ecs_task_definition.this.arn
desired_count = var.desired_count
deployment_minimum_healthy_percent = "100"
deployment_maximum_percent = "200"
subnets = data.aws_subnets.workload.ids
security_groups = [module.service_security_group.id]
wait_for_steady_state = local.wait_for_steady_state
load_balancer = [{
container_name = "ServiceContainer"
target_group_arn = module.target_groups["blue"].arn
container_port = var.container_port
}]
deployment_controller = local.deployment_controller
capacity_provider_strategy = [var.capacity_provider]
tags = var.tags
ecs_service_tags = { Description = "${var.app_name} application Service.", Environment = terraform.workspace }
}
module "target_groups" {
for_each = local.target_group
source = "../../modules/lb-target-group"
vpc_id = data.aws_vpc.vpc.id
name = "${local.stage_code}-${var.app_name}-tg-${each.key}"
port = "${each.value}"
protocol = "HTTP"
target_type = "ip"
load_balancing_algorithm_type = "round_robin"
health_check = [{
enabled = true
interval = 30
path = "/${var.app_name}/health-check"
port = "traffic-port"
healthy_threshold = 3
unhealthy_threshold = 3
timeout = 6
protocol = "HTTP"
matcher = "200-399"
}]
tags = {
createdby = "terraform"
owner = "DevOps"
}
target_group_tags = {
targetgroup = "${local.stage_code}-${var.app_name}-tg"
}
}
module "listener-rule_blue" {
source = "../../modules/lb-listener-rule"
listener_arn = var.listener_arn
actions = [{
type = "forward"
target_group_arn = module.target_groups["blue"].arn
}]
conditions = [{
path_patterns = ["/${var.app_name}/*"]
}]
}
resource "aws_alb_listener" "lb_listener_8080" {
load_balancer_arn = "arn:aws:elasticloadbalancing:eu-west-1:123456789:loadbalancer/app/alb/123"
port = "8080"
protocol = "HTTP"
default_action {
type = "fixed-response"
fixed_response {
content_type = "text/plain"
message_body = "Not found."
status_code = "404"
}
}
lifecycle {
ignore_changes = [default_action]
}
}
module "listener-rule_green" {
source = "../../modules/lb-listener-rule"
listener_arn = aws_alb_listener.lb_listener_8080.arn
actions = [{
type = "forward"
target_group_arn = module.target_groups["blue"].arn
}]
conditions = [{
path_patterns = ["/${var.app_name}/*"]
}]
}
I expect the service to be created with new task definition revision and the blue green swap to happen. Any help would be greatly appreciated.