Amazon ECS 入門ハンズオンの環境をTerraformで作成する
本記事では、以下のAmazon ECS 入門ハンズオンの環境をTerraformで作成する具体的な手順を紹介します。
catalog.us-east-1.prod.workshops.aws
AWSでコンテナを用いたシステムを構築する際にはECSが有力な選択肢であるため、有用なハンズオンになっていると思います。 なお、環境構築をする際のオプション的な要素であるため、作業環境となるAWS Cloud9については環境構築の対象外としています。
全体のソースコードは以下にあります
手順
コンテナイメージの作成
最初に以下の内容の通りにECSで動かす対象となるコンテナのイメージを作成します。
コンテナイメージの作成
ECRにアップロード
コンテナイメージをアップロードする先になるECRのリポジトリを作成します。
リポジトリを作成するためのTerraformのコードは以下です。
ecr.tf
resource "aws_ecr_repository" "main" { name = "h4b-ecs-helloworld" force_delete = true } output "repository_url" { value = aws_ecr_repository.main.repository_url }
Terraformで環境を作成する際には、初回のみterraform init
を実行し、環境を更新するたびにterraform apply
を実行します。
$ terraform init $ terraform apply Outputs: repository_url = "xxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/h4b-ecs-helloworld"
リポジトリのURLが出力されますので、このURLに合わせてコンテナイメージのタグ名を変更して、ECRのリポジトリにアップロードできるようにします。
$ docker build -t xxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/h4b-ecs-helloworld:0.0.1 .
コンテナイメージをリポジトリにアップロード(push)するために、docker login が必要です。成功した場合、Login Succeededという出力があります。
$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin xxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com Login Succeeded
コンテナイメージをECRにアップロードします。
$ docker push xxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/h4b-ecs-helloworld:0.0.1
VPCの作成
ECS クラスターを作成するために、新しくVPC を作成します。Terraformのコードは以下です。
VPCとパブリックサブネットを2つ作成します。また、デフォルトのセキュリティグループの設定を変更し、HTTPのプロトコルでのアクセスを許可するようにします。
vpc.tf
resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" enable_dns_support = true enable_dns_hostnames = true tags = { Name = "h4b-ecs" } } resource "aws_subnet" "public1" { vpc_id = aws_vpc.main.id cidr_block = "10.0.0.0/20" availability_zone = "ap-northeast-1a" tags = { Name = "h4b-ecs-public1-ap-northeast-1a" } } resource "aws_subnet" "public2" { vpc_id = aws_vpc.main.id cidr_block = "10.0.16.0/20" availability_zone = "ap-northeast-1c" tags = { Name = "h4b-ecs-public2-ap-northeast-1c" } } resource "aws_internet_gateway" "main" { vpc_id = aws_vpc.main.id tags = { Name = "h4b-ecs" } } resource "aws_route_table" "public" { vpc_id = aws_vpc.main.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.main.id } tags = { Name = "h4b-ecs-rtb-public" } } resource "aws_route_table_association" "public1" { subnet_id = aws_subnet.public1.id route_table_id = aws_route_table.public.id } resource "aws_route_table_association" "public2" { subnet_id = aws_subnet.public2.id route_table_id = aws_route_table.public.id } resource "aws_default_security_group" "default" { vpc_id = aws_vpc.main.id ingress { protocol = -1 self = true from_port = 0 to_port = 0 } ingress { protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] from_port = 80 to_port = 80 } egress { protocol = -1 cidr_blocks = ["0.0.0.0/0"] from_port = 0 to_port = 0 } }
ECSクラスターの作成
ECSクラスターは、コンテナを動かすための論理的なグループです。ECSを操作するために、まずは ECSクラスターを作成していきます。Terraformのコードは以下です。
ecs.tf
resource "aws_ecs_cluster" "main" { name = "h4b-ecs-cluster" }
タスク定義の作成
タスク定義とは、アプリケーションを動かすために、どのようにコンテナを動かすか、コンテナの動作を定義したものです。Terraformのコードは以下です。
ecs.tf
locals { container_name = "apache-helloworld" } resource "aws_ecs_task_definition" "main" { family = "h4b-ecs-task-definition" cpu = 512 memory = 1024 requires_compatibilities = ["FARGATE"] execution_role_arn = aws_iam_role.ecs_task_execution_role.arn network_mode = "awsvpc" container_definitions = <<-EOS [ { "name": "${local.container_name}", "image": "${aws_ecr_repository.main.repository_url}:0.0.1", "cpu": 0, "portMappings": [ { "name": "${local.container_name}", "containerPort": 80, "hostPort": 80, "protocol": "tcp", "appProtocol": "http" } ], "essential": true, "environment": [], "environmentFiles": [], "mountPoints": [], "volumesFrom": [], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-create-group": "true", "awslogs-group": "/ecs/h4b-ecs-task-definition", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "ecs" } } } ] EOS runtime_platform { cpu_architecture = "X86_64" operating_system_family = "LINUX" } }
タスク定義ではタスク実行ロールというIAMロールを設定する必要があります。以下のTerraformのコードでそのIAMロールを作成します。
このIAMロールにより、ECRリポジトリからコンテナイメージを取得する、CloudWatch Logsにコンテナログを送信するといった許可を与えます。
iam.tf
resource "aws_iam_role" "ecs_task_execution_role" { name = "h4b-ecs-task-execution-role" assume_role_policy = <<-EOS { "Version": "2008-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "ecs-tasks.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOS } resource "aws_iam_policy" "ecs_task_execution_role_policy" { name = "h4b-ecs-task-execution-role-policy" policy = <<-EOS { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken", "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage", "logs:CreateLogStream", "logs:PutLogEvents", "logs:CreateLogGroup" ], "Resource": "*" } ] } EOS } resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" { role = aws_iam_role.ecs_task_execution_role.name policy_arn = aws_iam_policy.ecs_task_execution_role_policy.arn }
サービスの作成
サービスを使用すると、ECSクラスターで、指定した数のコンテナ群(タスク)を維持できます。一般的には、長期間動かすアプリケーションに適しています。
Terraformのコードは以下です。
ecs.tf
resource "aws_ecs_service" "main" { name = "h4b-ecs-service" cluster = aws_ecs_cluster.main.id task_definition = aws_ecs_task_definition.main.arn launch_type = "FARGATE" desired_count = 2 network_configuration { subnets = [ aws_subnet.public1.id, aws_subnet.public2.id ] security_groups = [ aws_default_security_group.default.id ] assign_public_ip = true } load_balancer { target_group_arn = aws_lb_target_group.main.arn container_name = local.container_name container_port = 80 } }
サービスを作成する際にロードバランサーも必要になります。 ロードバランサーにアクセスが来ると、ロードバランサーを経由してECSサービスで起動するタスクに接続される形になります。
lb.tf
resource "aws_lb" "main" { name = "h4b-ecs-alb" internal = false load_balancer_type = "application" security_groups = [aws_default_security_group.default.id] subnets = [aws_subnet.public1.id, aws_subnet.public2.id] } resource "aws_lb_listener" "main" { load_balancer_arn = aws_lb.main.arn port = "80" protocol = "HTTP" default_action { type = "forward" target_group_arn = aws_lb_target_group.main.arn } } resource "aws_lb_target_group" "main" { name = "h4b-ecs-targetgroup" port = 80 protocol = "HTTP" vpc_id = aws_vpc.main.id target_type = "ip" }
これで環境作成は完了です。
サービス→ ネットワーキング→ロードバランサーのDNS名にアクセスするとHello World! と表示されてアクセスできるはずです。
まとめ
この記事では、Amazon ECS 入門ハンズオンの環境をTerraformで作成する手順を紹介しました。
Terraformを使用することで、以下のメリットがあります。
- インフラのコード化: 環境構築の手順をコードで管理することで、再現性と柔軟性が向上します。
- バージョン管理: インフラの変更履歴をGitなどのバージョン管理システムで追跡できます。
- 環境の再利用: 同じ環境を複数のプロジェクトやチームで再利用できます。
- 簡易化されたデプロイ: Terraformを使うことで、インフラのデプロイが簡単になり、ミスを減らすことができます。
これらのメリットを活かし、ECSを利用したシステム構築を効率的に行うことができます。
宣伝
以下のUdemy講座を公開しています。AWSやTerraformの入門から実践的な内容までを学べるものになっています。ぜひ受講ください。