[AWS]TerraformでECS FargateでAPIの実行環境を作ってみた

# はじめに
完璧の「璧」って、「壁」じゃなくて「璧」だって知ってました？
僕は知らなくて、最近会社の先輩に言われて初めて気づきました、、、
スマホとかPCで入力するときは勝手に変換してくれているのでいいんですけど、手書きの時は絶対まちがっていただろうなーと思います

はい、では、前回までで、API の作成と GithubActions で CI の構築をしました
せっかくなので、今回は作った API を動かすための AWS 環境を作っていきます

## 実際に動かす方法について
以下の手順を見てください
https://github.com/Ixy-194/go-api-sample-todo-terraform/blob/main/README.md
docker で動くようにしているので、terraform インストールしなくても、docker さえ入ってれば動かせます👍

# 今回のゴール
以下構成の AWS 環境を作ります。terraform で
よくある構成な、シングルリージョン、マルチ AZ 、アプリは ECS 、RDS は Aurora です
API は ECS Fargate で動かす予定で、今回 API のデプロイまではしないので、とりあえずコンテナで nginx を動かしてアクセスできるようにするとこまでやります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974822/c149a8da-d032-9236-2c77-9b0aa786c26c.png)

## Terraform とは？
HashiCorp 社によって開発されたオープンソースの IaC　ツールです
AWS, GCP, Azure 等のクラウドサービスのインフラをコードによって構築することができます

https://www.hashicorp.com/products/terraform

>Terraformとは、 HashiCorp社によって開発された オープンソースのサービス で、 開発環境を効率的に構築できるIaC（Infrastructure as Code）ツールの一種です。クラウドサーバーなどシステム開発に必要なインフラを、コードを記述することにより自動で構築できます。また、インフラの構成管理などもTerraformのコードによる宣言が可能な事も特徴です


### Terraform のメリット
>Terraformを導入する一つ目のメリットは、誰が構築しても同一のインフラ構成となることです。複数の開発者が携わるプロジェクトであっても、開発環境の一貫性を保てます
二つ目のメリットは、工数削減効果です。Terraformでは、一度構築したインフラをもとに設計ができるため、同様の環境を構築する際の工数を削減できます。三つ目のメリットは、Gitによるバージョン管理に対応していることです。GitOpsやDevOpsなどさまざまな管理システムを用いて、テスト環境や本番環境を管理できます

詳細はこちらを参照

https://udemy.benesse.co.jp/development/system/what-is-terraform.html


# AWS 環境の構築
ECS Fargate で API の実行環境を作るにあたり、以下の AWS リソースを作成します
1. VPC
1. RDS(Aurora)
1. ALB
1. ECS
1. ECR
1. Bastion（RDSへの踏み台用サーバ） 

最終的に出来上がるコードの構成はこんな感じです
```
.
├── docker-compose.yml
├── env
│   └── dev
│       ├── main.tf
│       └── provider.tf
└── modules
    ├── alb
    │   ├── main.tf
    │   ├── output.tf
    │   └── variables.tf
    ├── bastion
    │   ├── main.tf
    │   └── variables.tf
    ├── ecr
    │   ├── main.tf
    │   ├── output.tf
    │   └── variables.tf
    ├── ecs
    │   ├── main.tf
    │   └── variables.tf
    ├── rds
    │   ├── main.tf
    │   └── variables.tf
    └── vpc
        ├── main.tf
        ├── outputs.tf
        └── variables.tf
```

では、順々にコードを書いて環境を作っていきます

## VPC
まずは VPC の作成です
VPC とは [Amazon Virtual Private Cloud](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/what-is-amazon-vpc.html) のことで、AWS 上に構築する仮想ネットワーク環境のことです

ここでは、VPC リソースの作成に「[Terraform-aws-modules/vpc/aws](https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/5.0.0)」を使い、以下赤枠内の環境を構築します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974822/6ee6b1c7-e50a-88e8-2fd9-3209e6d217e5.png)


実際のコード
```terraform:env/dev/main.tf
# 共通的に使用する値を変数として定義
locals {
  env = "dev"

  cidr = "192.168.1.0/24"
  public_subnets = ["192.168.1.64/28", "192.168.1.80/28"]
  private_subnets = ["192.168.1.32/28", "192.168.1.48/28"]
  rds_subnets = ["192.168.1.0/28", "192.168.1.16/28"]
  azs = ["ap-northeast-1a", "ap-northeast-1c"]
  service_name = "go-api-sample-todo"
}

module "vpc" {
  source = "../../modules/vpc"

  cidr            = local.cidr
  public_subnets  = local.public_subnets
  private_subnets = local.private_subnets
  rds_subnets     = local.rds_subnets
  azs             = local.azs
  env             = local.env
}
```
`locals`に共通的に使用する値（CIDRとか使用する AZとか）を変数として定義し、`/modules/vpc`を呼び出します

