TerraformでFargateを構築する

はじめに
インフラエンジニアとしてTerraform運用を行っているのですが、 TerraformやFargateもだいぶ浸透してきて、導入している企業も増えてきているように感じます。 そのようなケースのサンプルとして公開したいと思います。
ファイル構成
ファイル構成は以下としています。
├── logs
│ ├── backend.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── provider.tf
│ └── variables.tf
├── buckets
│ ├── backend.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── provider.tf
│ └── variables.tf
├── ecr
│ ├── backend.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── provider.tf
│ └── variables.tf
└── fargate
├── backend.tf
├── files
│ └── container\_definition.json
├── main.tf
├── outputs.tf
├── provider.tf
└── variables.tf
ポイントとしては、logとFargateのtfファイルの階層を分けている事です。 分ける理由としては、同階層にしてしまうとTerraform destoryした時にログまで消えてしまって後悔。。。というケースが起こるかなと思い階層を分けています。 同様の理由としてS3bucket、ECRも階層を分けています。
また、files以下にコンテナ定義のjsonファイル等を入れています。
Fargate
まずはクラスターから
resource "aws\_ecs\_cluster" "default" {
name = local.service\_name
}
タスク定義は以下のようになっています。 定義の内容をjsonファイルに記載しておいて、ECRのARNなどはdataソースを使って記入しています。
data "template\_file" "default" {
template = file("files/container\_definition.json")
vars = {
ECR\_ARN = data.terraform\_remote\_state.ecr.outputs.default\["repository\_url"\]
SERVICE\_NAME = local.service\_name
}
}
resource "aws\_ecs\_task\_definition" "default" {
family = local.service\_name
container\_definitions = data.template\_file.default.rendered
task\_role\_arn = aws\_iam\_role.default.arn
network\_mode = "awsvpc"
execution\_role\_arn = aws\_iam\_role.default.arn
cpu = 512
memory = 1024
requires\_compatibilities = \["FARGATE"\]
}
タスク定義のjsonファイルは以下のようになっています。
\[
{
"name": "${SERVICE\_NAME}",
"image": "${ECR\_ARN}",
"essential": true,
"portMappings": \[
{
"containerPort": 80,
"hostPort": 80
}
\],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-region": "ap-northeast-1",
"awslogs-group": "/ecs/${SERVICE\_NAME}",
"awslogs-stream-prefix": "${SERVICE\_NAME}"
}
}
}
\]
Ecsのサービスは以下のようになっています。
resource "aws\_ecs\_service" "default" {
name = local.service\_name
cluster = aws\_ecs\_cluster.default.id
task\_definition = aws\_ecs\_task\_definition.default.arn
desired\_count = 2
launch\_type = "FARGATE"
load\_balancer {
target\_group\_arn = aws\_lb\_target\_group.default.arn
container\_name = local.service\_name
container\_port = 80
}
network\_configuration {
subnets = \[
data.terraform\_remote\_state.subnet.outputs.publib\_a\["id"\],
data.terraform\_remote\_state.subnet.outputs.publib\_c\["id"\],
\]
security\_groups = \[
aws\_security\_group.default.id
\]
assign\_public\_ip = true
}
}
LB
resource "aws\_lb" "default" {
name = local.service\_name
internal = false
load\_balancer\_type = "application"
subnets = \[
data.terraform\_remote\_state.subnet.outputs.publib\_a\["id"\],
data.terraform\_remote\_state.subnet.outputs.publib\_c\["id"\],
\]
security\_groups = \[
aws\_security\_group.default.id,
\]
enable\_deletion\_protection = true
access\_logs {
bucket = data.terraform\_remote\_state.buckets.outputs.default\["id"\]
enabled = true
}
}
resource "aws\_lb\_target\_group" "default" {
name = local.service\_name
port = 80
protocol = "HTTP"
vpc\_id = data.terraform\_remote\_state.subnet.outputs.default\["id"\],
target\_type = "ip"
}
VPCとサブネットはバックエンドから参照しています。 また、security groupは別で作成しておいてください。 bucketについては、前述の通り階層を分けているためバックエンドから参照してください。 ターゲットグループのtarget_typeはFargateと連携するためにipに指定しておいてください。
LBへSSL証明書の適用 Certificate Managerに登録してあるSSL証明書を参照しています。
resource "aws\_lb\_listener" "default" {
load\_balancer\_arn = aws\_lb.default.arn
protocol = "HTTPS"
port = "443"
ssl\_policy = "ELB\_SecurityPolicy-TLS-1-2-2017-01"
certificate\_arn = data.terraform\_remote\_state.certificate.outputs.default\["arn"\]
default\_action {
type = "forward"
target\_group\_arn = aws\_lb\_target\_group.default.arn
}
}
80ポートへのアクセスはリダイレクトするようにします。
resource "aws\_lb\_listener" "redirect\_https" {
load\_balancer\_arn = aws\_lb.default.arn
port = "80"
protocol = "HTTP"
default\_action {
type = "redirect"
redirect {
port = "443"
protocol = "HTTPS"
status\_code = "HTTP\_301"
}
}
}
variables
最後に、variablesは以下のようになっています。
variable "environment" {
default = "development"
}
locals {
service\_name = "${var.environment}-service-name"
}
ここでlocalsを使っているのは、環境名などを変数に埋め込むためです。 特に必要ないかもしれないです。
最後に
これからTerraformを導入していきたい、Fargateを使ってみたいという方に少しでも参考になれば。。。
Discussion