【Terraform】AWS事始め

# 概要
TerraformでAWSリソースを扱い始めるためのチュートリアルのような内容を記載します。
ハンズオンライクに、terraformコマンドでEC2インスタンスを生成できることを本記事でのゴールとします。

GCPについては[こちら](https://qiita.com/mintak21/items/73ac36a17d22e881cbe0)を参照ください。

# 前提
- MacOSである
- Homebrewを導入している
- AWSアカウントを保持している

# 手順
## 1. セットアップ
### 1.1. AWS IAMユーザー払い出し
`terraform`コマンドで、AWSとのやりとりを行うためのユーザーを作成します。

※以下の画面キャプチャは執筆時点のものです。今後変更される可能性がある点について承知おきください。
AWSマネジメントコンソールにログインし、IAMへ移動->「ユーザーを追加」をクリックします。
<img width="557" alt="スクリーンショット 2020-06-21 0.45.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552343/4e19ba68-94d8-9e26-64cf-65114b39f9f9.png">

ユーザー名には任意の名称、アクセスの種類は「プログラムによるアクセス」にチェックを入れます。
<img width="975" alt="スクリーンショット 2020-06-21 1.22.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552343/85013297-9140-7c51-7316-d2988c10f480.png">


権限には`Administrator Access`を設定します。
※本来この権限を設定すべきではありません。しかし今回は検証用IAMユーザーであることと、適切な権限を割り振ることにコストを割く必要がないように最も強い権限を付与することとします。
<img width="976" alt="スクリーンショット 2020-06-21 1.23.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552343/711add91-0277-3bc8-d5e0-2f5e695d6469.png">

必要があれば次ページでタグを設定し、「ユーザーの作成」をクリックします。
作成後の以下の画面での「アクセスキーID」「シークレットアクセスキー」を控えます。（認証情報）
<img width="965" alt="スクリーンショット 2020-06-21 1.25.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552343/b4f61da6-62ac-9c88-5727-018e5dce7d32.png">


### 1.2. ローカル実行環境の設定
ローカルPCで`terraform`コマンドを実行できる環境のセットアップを行います。


### terraformのインストール
`terraform`のバージョンマネージャーである`tfenv`を用いることにします。
#### tfenv
homebrewでインストールを行います。

```bash
$ brew install tfenv
```

#### terraform
続いて、`terraform`をインストールします。おおまかには以下の手順となります。

1. `list-remote`コマンドでインストール可能なバージョンを取得
1. `install`コマンドで上記のうち、任意のバージョンを指定してインストール
1. `use`コマンドで使用バージョンを設定

下記に、本記事執筆時点での最新バージョン`0.12.26`を利用する例を示します。

```bash:Terminal
# インストール可能バージョンの取得
$ tfenv list-remote

1.1.2
1.1.1
1.1.0
1.1.0-rc1
# 以下略

# バージョンを指定してインストール実行
$ tfenv install 1.1.2

# 使用するバージョンを指定を明示
$ tfenv use 1.1.2

# terraformバージョン確認
$ terraform version
Terraform v1.1.2

# c.f. インストール済バージョンを確認
$ tfenv list

* 1.1.2 (set by /usr/local/Cellar/tfenv/2.0.0/version)
  0.12.26
```

これでインストールは完了ですが、コマンド入力コストを低減するために自動補完を有効にしておきましょう。
（実際には`.bashrc` `.zshrc`に`complete`コマンドが追記されます。）

```bash:Terminal
$ terraform -install-autocomplete
```

### aws認証情報設定
`terraform`でAWSへアクセスするための認証情報を設定します。
認証情報の設定方法はいくつかありますが、ここでは**名前付きプロファイル**にて設定を行うこととします。

#### aws-cliインストール
これがなくてもプロファイルは作成できるのですが、コンソールからAWSアクセスを行うこともあると思うので、このタイミングでインストールを実施しておくのがよいでしょう。

```bash:Terminal
$ brew install awscli
```

1.1 で作成したIAMユーザーの認証情報を名前付きプロファイルとして設定します。

```bash:Terminal
$ aws configure --profile YOUR_PROFILE_NAME
AWS Access Key ID[None]: 1.1のアクセスキーID
AWS Secret Access Key[None]: 1.1のシークレットアクセスキー
Default region name[None]: ap-northeast-1
Default output format[None]: json

# アクセス確認
$ aws sts get-caller-identity --profile YOUR_PROFILE_NAME
# 結果が返ってくればOK
```

コマンドの都度`--profile YOUR_PROFILE_NAME`を打つのは面倒なので、今回作成したプロファイルを自動的に使用するように環境変数`AWS_PROFILE`を設定しておくと良いでしょう。

```bash:.bashrc
export AWS_PROFILE=YOUR_PROFILE_NAME
```

### git-secrets
認証情報がGitコミット時に不用意に公開されないようにするため、念の為いれておくとカタイです。
キーやパスワードといったものをGitコミットしようとしたときに警告を発してくれます。

```bash:Terminal
$ brew install git-secrets
$ git secrets --register-aws --global
$ git secrets --install ~/.git-templates/git-secrets
$ git config --global init.templatedir '~/.git-templates/git-secrets'
```

## 2. 実行ファイルの作成
AWS上にEC2インスタンス（`t2.micro`）を1つ作成するためのコードを記述していきます。

- フォルダ構成

```text
directory
|- main.tf       実行対象
|- providers.tf  プロバイダ設定
|- variables.tf  変数設定
```

- 各ファイル

```terraform:providers.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
  required_version = ">=0.13"
}


provider "aws" {
  region = "ap-northeast-1" # Your region
  profile = "YOUR_PROFILE_NAME" # 1.2で作成したプロファイルの名称を設定、名前付きプロファイルから認証情報を読み込む
}
```

```terraform:main.tf
resource "aws_instance" "tutorial" {
  ami           = "ami-063f4c001c8a7c154" # 直接指定しているがもっといい設定方法はある
  instance_type = var.aws_instance_type   # tfvarsで指定した値 or variables.tfで設定したdefaultが設定される
  tags = {
    Name = var.aws_instance_tag_name
  }
}
```

```terraform:variables.tf
variable "aws_instance_type" {
  type        = string
  description = "AWSインスタンス種別"
  default     = "t2.micro"
}

variable "aws_instance_tag_name" {
  type        = string
  description = "AWSインスタンスタグ：Name"
  default     = "terraform-tutorial"
}
```

## 3. リソース作成 / 削除
### 3.1. init
BackendとプロバイダのInitializeを行います。

```bash:Terminal
$ terraform init
```

### 3.2. plan
いきなり作成コマンドを実行するのはやはり気が引けるので、実行したときの結果のだいたいの予測ができるコマンドがあります。それが`plan`コマンドです。まずはこれで変更内容を把握しましょう。
エラーとなる場合は、エラー内容が表示されます。
下記の例のように、「applyして、どうぞ」となっていれば実行できる状態です。
※ただし、`plan`が成功したといって`apply`が成功するとは限りません。

```bash:Terminal
$ terraform plan
------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.tutorial will be created
  + resource "aws_instance" "tutorial" {
      + ami                          = "ami-0a1c2ec61571737db"
      + arn                          = (known after apply)
      + associate_public_ip_address  = (known after apply)
      + availability_zone            = (known after apply)
      + cpu_core_count               = (known after apply)
      + cpu_threads_per_core         = (known after apply)
      + get_password_data            = false
      + host_id                      = (known after apply)
      + id                           = (known after apply)
      + instance_state               = (known after apply)
      + instance_type                = "t2.micro"
      + ipv6_address_count           = (known after apply)
      + ipv6_addresses               = (known after apply)
      + key_name                     = (known after apply)
      + network_interface_id         = (known after apply)
      + outpost_arn                  = (known after apply)
      + password_data                = (known after apply)
      + placement_group              = (known after apply)
      + primary_network_interface_id = (known after apply)
      + private_dns                  = (known after apply)
      + private_ip                   = (known after apply)
      + public_dns                   = (known after apply)
      + public_ip                    = (known after apply)
      + security_groups              = (known after apply)
      + source_dest_check            = true
      + subnet_id                    = (known after apply)
      + tags                         = {
          + "Name" = "terraform-tutorial"
        }
      + tenancy                      = (known after apply)
      + volume_tags                  = (known after apply)
      + vpc_security_group_ids       = (known after apply)
# 中略
    }

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

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
```

### 3.3. apply
3.2. planが成功したら、いよいよ`apply`コマンドでリソースを作成してみましょう。
`plan`と同様の変更内容がコンソールに表示された後、`Do you want to perform these actions?`と尋ねられるため、問題なければ「yes」と入力することでリソース作成が開始されます。

```bash:Terminal
$ terraform apply

# 中略

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_instance.tutorial: Creating...
aws_instance.tutorial: Still creating...[10s elapsed]
aws_instance.tutorial: Still creating...[20s elapsed]
aws_instance.tutorial: Still creating...[30s elapsed]
aws_instance.tutorial: Creation complete after 34s[id=i-0f6cd3a49eb01d903]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
```

実際にマネジメントコンソールを見てみると、新しくインスタンスが生成されていることがわかります。
<img width="1226" alt="スクリーンショット 2020-06-21 2.07.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552343/16223f35-5191-a3ef-d52c-bd7cf74d7068.png">


### 3.4. destroy
本来はこのままでよいのですが、個人アカウントでクラウドリソースを作ったままにしておくと、知らないうちに課金が発生してしまうため、実際の作成が確認できたらリソース削除を行いましょう。`destroy`コマンドを使用します。
※今回使用した`t2.micro`はアカウント作成から1年間無料枠の対象なので、この対象となっている方はそこまで目くじら立てる必要はないかもしれません。

```bash:Terminal
$ terraform destroy

# 中略
Plan: 0 to add, 0 to change, 1 to destroy.

aws_instance.tutorial: Destroying... [id=i-0f6cd3a49eb01d903]
aws_instance.tutorial: Still destroying... [id=i-0f6cd3a49eb01d903, 10s elapsed]
aws_instance.tutorial: Still destroying... [id=i-0f6cd3a49eb01d903, 20s elapsed]
aws_instance.tutorial: Still destroying... [id=i-0f6cd3a49eb01d903, 30s elapsed]
aws_instance.tutorial: Destruction complete after 30s

Destroy complete! Resources: 1 destroyed.
```

EC2では`terminated`ステータスになったのち、一定時間たつとコンソールからも見えない状態となります。
<img width="1228" alt="スクリーンショット 2020-06-21 2.11.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552343/04e9c5b3-9fb4-8c04-16af-91e10c701a30.png">


これでひとまず、EC2インスタンスの作成および削除を行うことができました。
その他のリソースを作成するには2の実行ファイルの内容を都度変更していく必要がありますが、3の実行に関しては流れは同じです。



# References
- [Terraform provider:AWS](https://www.terraform.io/docs/providers/aws/index.html)
- [AWS名前付きプロファイル](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-profiles.html)