`modules/vpc`には、以下の３ファイルがあります
- main.tf
    - 作成する AWS リソースを定義するファイル
- outputs.tf
    - 戻り値を定義するファイル
⇨ここで作成したリソースの情報を他モジュールでも参照・利用できるように変数に格納する
- variables.tf
    - 引数を定義するファイル

`variables.tf` では以下のように、`env/dev/main.tf`から値を受け取るための引数を定義しています
```terraform:modules/vpc/variables.tf
variable "cidr" {}
variable "public_subnets" {}
variable "private_subnets" {}
variable "rds_subnets" {}
variable "azs" {}
variable "env" {}
```
`main.tf` 
```terraform:modules/vpc/main.tf
#################################################################################
# Network
# Ref. https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/5.0.0

#################################################################################

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"
  version = "5.0.0"

  name = "${var.env}-vpc"
  cidr = var.cidr

  azs              = var.azs
  public_subnets   = var.public_subnets
  private_subnets  = var.private_subnets
  database_subnets = var.rds_subnets
  enable_nat_gateway = true
  enable_vpn_gateway = true

  tags = {
    Terraform   = "true"
    Environment = var.env
  }
}
```
「[Terraform-aws-modules/vpc/aws](https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/5.0.0)」を使うと、これだけの記述で VPC 周りの NW 環境を作れるので便利です

`outputs.tf`
VPC リソースの情報を他のモジュールでも使えるように変数に格納しておきます。
```terraform:modules/vpc/main.tf
output "vpc" {
  value = module.vpc
}
```
これでベースとなるネットワーク環境ができました。

## ALB
ALB とは [Application Load Balancer](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/introduction.html) のことで、いわゆる　ロードバランサーです
リクエストを受けて、背後にあるサービス（今回なら ECS）にいい感じにリクエストを振り分けてルーティングしてくれます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974822/db51fd9c-2c85-978e-9f5b-127ad330e089.png)


`main.tf`
```terraform:modules/alb/main.tf
# ALB
# ALB
resource "aws_lb" "this" {
  name = "${var.env}-alb"

  internal           = false
  load_balancer_type = "application"
  subnets            = var.subnets

  security_groups = [aws_security_group.this.id]
  tags = {
    Name        = "${var.env}-alb"
    Terraform   = "true"
    Environment = var.env
  }
}

# SecurityGroup
resource "aws_security_group" "this" {
  name   = "${var.env}-sg-alb"
  vpc_id = var.vpc_id

  ingress {
    from_port   = 80
    to_port     = 80
    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        = "${var.env}-sg-alb"
    Terraform   = "true"
    Environment = var.env
  }
}
```
これで `terraform apply`をすると、コンソールから ALB が作成されているのがわかります
ただし、現時点では listener（ALBの振り分け先）の指定をしていないので、アクセスすることはできません
次の ECS で listener の作成を行います

