ECS Canary deoloyをterraformで作成

TL;DR

ecsで構築したアプリケーションをCanary deployする構成を作ってterraformで構築します。

目的

ecsで構築するEC2起動タイプのアプリケーションをaws-sampleを参考にCanary deployできるよう設計を試みました。 それをterraformで構築したのでメモを兼ねて紹介します。 もっとよい方法があったら教えてほしいです。

github.com

前提

  • ecsはEC2起動タイプを使う
  • ECSについては用語等最低限知っているものとする
  • route53の設定は済んでいるものとする
  • vpc, subnet, security group, はすでにあるものを使う(ここで作成しない)

構成

概略

f:id:ryook:20191027110544p:plain

説明

ecsのcluster内に2つのserviceを作成し、Route53の荷重ルーティングを使ってCanary deployを実現します。

各serviceの前段にLoadBalancerをおいてRoute53はそこを指すようにします。

コード

sample

sampleコードはgithubにあります。

github.com

service2つとそれぞれのloadbalancerを作ります。

clusterとtaskは同じresourceを使えるので、service_resourceだけ利用します。 デプロイの際はtaskを切り替えるなど適宜に修正が必要です。

# cluster
resource "aws_ecs_cluster" "sample_app_canary_deploy" {
  name = "sample-app_canary-deploy"
}

# task
resource "aws_ecs_task_definition" "task_example" {
  family                   = "sample_app"
  cpu                      = "256"
  memory                   = "512"
  requires_compatibilities = ["EC2"]
  container_definitions    = "${file("./task_definition.json")}"
}

# servie_blue
resource "aws_ecs_service" "service_blue" {
  name                              = "example"
  cluster                           = "${aws_ecs_cluster.sample_app_canary_deploy.arn}"
  task_definition                   = "${aws_ecs_task_definition.task_example.arn}"
  desired_count                     = 1
  launch_type                       = "EC2" // default: EC2 
  health_check_grace_period_seconds = 1     // defautl:0 task起動に時間がかかると引っかるので0以上にしておく

  load_balancer {
    target_group_arn = "${aws_lb_target_group.green_target}"
    container_name   = "example"
    container_port   = 80
  }

  lifecycle {
    ignore_changes = []
  }
}


# serivice_green
# servie_blueと同様

serviceごとにtarget groupを作成し、向き先をaws_ecs_serviceで指定します。 listener groupとtarget groupだけblue, green環境用に2つ必要です。

resource "aws_lb" "alb_sample" {
  name                       = "ecs-sample-alb"
  load_balancer_type         = "application"
  internal                   = false
  idle_timeout               = 60
  enable_deletion_protection = false
  subnets = [
    "subnet-a",
    "subnet-b",
    "subnet-c"
  ]
  security_groups = [
    "sg-1"
  ]
}

resource "aws_lb_listener" "http" {
  load_balancer_arn = "${aws_lb.alb_sample.arn}"
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "fixed-response"
    fixed_response {
      content_type = "text/plain"
      message_body = "test"
      status_code  = "200"
    }
  }
}

resource "aws_lb_target_group" "blue_target" {
  name        = "ecs-sample_blue-lb-target"
  vpc_id      = "vpc-a"
  target_type = "instance"
  port        = 80
  protocol    = "HTTP"
  depends_on  = ["${aws_lb.example}"]
}

# green用も同様に作る


resource "aws_lb_listener_rule" "listener_blue" {
  listener_arn = "${aws_lb_listener.http.arn}"
  action {
    type             = "forward"
    target_group_arn = "${aws_lb_target_group.blue_target.arn}"
  }
  condition {
    field  = "path-pattern"
    values = ["/*"]
  }
}


# green用も同様に作る

参考

【ダウンロード版】Pragmatic Terraform on AWS - KOS-MOS - BOOTH