概要
- TerraformでECS Fargateの環境を構築
- Codeシリーズを利用してBlue/Greenデプロイをできるようにする。
- Blue/Green時に必要な部分だけ記載
Fargate + CodePipelineのソースコード
https://github.com/saku3/aws-terraform
ALB
- Fargate用のALBを構築
- TargetGroupをblueとgreen二つ用意する
- リスナールールでポート443のルールとテスト用ポート10443のルールを用意する。
- ALBは443と10443両方からアクセスできるようにする。(テスト用の10443ポートは適宜制限する)
ソースコード
alb
resource "aws_lb" "lb" {
name = "${var.project}-${var.env}-alb"
internal = false
load_balancer_type = "application"
security_groups = [
"${aws_security_group.alb_sg.id}",
]
subnets = [
aws_subnet.public_subnet_1.id,
aws_subnet.public_subnet_2.id,
]
access_logs {
enabled = true
bucket = var.lb_logs_bucket.id
}
}
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.lb.arn
port = "80"
protocol = "HTTP"
default_action {
type = "redirect"
redirect {
host = "#{host}"
path = "/#{path}"
port = "443"
protocol = "HTTPS"
query = "#{query}"
status_code = "HTTP_301"
}
}
}
resource "aws_lb_listener" "https" {
load_balancer_arn = aws_lb.lb.arn
port = "443"
protocol = "HTTPS"
default_action {
type = "fixed-response"
fixed_response {
content_type = "text/plain"
status_code = "403"
}
}
certificate_arn = aws_acm_certificate.cert.arn
}
resource "aws_lb_listener" "test_https" {
load_balancer_arn = aws_lb.lb.arn
port = "10443"
protocol = "HTTPS"
default_action {
type = "fixed-response"
fixed_response {
content_type = "text/plain"
status_code = "403"
}
}
certificate_arn = aws_acm_certificate.cert.arn
}
resource "aws_lb_listener_rule" "routing" {
listener_arn = aws_lb_listener.https.arn
priority = 100
action {
type = "forward"
target_group_arn = aws_lb_target_group.tg_blue.arn
}
condition {
host_header {
values = ["${var.domain}"]
}
}
lifecycle {
ignore_changes = [action]
}
}
resource "aws_lb_listener_rule" "test_routing" {
listener_arn = aws_lb_listener.test_https.arn
priority = 100
action {
type = "forward"
target_group_arn = aws_lb_target_group.tg_green.arn
}
condition {
host_header {
values = ["${var.domain}"]
}
}
lifecycle {
ignore_changes = [action]
}
}
resource "aws_lb_target_group" "tg_blue" {
name = "${var.project}-${var.env}-blue-tg"
port = 80
protocol = "HTTP"
target_type = "ip"
vpc_id = aws_vpc.vpc.id
health_check {
interval = 60
path = "/"
port = "traffic-port"
protocol = "HTTP"
timeout = 10
healthy_threshold = 3
unhealthy_threshold = 3
}
}
resource "aws_lb_target_group" "tg_green" {
name = "${var.project}-${var.env}-green-tg"
port = 80
protocol = "HTTP"
target_type = "ip"
vpc_id = aws_vpc.vpc.id
health_check {
interval = 60
path = "/"
port = "traffic-port"
protocol = "HTTP"
timeout = 10
healthy_threshold = 3
unhealthy_threshold = 3
}
}
Fargate
- load_balancerのtarget_group_arnはblueのターゲットグループと紐づけておく
- aws_ecs_serviceでdeployment_controllerのtypeで「CODEDEPLOY」を指定する
- 既に作成済みのaws_ecs_serviceでdeployment_controllerを変更する場合は再作成が必要になる
ソースコード
fargate
resource "aws_ecs_service" "main" {
name = "${var.project}-${var.env}-${var.app_name}"
cluster = var.cluster.id
task_definition = aws_ecs_task_definition.main.arn
platform_version = "1.4.0"
desired_count = var.desired_count
launch_type = "FARGATE"
health_check_grace_period_seconds = 200
enable_execute_command = true
network_configuration {
subnets = [var.private_subnet_1_id, var.private_subnet_2_id]
security_groups = [var.ecs_sg_id]
assign_public_ip = "false"
}
load_balancer {
target_group_arn = var.target_group_blue_arn
container_name = "${var.project}-${var.env}-${var.app_name}"
container_port = var.container_port
}
deployment_controller {
type = "CODE_DEPLOY"
}
tags = {
Name = "${var.project}-${var.env}-${var.app_name}"
}
lifecycle {
ignore_changes = [
desired_count,
task_definition,
load_balancer,
]
}
depends_on = [var.alb]
}
CodeDeploy
- アプリケーションはECSを指定する
- デプロイグループでload_balancer_infoで本稼働リスナー、テストリスナーを指定
- 本稼働リスナー : prod_traffic_route
- テストリスナー : test_traffic_route
ソースコード
codedeploy
resource "aws_codedeploy_deployment_group" "main" {
app_name = aws_codedeploy_app.main.name
deployment_config_name = "CodeDeployDefault.ECSAllAtOnce"
deployment_group_name = "${var.project}-${var.env}-${var.app_name}-deploy-group"
service_role_arn = aws_iam_role.deploy_role.arn
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE"]
}
blue_green_deployment_config {
deployment_ready_option {
action_on_timeout = "STOP_DEPLOYMENT"
wait_time_in_minutes = 60
}
terminate_blue_instances_on_deployment_success {
action = "TERMINATE"
termination_wait_time_in_minutes = 60
}
}
deployment_style {
deployment_option = "WITH_TRAFFIC_CONTROL"
deployment_type = "BLUE_GREEN"
}
ecs_service {
cluster_name = var.ecs_cluster_name
service_name = var.ecs_service_name
}
load_balancer_info {
target_group_pair_info {
prod_traffic_route {
listener_arns = [
var.lb_listener_https_arn
]
}
target_group {
name = var.target_group_blue_name
}
target_group {
name = var.target_group_green_name
}
test_traffic_route {
listener_arns = [var.lb_listener_test_https_arn]
}
}
}
}
CodeDeployで「テストトラフィックルーティングのセットアップ」が完了していればテストリスナーの10443ポートでアクセスができるようになる。
関連
CloudFormationだと、ECSのBlue/GreenデプロイのDeployment Groupは作成することができない。