## ECS
ECS とは [Amazon Elastic Container Service (Amazon ECS)](https://aws.amazon.com/jp/ecs/)のことで、AWS が作成したフルマネージドなコンテナオーケストレーションサービスです
k8s の AWS 版と思っていればいいと思います

ECS は、大きく3つの要素によって構成されています
- クラスタ
    - タスクとサービスをグループ化するもの
- サービス
    - タスク定義を元にタスク（コンテナ）を立ち上げて、ロードバランサとの紐付けをするもの
- タスク
    - 実際に起動するコンテナ
    - タスク定義（task_definition）の内容を元に生成されたコンテナのこと

ここでは、以下のリソースを作成します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974822/ebd41c5b-9df7-719b-3434-2b811fbfdf2a.png)
実際のコードはこんな感じ
```terraform:modules/ecs/main.tf
# クラスター定義
resource "aws_ecs_cluster" "this" {
  name = "${var.env}-ecs-cluster-${var.service_name}"

  tags = {
    Name        = "${var.env}-ecs-cluster-${var.service_name}"
    Terraform   = "true"
    Environment = var.env
  }
}

# サービス定義
resource "aws_ecs_service" "this" {
  name            = "${var.env}-ecs-service-${var.service_name}"
  cluster         = aws_ecs_cluster.this.id
  task_definition = aws_ecs_task_definition.this.arn

  desired_count    = 1
  launch_type      = "FARGATE"
  platform_version = "1.4.0"

  network_configuration {
    subnets         = var.subnets
    security_groups = [aws_security_group.this.id]
  }
  
  # ALB との紐付け
  load_balancer {
    target_group_arn = aws_lb_target_group.this.arn
    container_name   = var.service_name
    container_port   = "80"
  }

  lifecycle {
    ignore_changes = [desired_count, task_definition]
  }

  tags = {
    Name        = "${var.env}-ecs-service-${var.service_name}"
    Terraform   = "true"
    Environment = var.env
  }
}

# タスク定義
resource "aws_ecs_task_definition" "this" {
  family                   = "${var.env}-task-definition-${var.service_name}"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = 256
  memory                   = 512
  container_definitions = jsonencode([
    {
      name = var.service_name
      # 暫定で nginx を立てる
      # 別途 CD でイメージを上書きする
      image = "nginx:latest"
      logConfiguration : {
        logDriver : "awslogs",
        options : {
          awslogs-region : "ap-northeast-1",
          awslogs-stream-prefix : var.service_name,
          awslogs-group : "/ecs/${var.service_name}/${var.env}"
        }

      }
      portMappings = [
        {
          containerPort = 80
        }
      ]
    }
  ])
  task_role_arn      = aws_iam_role.this.arn
  execution_role_arn = aws_iam_role.this.arn

  tags = {
    Name        = "${var.env}-task-definition-${var.service_name}"
    Terraform   = "true"
    Environment = var.env
  }
}

# ターゲットグループの作成
resource "aws_lb_target_group" "this" {
  name = "${var.env}-alb-tg-${var.service_name}"

  port        = 80
  protocol    = "HTTP"
  target_type = "ip"
  vpc_id      = var.vpc_id

  tags = {
    Name        = "${var.env}-alb-tg-${var.service_name}"
    Terraform   = "true"
    Environment = var.env
  }
}

# listener の作成
resource "aws_lb_listener" "http" {
  port     = "80"
  protocol = "HTTP"
  load_balancer_arn = var.lb.arn

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.this.arn
  }

  tags = {
    Name        = "${var.env}-lb-http-listener-${var.service_name}"
    Terraform   = "true"
    Environment = var.env
  }
}

resource "aws_security_group" "this" {
  name        = "${var.env}-sg-${var.service_name}"
  description = "${var.env}-sg-${var.service_name}"
  vpc_id      = var.vpc_id

  ingress {
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    security_groups = [var.lb_security_group_id]
  }
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name        = "${var.env}-sg-${var.service_name}"
    Terraform   = "true"
    Environment = var.env
  }
}

resource "aws_cloudwatch_log_group" "this" {
  name = "/ecs/${var.service_name}/${var.env}"
}


# 実行ロール
resource "aws_iam_role" "this" {
  name = "${var.env}-ecs-execution-role-${var.service_name}"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "ecs-tasks.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}
resource "aws_iam_role_policy" "this" {
  name = "${var.env}-ecs-execution-role-policy-${var.service_name}"
  role = aws_iam_role.this.id
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "ssm:GetParameters",
          "secretsmanager:GetSecretValue",
        ]
        Effect   = "Allow"
        Resource = "*"
      },
    ]
  })
}

resource "aws_iam_role_policy_attachment" "this" {
  role       = aws_iam_role.this.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

```
これで `terraform apply`をして、 ALB の URL にアクセスすると nginx の画面が表示されるはずです
ALB の URL はコンソール画面から確認できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974822/06f3dede-7dec-895b-e53e-b7ab99e1ed77.png)

ALB の  URL にアクセスしてこんな画面が表示されれば OK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974822/dd3fbb7c-eede-fc3f-3abb-bc62c239753a.png)

