はじめに
webアプリ(フロントとバックエンドを分けた)をいきなりECS on Fargate × Terraformで構築するのは難しそうなので、今回は難易度をグッと下げてNginxサーバーを立ち上げてみました。ゴールはタスクのパブリックIPからNginxサーバーの初期画面にアクセスできることです。
環境
MacBook Pro intel
macOS Monterey バージョン12.6
Terraform v1.4.5
Docker version 20.10.21
VPC、サブネット、セキュリティグループ、タスク実行ロールはデフォルトを使用します。
手順
- Dockerfileの作成
- ECR リポジトリの作成
- リポジトリにイメージをpush
- ECS クラスターの作成
- タスク定義の作成
- サービスの作成
Dockerfileの作成
NginxのDockerfileを作成します。
FROM nginx:latest
ECR リポジトリの作成
空のプライベートリポジトリを作成し、ここで一旦applyします。
### ECR ###
resource "aws_ecr_repository" "nginx_repo" {
name = "nginx-repo"
}
リポジトリにイメージをpush
マネジメントコンソールのプッシュコマンドを参考に、作成したリポジトリにビルドしたDockerイメージをpushします。今回はバージョンが分かるようにタグ付けしました。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
123456789098.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-img v1 hog1e1b34az5 2 weeks ago 143MB
nginx-img v1 hog1e1b34az5 2 weeks ago 143MB
# リポジトリへpush
docker push 123456789098.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-img:v1
ECS クラスターの作成
これからECSを構築していきます。クラスターを作成します。
### クラスター ###
resource "aws_ecs_cluster" "cluster" {
name = "cluster"
}
タスク定義の作成
Webサーバーを立ち上げるだけなので特に設定する箇所はありませんが、container_definitionsのimageには正確なリポジトリのURIを指定します。オプションでタグ付け(-t)していない場合は、:latestを加えます。
### タスク定義 ###
resource "aws_ecs_task_definition" "task_def" {
family = "task-def"
cpu = 512
memory = 1024
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
execution_role_arn = module.ecs_task_execution_role.iam_role_arn
container_definitions = jsonencode([
{
name = "nginx-container"
image = "${aws_ecr_repository.nginx_repo.repository_url}:v1"
memory = 512
essential = true
portMappings = [
{
containerPort = 80
hostPort = 80
protocol = "tcp"
}
]
}
])
}
### タスク実行ロール ###
# ~省略~
aws_ecr_repository.リポジトリ名.repository_urlでは正確なURIを取得できません。
$ terraform state show aws_ecr_repository.nginx_repo
# aws_ecr_repository.nginx_repo:
resource "aws_ecr_repository" "nginx_repo" {
arn = "arn:aws:ecr:ap-northeast-1:123456789098:repository/nginx-repo"
id = "nginx-repo"
image_tag_mutability = "MUTABLE"
name = "nginx-repo"
registry_id = "123456789098"
repository_url = "123456789098.dkr.ecr.ap-northeast-1.amazonaws.com/nginx-repo"
# ~省略~
}
サービスの作成
最後の作業です!クラスターのサービスにタスク定義を読み込ませます。applyすればNginxにアクセスできます!
resource "aws_ecs_service" "service" {
name = "service"
cluster = aws_ecs_cluster.cluster.arn
task_definition = aws_ecs_task_definition.task_def.arn
desired_count = 1
launch_type = "FARGATE"
platform_version = "1.4.0"
network_configuration {
subnets = data.aws_subnets.default.ids
security_groups = [data.aws_security_group.default.id]
assign_public_ip = true
}
lifecycle {
ignore_changes = [task_definition]
}
}
あとがき
マネジメントコンソールを操作したのはECRのプッシュコマンドを確認した時だけです。凄いぞTerraform!(ただのタグの付け替えなので確認しなくても出来ますが笑)
今回の構成にCI/CDパイプラインを組み込むことで、アプリのソースコードを更新するたびわざわざDockerイメージをpushする手間も省けます。