AWS の ECS Fargate を使って本番環境を構築していますが、 Terraform だけだと環境構築が若干複雑になるのが悩みでした。
そこで、 Fargate CLI と Terraform を組み合わせると、非常にシンプルでいい感じになりました。
[追記]
最近は、 Fargate CLI をやめて素の AWS CLI でやっています。
完全自動構築を目指す場合、その方が確実だな思いました。詳しくは下記。
AWS Fargate サービスを Terraform で構築、 コマンドラインからデプロイ
[/追記]
デモ: https://github.com/acro5piano/terraform-fargate-example
概要
- Terraform を使って、 AWS ECS に必要な基本的な環境を構築する
- Fargate CLI で Fargate のサービスやタスク定義などを構築する
- デプロイは Fargate のおかげでダウンタイム無し
モチベーション
AWS の ECS Fargate を使って本番環境を構築する場合、いくつかの選択肢があります。
- 管理画面からぽちぽち
- AWS CLI
- ECS CLI
- Terraform
- Fargate CLI
それぞれ、
- は属人的になるのでやりたくない。
- は設定が大変なのと、元に戻せないため、管理画面ぽちぽちするのとあまり変わらない。
- はセキュリティグループや ALB の設定などは結局管理画面からやらないといけない。
- は全てコード化でき、再適用や複製などもできるが、構築スクリプトがちょっと長くなる。そしてデプロイは単体ではできない。(できるけど Terraform 完全管理だと、運用上やりづらい)
- はセキュリティグループの設定などは結局管理画面からやらないといけない。
そこで、 4. と 5. を組み合わせて、いいとこ取りしようという話です。
完成品はこちらをご覧ください。
やり方
簡単な Web App を作る前提で進めます。
Dockerfile
ポート 3000 を Listen できれば、何でも良いです。
FROM python:3.7.7-alpine3.11
CMD python -m http.server 3000
Terraform
Terraform は、下記を作成する役割を持っています。
- ECS クラスター (Fargate のサービスを動かすもの)
- Security Group (ファイアーウォール) 下記2つ
- ALB
- ECS ( ALB との通信のみを許可する)
aws-credentials.ini
の置き場所やリージョンはプロジェクトによると思うので、適宜置き換えて下さい。
# この辺の設定は環境によります
provider "aws" {
region = "ap-northeast-1"
shared_credentials_file = "./aws-credentials.ini"
profile = "default"
}
resource "aws_ecs_cluster" "webapp" {
name = "webapp"
}
resource "aws_security_group" "webapp" {
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 3000
to_port = 3000
protocol = "tcp"
security_groups = [aws_security_group.webapp_lb.id]
}
}
resource "aws_security_group" "webapp_lb" {
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
output "webapp_ecs_security_group" {
value = aws_security_group.webapp.id
}
output "webapp_lb_security_group" {
value = aws_security_group.webapp_lb.id
}
Fargate CLI で使う値は、 Terraform の output
機能で、簡単に取得できるようにしています。
Fargate CLI
次に、 Fargate CLI でサービスを作成します。
Fargate CLI のインストールは、下記からバイナリをダウンロードしてください。
やや長いのでスクリプトにしました。
aws-credentials.ini
の置き場所やリージョンはプロジェクトによると思うので、適宜置き換えて下さい。
#!/bin/bash
export AWS_SHARED_CREDENTIALS_FILE=$PWD/aws-credentials.ini
export AWS_PROFILE=default
export AWS_REGION=us-east-1
# 先に ALB を作成する
fargate lb create webapp \
--cluster webapp \
--port HTTP:80 \
--security-group-id `terraform output webapp_lb_security_group`
# 次に Fargate のサービスを作成する
fargate service create webapp \
--cluster webapp \
--lb webapp \
--num 1 \
--port HTTP:3000 \
--cpu 256 \
--memory 512 \
--security-group-id `terraform output webapp_ecs_security_group`
fargate service create
コマンドには、 --image
で ECR を明示的に指定することもできますが、何も指定しないことで
- 現在のディレクトリにある
Dockerfile
をビルド - ビルドした Dockerfile を ECR にプッシュ
- その ECR をイメージに指定してサービスを作成
という挙動をしてくれます。
確認する
サービスができたことを確認します。
$ fargate lb list --cluster webapp
NAME TYPE STATUS DNS NAME PORTS
webapp Application Active webapp-xxxxxxxxxx.us-east-1.elb.amazonaws.com HTTP:80
出力の webapp-xxxxxxxxxx.us-east-1.elb.amazonaws.com
を開くと、サービスができていると思います。
作成されたもの一覧
By Terraform:
- ECR Repository
- ECS Cluser
- EC2 Security Group
By Fargate CLI:
- ECS Task Definition
- ECS Service
- ECS Task
- ECS Task Execution Role
- ALB
- ALB Target Group
- CloudWatch Log Group
更新する
$ fargate service deploy webapp --cluster webapp
消す
残念ながら Fargate CLI 自体には冪等性はありませんが、消すことはできます。
$ fargate service scale webapp 0 --cluster webapp
$ fargate service destroy webapp --cluster webapp
$ fargate lb destroy webapp
$ terraform destroy
Note: ECS Execution Role will not be deleted.
まとめ
簡潔になりましたが、これを基にデプロイのスクリプトなども容易に作れると思います。
下記のデモのリポジトリでは、 Makefile や fargate コマンドのラッパーを使って、より簡潔にしています。良かったらご覧ください。