あめがえるのITブログ

頑張りすぎない。ほどほどに頑張るブログ。

TerraformでAmazon ECS(Fargate)を作成してみた

今回はTerraformでECS(Fargate)作成に挑戦してみた。

やること

TerraformでECS(Fargate)を作成、Serviceにはnginxを稼働させ、インターネット越しから接続できるよう環境を整え、インターネットからnginxのWelcomeページが表示できることを確認する。

前提

 ・Windows11で実施してます。
  ※Linuxで参考にする場合は"(ダブルクォーテーション)などを適宜変更要。
 ・jqがインストールされていること。
  ※なくてもいいですがCLIで調べるのが面倒になります
 ・aws vaultが設定されていること。
  ※設定していない場合は適宜profile周りを変更する
  ※設定方法は下記参照
amegaeru.hatenablog.jp

作成リソース

 ・VPC×1
 ・Subnet×2
 ・InternetGateway×1
 ・RouteTable×2
 ・IAMRole×1
 ・SecurityGroup×1
 ・SecurityGroup Rule×1
 ・ECS Cluster×1
 ・ECS TaskDefinition×1
 ・ECS Service×1
 

実践!

1.イメージ選定
 今回はサンプルでDocker-Hubからnginx:latestを使用する。

2.作成
2-1.tfファイル作成

provider "aws" {
    region = "ap-northeast-1"
    profile = "testvault"
}
variable "env" {
    default = {
        env_name = "test"
    vpc_cidr = "10.0.0.0/16"
    sb_az1a = "ap-northeast-1a"
    sb_az1a_cidr = "10.0.1.0/24"
    sb_az1c = "ap-northeast-1c"
    sb_az1c_cidr = "10.0.2.0/24"
    }
}

### VPC
resource "aws_vpc" "vpc" {
    cidr_block = "${var.env.vpc_cidr}"
    tags = {
        Name = "${var.env.env_name}_vpc"
    }
}

### Subnet
resource "aws_subnet" "public_1a" {
  vpc_id = "${aws_vpc.vpc.id}"
  availability_zone = "${var.env.sb_az1a}"
  cidr_block        = "${var.env.sb_az1a_cidr}"
  tags = {
    Name = "${var.env.env_name}_public_1a"
  }
}

resource "aws_subnet" "public_1c" {
  vpc_id = "${aws_vpc.vpc.id}"
  availability_zone = "${var.env.sb_az1c}"
  cidr_block        = "${var.env.sb_az1c_cidr}"
  tags = {
    Name = "${var.env.env_name}_public_1c"
  }
}

### InternetGateway
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name = "${var.env.env_name}_igw"
  }
}

### RouteTable
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }

  tags = {
    Name = "${var.env.env_name}_public_route_table"
  }
}

resource "aws_route_table_association" "public_1a" {
  subnet_id      = aws_subnet.public_1a.id
  route_table_id = aws_route_table.public.id
}

resource "aws_route_table_association" "public_1c" {
  subnet_id      = aws_subnet.public_1c.id
  route_table_id = aws_route_table.public.id
}

### SecurityGroup
resource "aws_security_group" "my_sg" {
  name        = "${var.env.env_name}_my-sg"
  description = "My security group for ECS tasks"
  vpc_id      = aws_vpc.vpc.id
}

resource "aws_security_group_rule" "ingress_http" {
  type        = "ingress"
  from_port   = 80
  to_port     = 80
  protocol    = "tcp"
  cidr_blocks = ["0.0.0.0/0"]
  security_group_id = aws_security_group.my_sg.id
}

resource "aws_security_group_rule" "egress_all" {
  type        = "egress"
  from_port   = 0
  to_port     = 0
  protocol    = "-1"
  cidr_blocks = ["0.0.0.0/0"]
  security_group_id = aws_security_group.my_sg.id
}

### IAM Role
resource "aws_iam_role" "ecs_execution_role" {
  name = "${var.env.env_name}_ecs_execution_role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Action = "sts:AssumeRole",
        Principal = {
          Service = "ecs-tasks.amazonaws.com"
        },
        Effect = "Allow",
        Sid    = ""
      }
    ]
  })
}

### ECS Cluster
resource "aws_ecs_cluster" "my_cluster" {
  name = "${var.env.env_name}_my_cluster"
}

### ECS TaskDefinition
resource "aws_ecs_task_definition" "my_task" {
  family                   = "${var.env.env_name}_my_task"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = "256"
  memory                   = "512"
  execution_role_arn       = aws_iam_role.ecs_execution_role.arn

  container_definitions = jsonencode([
    {
      name  = "${var.env.env_name}_my_container"
      ## 1.で決めたイメージを記載する。※サーバを指定しない場合、Docker-Hubから取得される。
      image = "nginx:latest"
      portMappings = [
        {
          containerPort = 80
          hostPort      = 80
        }
      ]
    }
  ])
}

### ECS Service
resource "aws_ecs_service" "my_service" {
  name            = "${var.env.env_name}_my_service"
  cluster         = aws_ecs_cluster.my_cluster.id
  task_definition = aws_ecs_task_definition.my_task.arn
  launch_type     = "FARGATE"
 desired_count    = 2

  network_configuration {
    subnets = [aws_subnet.public_1a.id, aws_subnet.public_1c.id]
    security_groups = [aws_security_group.my_sg.id]
    assign_public_ip = true
  }
}

2-2.適用

# terraform plan
# terraform apply

2-3.確認

### VPC
# aws ec2 describe-vpcs --profile testvault | jq ".Vpcs[] | .CidrBlock"
"100.0.0/16"
### Subnet
# aws ec2 describe-subnets --profile testvault | jq ".Subnets[] | .Tags[]?.Value "
"test_public_1a"
"test_public_1c"
### InternetGateway
# aws ec2 describe-internet-gateways --profile testvault | jq ".InternetGateways[] | .Tags[].Value"
"my-internetgw"
### RouteTable
# aws ec2 describe-route-tables --profile testvault | jq ".RouteTables[] | .Associations[].RouteTableId"
"rtb-00646f022be6c7ce8"
### SecurityGroup
# aws ec2 describe-security-groups --profile testvault | jq ".SecurityGroups[] | .GroupName" | findstr "test"
"test_my-sg"
### IAM Role
# aws iam list-roles --profile testvault | jq ".Roles[] | .RoleName" | findstr "test"
"test_ecs_execution_role"
### ECS Cluster
# aws ecs list-clusters --profile testvault | jq ".clusterArns[]"
"arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:cluster/test_my_cluster"
### ECS TaskDefinition
# aws ecs list-task-definitions --profile testvault | jq ".taskDefinitionArns" | findstr "test"
"arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:task-definition/test_my_task:1"
### ECS Service
# aws ecs list-services --cluster test_my_cluster --profile testvault | jq ".serviceArns "
"arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:service/test_my_cluster/test_my_service"

2-4.動作確認
 2-4-1.[ECS]-[クラスター]-[test-my-cluster]-[test_my-service]-[タスク]タブ-タスクを1つ選択し、パブリックIPをメモする。




 2-4-2.ブラウザで下記にアクセスし、Welcomのページが表示されることを確認する。

http://[パブリックIP]



3.後始末

# terraform destroy



感想

結構作るものが多くて大変だった。(´Д`)