I'm using terraform to configure ECS and CI/CD.
There are two target groups, blue and green:
resource "aws_lb_target_group" "target_group_blue" {
name = "${local.resource_id}-blue"
port = var.target_group_port
protocol_version = var.target_group_protocol_version
protocol = var.target_group_protocol
vpc_id = var.vpc_id
target_type = "ip"
health_check {
enabled = true
path = var.healthcheck_uri
interval = var.healthcheck_interval
protocol = var.target_group_protocol
healthy_threshold = 5
unhealthy_threshold = 2
timeout = 20
}
tags = local.tags
}
resource "aws_lb_target_group" "target_group_green" {
name = "${local.resource_id}-green"
port = var.target_group_port
protocol_version = var.target_group_protocol_version
protocol = var.target_group_protocol
vpc_id = var.vpc_id
target_type = "ip"
health_check {
enabled = true
path = var.healthcheck_uri
interval = var.healthcheck_interval
protocol = var.target_group_protocol
healthy_threshold = 5
unhealthy_threshold = 2
timeout = 20
}
tags = local.tags
}
The listener is configured as follows. Ports 80 and 443 to use for production deployment, and port 8080 to use for testing traffic.
resource "aws_lb_listener" "http_listener" {
load_balancer_arn = aws_lb.loadbalancer.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.target_group_blue.arn
}
lifecycle {
ignore_changes = [default_action]
}
tags = local.tags
}
resource "aws_lb_listener" "http_test_listener" {
load_balancer_arn = aws_lb.loadbalancer.arn
port = "8080"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.target_group_green.arn
}
lifecycle {
ignore_changes = [default_action]
}
tags = local.tags
}
resource "aws_lb_listener" "https_listener" {
load_balancer_arn = aws_lb.loadbalancer.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-2016-08"
certificate_arn = var.certificate_arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.target_group_blue.arn
}
tags = local.tags
}
The code deploy group is as follows.
resource "aws_codedeploy_deployment_group" "deployment_group" {
app_name = aws_codedeploy_app.deploy.name
deployment_config_name = aws_codedeploy_deployment_config.config_deploy.deployment_config_name
deployment_group_name = local.resource_id
service_role_arn = aws_iam_role.codedeploy_role.arn
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE"]
}
blue_green_deployment_config {
deployment_ready_option {
action_on_timeout = "CONTINUE_DEPLOYMENT"
wait_time_in_minutes = 0
}
terminate_blue_instances_on_deployment_success {
action = "TERMINATE"
termination_wait_time_in_minutes = 5
}
}
deployment_style {
deployment_option = "WITH_TRAFFIC_CONTROL"
deployment_type = "BLUE_GREEN"
}
ecs_service {
cluster_name = aws_ecs_cluster.ecs_cluster.name
service_name = aws_ecs_service.ecs_service.name
}
load_balancer_info {
target_group_pair_info {
prod_traffic_route {
listener_arns = [aws_lb_listener.http_listener.arn]
}
test_traffic_route {
listener_arns = [aws_lb_listener.http_test_listener.arn]
}
target_group {
name = aws_lb_target_group.target_group_blue.name
}
target_group {
name = aws_lb_target_group.target_group_green.name
}
}
}
}
This way, the blue-green targetgroup replacement works fine for the 80 port listener. However, targetgroup replacement does not occur for the 443 listener.
Whenever deploy, blue-green is applied to both 80 and 443 listeners, I want it to work without problems on https domain endpoint.
Are there any recommended best practices for this?
The listener_arns
setting in CodeDeploy is a list. So you could be adding both listeners to that:
prod_traffic_route {
listener_arns = [aws_lb_listener.http_listener.arn,
aws_lb_listener.https_listener.arn]
}
Then both would be switched over to the new deployment at the same time.
However, you asked about "best practice", and the best practice for serving HTTPS from the load balancer is to always serve HTTPS. In other words: don't ever allow insecure traffic. If insecure traffic comes in, convert it to secure traffic.
To do that you would configure the HTTP listener to simply issue a redirect to your HTTPS listener, like so:
resource "aws_lb_listener" "http_listener" {
load_balancer_arn = aws_lb.loadbalancer.arn
port = "80"
protocol = "HTTP"
default_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
Now any requests to your HTTP listener will receive a redirect response that sends them over to the HTTPS listener. After configuring that, you would only need to register the HTTPS listener with CodeDeploy:
prod_traffic_route {
listener_arns = [aws_lb_listener.https_listener.arn]
}