## RDS（Aurora）
続いて、[Amazon Aurora](https://aws.amazon.com/jp/rds/aurora/) で DB を作ります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974822/7df9acb1-1ddd-518b-01aa-927d21055003.png)

Amazon Aurora は、AWS が開発したフルマネージドなリレーショナルデータベースのことです

`terraform:env/dev/main.tf` からの呼び出し部分はこんな感じ
```terraform:env/dev/main.tf
module "rds" {
  source = "../../modules/rds"

  env                      = local.env
  vpc_id                   = module.network.vpc.vpc_id
  azs                      = local.azs
  db_subnet_group_name     = module.network.vpc.database_subnet_group
  access_allow_cidr_blocks = module.network.vpc.private_subnets_cidr_blocks
}
```
配置する VPC、AZ、サブネットグループの指定と、アクセスを許可する cider（今回は private subnet からのみアクセス許可する）を指定します

```terraform:modules/rds/main.tf
# 使用する Aurora DB のエンジン、バージョン情報を定義
locals {
  master_username = "admin"
  engine          = "aurora-mysql"
  engine_version  = "8.0.mysql_aurora.3.02.0"
  instance_class  = "db.t4g.medium"
  database_name   = "todo"
}

# RDS
resource "aws_rds_cluster" "this" {
  cluster_identifier = "${var.env}-cluster-${local.database_name}"

  database_name                   = local.database_name
  master_username                 = local.master_username
  master_password                 = random_password.this.result
  availability_zones              = var.azs
  port                            = 3306
  vpc_security_group_ids          = [aws_security_group.this.id]
  db_subnet_group_name            = var.db_subnet_group_name
  db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.this.id
  engine                          = local.engine
  engine_version                  = local.engine_version
  final_snapshot_identifier       = "${var.env}-cluster-final-snapshot-${local.database_name}"
  skip_final_snapshot             = true
  apply_immediately               = true

  tags = {
    Name        = "${var.env}-cluster-${local.database_name}"
    Terraform   = "true"
    Environment = var.env
  }

    lifecycle {
    ignore_changes = [
      availability_zones,
    ]
  }

}

resource "aws_rds_cluster_instance" "this" {
  count              = 1
  identifier         = "${var.env}-${local.database_name}-${count.index}"
  engine             = local.engine
  engine_version     = local.engine_version
  cluster_identifier = aws_rds_cluster.this.id
  instance_class     = local.instance_class
  
  tags = {
    Name        = "${var.env}-${local.database_name}-${count.index}"
    Terraform   = "true"
    Environment = var.env
  }
}

# master_username のパスワードを自動生成
resource "random_password" "this" {
  length           = 12
  special          = true
  override_special = "!#&,:;_"

  lifecycle {
    ignore_changes = [
      override_special
    ]
  }
}


resource "aws_rds_cluster_parameter_group" "this" {
  name   = "${var.env}-rds-cluster-parameter-group-${local.database_name}"
  family = "aurora-mysql8.0"

  parameter {
    name  = "time_zone"
    value = "Asia/Tokyo"
  }
}


# Security Group
resource "aws_security_group" "this" {
  name   = "${var.env}-sg-rds-${local.database_name}"
  vpc_id = var.vpc_id
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name        = "${var.env}-sg-rds-${local.database_name}"
    Terraform   = "true"
    Environment = var.env
  }
}

resource "aws_security_group_rule" "this" {
  type              = "ingress"
  from_port         = 3306
  to_port           = 3306
  protocol          = "tcp"
  cidr_blocks       = var.access_allow_cidr_blocks
  security_group_id = aws_security_group.this.id
}


# 各種パラメータを AWS Systems Manager Parameter Store へ保存
resource "aws_ssm_parameter" "master_username" {
  name      = "/${var.env}/rds/${local.database_name}/master_username"
  type      = "SecureString"
  value     = aws_rds_cluster.this.master_username

  tags = {
    Terraform   = "true"
    environment = var.env
  }
}
resource "aws_ssm_parameter" "master_password" {
  name  = "/${var.env}/rds/${local.database_name}/master_password"
  type  = "SecureString"
  value = aws_rds_cluster.this.master_password

  tags = {
    Terraform   = "true"
    environment = var.env
  }
}

resource "aws_ssm_parameter" "cluster_endpoint" {
  name      = "/${var.env}/rds/${local.database_name}/endpoint_w"
  type      = "SecureString"
  value     = aws_rds_cluster.this.endpoint

  tags = {
    Terraform   = "true"
    environment = var.env
  }
}

resource "aws_ssm_parameter" "cluster_reader_endpoint" {
  name      = "/${var.env}/rds/${local.database_name}/endpoint_r"
  type      = "SecureString"
  value     = aws_rds_cluster.this.reader_endpoint

  tags = {
    Terraform   = "true"
    environment = var.env
  }
}
```
`aws_ssm_parameter`では、生成されたパスワードや RDS のエンドポイントをアプリケーション側から取得できるように、AWS System Manager の[Parameter Store](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/systems-manager-parameter-store.html)に格納しています

これで、`terraform apply`すると、コンソール画面から クラスターとインスタンスが作成され、Parameter Store にも以下で指定したパラメータが保存されています
```
# 各種パラメータを AWS Systems Manager Parameter Store へ保存
resource "aws_ssm_parameter" "master_username" {
  name      = "/${var.env}/rds/${local.database_name}/master_username"
  type      = "SecureString"
  value     = aws_rds_cluster.this.master_username

  tags = {
    Terraform   = "true"
    environment = var.env
  }
}
resource "aws_ssm_parameter" "master_password" {
  name  = "/${var.env}/rds/${local.database_name}/master_password"
  type  = "SecureString"
  value = aws_rds_cluster.this.master_password

  tags = {
    Terraform   = "true"
    environment = var.env
  }
}

resource "aws_ssm_parameter" "cluster_endpoint" {
  name      = "/${var.env}/rds/${local.database_name}/endpoint_w"
  type      = "SecureString"
  value     = aws_rds_cluster.this.endpoint

  tags = {
    Terraform   = "true"
    environment = var.env
  }
}

resource "aws_ssm_parameter" "cluster_reader_endpoint" {
  name      = "/${var.env}/rds/${local.database_name}/endpoint_r"
  type      = "SecureString"
  value     = aws_rds_cluster.this.reader_endpoint

  tags = {
    Terraform   = "true"
    environment = var.env
  }
}
```
画面から確認するとこんな感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974822/ec3b8e96-e2e0-e26b-7173-698b3fd1b44d.png)



