はじめに
この記事では、ローカルで作成したGoアプリケーションをTerraformを用いてインフラをコード化し、ECSがECRからDockerイメージを自動的にプルして本番環境にデプロイする手順を紹介します。
この記事は、過去の技術検証内容を組み合わせた実践的な応用例です。
自分用の備忘録も兼ねて、手順や実施内容を詳しくまとめていきます。少しでも参考になれば幸いです。
補足:過去記事の組み合わせによる検証
※注意点
本記事では、以下の記事で取り上げた技術検証を組み合わせて進めています。
1. Go言語用のDockerfileをシェルスクリプトで一括作成する方法👇
2. Dockerfileをローカルで実行し、ブラウザから『Hello, World!』を表示する方法👇
3. DockerイメージをAWS CLIを使ってECRにプッシュする方法👇
Terraformテンプレートの準備
以下は、今回使用したTerraformテンプレートです。このテンプレートには、ECSクラスター、タスク定義、IAMロールなど、必要なリソース設定が含まれています。
注意点として、デプロイするアプリケーションは「ポート1323」で動作するため、containerPort
を正しく指定する必要があります。
# AWSプロバイダーの設定
provider "aws" {
region = "ap-northeast-1"
}
# VPCの作成
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "honda-vpc"
}
}
# パブリックサブネットの作成
resource "aws_subnet" "public1" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.0.0/20"
availability_zone = "ap-northeast-1a"
tags = {
Name = "honda-subnet-public1-ap-northeast-1a"
}
}
# インターネットゲートウェイの作成
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "honda-igw"
}
}
# パブリックルートテーブルの作成
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
tags = {
Name = "honda-rtb-public"
}
}
# パブリックルートの設定
resource "aws_route" "public_route" {
route_table_id = aws_route_table.public.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main.id
}
# サブネットとルートテーブルの関連付け
resource "aws_route_table_association" "public_subnet_association" {
subnet_id = aws_subnet.public1.id
route_table_id = aws_route_table.public.id
}
# セキュリティグループの作成(ECS用)
resource "aws_security_group" "ecs_sg" {
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 1323
to_port = 1323
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "ecs-sg"
}
}
# ECSクラスターの作成
resource "aws_ecs_cluster" "main" {
name = "my-ecs-cluster"
}
# ECSタスク実行ロールの作成
resource "aws_iam_role" "ecs_task_execution_role" {
name = "ecs-task-execution-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "ecs-tasks.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
inline_policy {
name = "ecs-task-execution-policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"ecr:GetAuthorizationToken",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"logs:CreateLogStream",
"logs:PutLogEvents",
"s3:GetObject"
]
Resource = "*"
}
]
})
}
}
# ECSタスク定義の作成
resource "aws_ecs_task_definition" "main" {
family = "my-app-task"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = "256"
memory = "512"
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
container_definitions = jsonencode([
{
name = "my-app-repo"
image = "xxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-app-repo"
portMappings = [
{
containerPort = 1323
hostPort = 1323
protocol = "tcp"
}
]
}
])
}
# ECSサービスの作成
resource "aws_ecs_service" "main" {
name = "my-ecs-service"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.main.arn
desired_count = 1
launch_type = "FARGATE"
network_configuration {
subnets = [aws_subnet.public1.id]
security_groups = [aws_security_group.ecs_sg.id]
assign_public_ip = true
}
}
今回は、過去の記事で作成したテンプレートを基に、コンテナとホストのポート設定、およびセキュリティグループ周りの設定を修正しました。
実際に動かしてみた
ここでは詳細な使い方は省略しますが、私はCloudShellを使ってTerraformを実行しています。
詳しく知りたい方は、過去の記事で紹介していますので、ぜひ参考にしてみてください。
デプロイ後の動作確認
デプロイが完了したら、タスクが正常に実行されていることを確認します。ここでは、ECRのイメージコンテナからプルされていることも合わせて確認しました。
ECSページの「クラスター」→「タスク」タブから、実行中のタスクを選択し、タスクのパブリックIPを確認します。
http://52.195.176.91:1323/
ここで、タスクが使用しているパブリックIP(例:52.195.176.91
)を確認したら、ブラウザでアクセスしてみます。
想定通り、Goアプリが正常に動作し、Hello, World!
と表示されることを確認できました!
まとめ
ここまでお読みいただき、ありがとうございました。今回の記事は、過去の複雑な技術検証を組み合わせた内容となりましたが、無事にまとめることができて本当によかったです。
ただ、CloudFormationで同じことをしていた経験があったため、その知識を活用して比較的スムーズに進めることができました。
この記事がどなたかの技術的な参考になれば幸いです!