terraformで開発者個人別に自由にECSにコンテナをデプロイできる開発環境を用意する

  • 7
    いいね
  • 0
    コメント

できるだけproductionに近い状態でAWSの各コンポーネントと通信したり、DBのデータを取得できる環境で、アプリケーションの動作確認をしたいことがある。
共有の開発者用のステージング環境等で、それを行うこともできるが、開発者が増えてくると利用が競合して順番待ちが発生したりとかする。

RDBのスキーマを弄ったり、データ投入フロー自体を修正する様な場合は、排他的に利用するべきだが、必ずしも全ての修正がそんなにヘビーな修正ではない。
コンテナの独立性を利用すれば、開発者個別にもっと自由に使える環境を開放できるはず。

というわけで、terraformと組み合わせて、そこそこ手軽に作る方法を考えてみた。

resource "aws_alb" "per_developer" {
  count = "${length(var.users)}"

  name = "${element(var.users, count.index)}"
  internal = false
  subnets = ["<your subnet id>"]
  security_groups = ["<your security_group id>"]
  idle_timeout                = 120

  tags {
    PerDeveloper = true
    User = "${element(var.users, count.index)}"
  }
}

resource "aws_alb_target_group" "per_developer" {
  count = "${length(var.users)}"

  name = "${element(var.users, count.index)}"
  port = 8080
  protocol = "HTTP"
  vpc_id = "<your vpc id>"
  deregistration_delay = 60

  health_check {
    path = "<your health_check path>"
  }
}

resource "aws_alb_listener" "per_developer" {
  count = "${length(var.users)}"

  load_balancer_arn = "${element(aws_alb.per_developer.*.arn, count.index)}"
  port = 443
  protocol = "HTTPS"
  ssl_policy = "ELBSecurityPolicy-2016-08"
  certificate_arn = "<your certificate_arn>"

  default_action {
    target_group_arn = "${element(aws_alb_target_group.per_developer.*.arn, count.index)}"
    type = "forward"
  }
}

resource "aws_route53_record" "per_developer_analysis" {
  count = "${length(var.users)}"

  zone_id = "${var.zone_id}"
  name = "${element(var.users, count.index)}.${var.domain_name}"
  type = "A"
  alias {
    name = "${element(aws_alb.per_developer.*.dns_name, count.index)}"
    zone_id = "${element(aws_alb.per_developer.*.zone_id, count.index)}"
    evaluate_target_health = true
  }
}

こんな感じでterraformのcountと配列へのアクセスを利用するモジュールを作成する。
countと配列を組み合わせてループっぽいことを実現するのは、マニュアル読んでるだけだと、とても分かりにくいので最初どうしようかと思ったが、一応これでやりたいことはできた。

利用する時はこんな感じ。

module "per_developer_env" {
  source = <module path>

  users = ["josuke", "okuyasu", "rohan", "koichi"]
}

これで、各メンバー毎のDNSとALBが準備できる。
ALBを利用するのは、コンテナのdynamic port mappingを利用するためだ。
ECSのtask definitionでhost_portの指定を空欄にすれば、コンテナを起動する際に空いてるポートとコンテナ側の待受ポートをマッピングしてくれる。
ECS serviceをALB target groupと紐付ける際に、host_portが動的であれば、ECSが自動的にコンテナ側へのマッピングに利用しているポートを使って、ALB target groupにそのポートでノードを登録してくれる。
これで、アプリケーション側やミドルウェア側のポートを変更しなくても、同じマシンリソースに相乗りすることができる。

ECS側の設定は、各開発者が自分のIDを指定してUSERNAME=josuke cap member deploy等と実行すると、個別のIDと同一の名前のALB Target Groupを検索し、それと紐付いたECS Serviceを定義する様にしている。
デプロイ方式に依存する所が大きいので、サンプルは出せてないけど……。

というわけで、これで必要なユーザーが個別に自分だけの環境を簡単に持てる様になった。
まあ、まだ運用に乗せたばかりなので、上手く活用されるかは分からないが。