## Bastion
EC2 を使って踏み台サーバを構築します
ここでの用途としては、 DB にアクセスするための踏み台サーバです
踏み台といっても外部に公開するのは嫌なので、private subnet に配置し、ssh ではなく、コンソール画面からのみ接続できるようにします

実際のソースコードはこんな感じ
```terraform:modules/bastion/main.tf
# EC2
## 最新の AmazonLinux2 の AMI の ID を取得
data "aws_ssm_parameter" "this" {
  name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}

resource "aws_instance" "centos" { 
  ami                  = data.aws_ssm_parameter.this.value
  instance_type        = "t2.nano"
  subnet_id            = var.subnet_id
  iam_instance_profile = aws_iam_instance_profile.this.name

  vpc_security_group_ids = [aws_security_group.this.id]
  key_name = "centos-bastion"

  tags = {
    Name        = "${var.env}-bastion"
    Terraform   = "true"
    Environment = var.env
  }
}

resource "aws_instance" "this" {
  ami                  = data.aws_ssm_parameter.this.value
  instance_type        = "t2.nano"
  subnet_id            = var.subnet_id
  iam_instance_profile = aws_iam_instance_profile.this.name

  vpc_security_group_ids = [aws_security_group.this.id]

  tags = {
    Name        = "${var.env}-aws-bastion"
    Terraform   = "true"
    Environment = var.env
  }
}


# Security Group
## コンソール画面からしかアクセスしないので、 ingress は設定しない
resource "aws_security_group" "this" {
  name   = "${var.env}-sg-bastion"
  vpc_id = var.vpc_id

  ingress {
    description = "from rivate"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    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        = "${var.env}-sg-bastion"
    Terraform   = "true"
    Environment = var.env
  }
}

# IAM 
## コンソールからセッションマネージャーでアクセスできるように、IAMロールとIAMポリシーを設定
  resource "aws_iam_role" "this" {
    name = "${var.env}-iam-role-bastion"

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

resource "aws_iam_instance_profile" "this" {
  name = "${var.env}-iam-instance-profile-bastion"
  role = aws_iam_role.this.name
}

data "aws_iam_policy" "this" {
  arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

resource "aws_iam_role_policy_attachment" "this" {
  role       = aws_iam_role.this.name
  policy_arn = data.aws_iam_policy.this.arn
}
```
これでわざわざローカルから SSH で接続しなくても、コンソール画面から接続できるので便利ですね


## ECR
最後に ECR の作成です
ECR とは [Amazon Elastic Container Registry](https://aws.amazon.com/jp/ecr/) のことで、AWS が提供するフルマネージドなコンテナイメージレジストリです
docker のコンテナイメージの管理に使います
実際のコードはこんな感じ

```terraform:modules/ecr/main.tf
resource "aws_ecr_repository" "this" {
  name                 = var.service_name
  image_tag_mutability = "MUTABLE"

  image_scanning_configuration {
    scan_on_push = true
  }

  tags = {
    Name        = "${var.env}-ecr-${var.service_name}"
    Terraform   = "true"
    Environment = var.env
  }
}
```
これで `terraform apply`するだけでリポジトリが作れます
簡単ですね

# 最後に
こんな感じで AWS 環境を作ってみました
実際のソースコードはこちら

https://github.com/Ixy-194/go-api-sample-todo-terraform/tree/main

正直、コンソール画面からぽちぽち設定するよりも、 terraform とかで環境をコード化できるっていうのは素晴らしいと思う
作り直しが簡単だし、どこかの手順をが抜けてた！なんてこともないですし
わざわざエクセルとかで手順書なんて作りたくないですからねー

次回は、 この GithubActions でこの terraform のコードを CI/CD してみようと思います
ではでは