LoginSignup
2
0

More than 1 year has passed since last update.

TerraformでECS FargateのBlue/Greenデプロイを構築する

Posted at

概要

  • 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ポートでアクセスができるようになる。

スクリーンショット 2022-05-05 11.52.21.png

関連

CloudFormationだと、ECSのBlue/GreenデプロイのDeployment Groupは作成することができない。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0