TerraformでECRにリポジトリを作る

## はじめに

AWSのようなIaaSを利用使用している会社だと、
TerraformなどのIaC(Infrastructure as Code)を使用していることが
検討していることが多いと思います。

インフラの勉強としてTerraformを勉強してみようとしても
でも、Terraform入門で調べてみても、ものすごく簡単な内容であったり、
解説がざっくりとしていて、結局よくわからないという話を聞くことがあったので、
今回はECRを例に挙げて少し丁寧めに解説してみようと思います。

### この記事を読むことで得られること
1. Terraformをとりあえず動かすことができるようになる
1. Terraformの最低限の構文が理解できるようになる
1. Terraformを使ってAmazon ECR(Elastic Container Registry)を構築するための最小限のコードが理解できる

## 前提条件
- Terraformがインストールされていること
    - tfenvを使ったインストール方法については多くの記事が出回っているので、この記事では割愛します
- AWSアカウントを持っていること
    - AWSコンソールからIAMを作成したり、`IAM Identity Center`でアカウントを作って、ログインできるようにしておく
- AWS CLIがインストールされていること
    - aws-cliのインストールについても多くの記事が出回っているので、この記事では割愛します

### 下記が確認できれば準備完了
- tfenv, aws-cliの確認
``` bash
$ tfenv -v       
tfenv 3.0.0

$ aws --version
aws-cli/2.15.34 Python/3.11.9 Darwin/23.2.0 source/arm64 prompt/off
```

- credential, config情報の確認
    - Linux または macOS ~/.aws/config
    - Windows C:\Users\USERNAME.aws\config
``` bash
# ~/.aws/config
[profile user1]
sso_session = my-sso
sso_account_id = 444455556666
sso_role_name = readOnly
region = us-east-1
output = json

[sso-session my-sso]
sso_region = us-east-1
sso_start_url = https://my-sso-portal.awsapps.com/start
sso_registration_scopes = sso:account:access

# ~/.aws/credentials
# 下記情報は、AWS アクセスポータルから取得する
[sso-session my-sso]
sso_region = us-east-1
sso_start_url = https://my-sso-portal.awsapps.com/start

```
[参考：設定ファイルと認証情報ファイルの設定](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-files.html)

### 留意点
- テラフォームは細かくファイルを分割しても、一つのファイルにまとめて記載しても稼働します。今回は、複数のファイルに分ける形式で進めます
- terraformはバージョンによって、記述内容が異なることもあります

### ディレクトリイメージ
```
terraform
┠ provider.tf
┠ ecr.tf

```

# Step1：プロバイダーを指定する
- 意図：AWSを使いますよ。ということがわかるようにするします
- ※AWS_DEFAULT_REGION環境変数にデフォルトリージョン(configファイルのregionの項目です)が設定されている場合、Terraformは自動的にAWSプロバイダーを初期化してくれます
    - デフォルトリージョンが設定されていない場合は、下記のようprovider.tfファイルを作成します
``` terraform
# terraform/provider.tf

# AWSプロバイダーの設定
provider "aws" {
  # デフォルトリージョン（自身のアカウントを作成したリージョン）
  region = "us-east-1"

  # 使用するプロファイル名（プロファイルを使用しない場合や環境変数に登録図の場合は省略可）（configやconfidentialsに記載したプロファイル名（[plofile]←この値））
  profile = "profile"

  # デフォルトタグの設定（タグを設定しない場合は省略可）
  # 作成されるすべてのリソースに付与される
  default_tags {
    tags = {
      # 環境名
      Env = "prod"
      # システム名
      System = "terraform-sample"
    }
  }
}

# Terraformの設定
terraform {
  # 必要なプロバイダー
  required_providers {
    aws = {
      # プロバイダーソース
      source = "hashicorp/aws"

      # プロバイダーバージョン
      # バージョン指定は省略可能
      version = "~> 5.42.0" # 最新のマイナーバージョンを使用
    }
  }

  # 必要なTerraformバージョン
  required_version = "1.7.4"
}

```

# Step2：作成するECRの内容を作成する
## 記述テンプレ
``` terraform
# resource "リソースの種類" "リソースに付ける名前(terraform管理上の名前)" {
#   // このリソースの設定に使用する様々な引数
# }
```

``` terraform
# terraform/ecr.tf

resource "aws_ecr_repository" "nginx" {
  # リポジトリ名
  # リポジトリ名は、英数字、ハイフン、アンダースコアのみ使用可能
  # 長さは2～256文字
  name = "terraform-prod-nginx"

  # タグ
  # タグは、リポジトリを整理したり、検索したりするために使用できる
  tags = {
    # 名前タグ (必須)
    # リポジトリを識別するための名前
    Name = "terraform-prod-nginx"
  }
}
```

# 実行する:terraformを初期化する
### 1. terraformディレクトリに移動して、下記コマンドを実行
1. プロバイダーのバイナリをダウンロードし、必要なモジュールをインストールする
2. `terraform.tfstate`ファイルが作成される
``` bash
# terraformの設定を初期化する
$ terraform init


Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "5.42.0"...
- Installing hashicorp/aws v5.42.0...
- Installed hashicorp/aws v5.42.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
```

## ２. 実際に実行される変更内容を詳細にシミュレーション
- リソースの作成、更新、削除など、すべての変更を確認できる
``` bash
$ terraform plan

erraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_ecr_repository.nginx will be created
  + resource "aws_ecr_repository" "nginx" {
      + arn                  = (known after apply)
      + id                   = (known after apply)
      + image_tag_mutability = "MUTABLE"
      + name                 = "terraform-prod-nginx"
      + registry_id          = (known after apply)
      + repository_url       = (known after apply)
      + tags                 = {
          + "Name" = "terraform-prod-nginx"
        }
      + tags_all             = {
          + "Env"    = "prod"
          + "Name"   = "terraform-prod-nginx"
          + "System" = "terraform-sample"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

```

### 出力内容の解説
#### image_tag_mutability
- ECRリポジトリにおけるイメージタグの変更可能性で、以下の2つの値存在する
    - MUTABLE: タグを更新可能（デフォルト）
    - IMMUTABLE: タグを更新不可


#### tags_all
- Terraform独自の属性
- `tags_all`の部分には下記の内容が設定される
  - `provider.tf`の`provider`ブロックで指定したデフォルトのタグ
  - リソース個別に指定したタグ(tagsの内容)
- サンプルの例だと、最終的に、AWSリソースとしてのECRのタグには`Env`, `Name`, `System`が設定される

#### known after apply
- 「リソースのID」「リソースのURN」「リソースの状態」を表す
- サンプルの例だと、「1 to add」と表示されているが、これはリソースがひとつ追加されることを意味している
- `change`は、リソースの更新有無、`destroy`は、リソースの削除を意味している
    - サンプルの例だと、リソースの変更や削除はない(0である)ことを示している


#### チェックポイント
- `plan`後はまず最初にこの最終行を見て意図した通りにリソースが作成、変更、削除されようとしているか確認する
- その後、リソース個別の変更内容を確認する


## 実際にAWSにリソースを作成する
- `terraform plan`実行時とほとんど同じ内容が出力される
    - 最終行の`Enter a value:`で`yes`を入力すると実際にリソースが作成される
``` bash
$ terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_ecr_repository.nginx will be created
  + resource "aws_ecr_repository" "nginx" {
      + arn                  = (known after apply)
      + id                   = (known after apply)
      + image_tag_mutability = "MUTABLE"
      + name                 = "terraform-prod-nginx"
      + registry_id          = (known after apply)
      + repository_url       = (known after apply)
      + tags                 = {
          + "Name" = "terraform-prod-nginx"
        }
      + tags_all             = {
          + "Env"    = "prod"
          + "Name"   = "terraform-prod-nginx"
          + "System" = "terraform-sample"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: 

# yesを入力する
aws_ecr_repository.nginx: Creating...
aws_ecr_repository.nginx: Creation complete after 2s [id=terraform-prod-nginx]

```

AWSのコンソールで、Amazon Elastic Container Registryに行くと、
実際にリソースが作成されていることを確認できます。

## まとめ
Terraformを使ってECRを構築するためのコードと解説を、Terraform初心者向けに提供しました。上記のコードと解説を参考に、Terraformを使ってECRを構築してみてください。
そして、まず動かすことができたら、少しずつ他のリソースのファイルも作成して、
terraformをどんどん使ってみるといいかなぁと思います。

では！