Tarraformを使ってAWSにWebサーバを構築 #3 ~TerraformでEC2サーバを立ち上げてみる~

## 目的
EC2にNginxがインストールされた状態を作り出し、ブラウザからデフォルトページが確認できることをゴールとする。
インフラ構築はTerraformでコード化することで再現性、再利用性、速度などが手作業に比べると高い。
[GitHubリンク](https://github.com/keitasato/terraform-nginx)

### 手順
1. [TerraformからAWSリソースを操作できるように設定する](https://qiita.com/kekkepy/items/4185a621e5d3cc75016b)
1. [Terraformをインストールする](https://qiita.com/kekkepy/items/1b3f4f14bbc2d2dc2c9b)
1. [TerraformでEC2サーバを立ち上げてみる](https://qiita.com/kekkepy/items/8b84fc0c39313267a078)
1. [ネットワークを整える(VPC, サブネット, ルーティングテーブル,インターネットゲートウェイ)](https://qiita.com/kekkepy/items/c941c00536af57bae163)
1. [セキュリティグループ(ファイアウォール)を設定する](https://qiita.com/kekkepy/items/47dcda4d9a7a2064382f)
1. [Webサーバ用EC2を立ち上げる](https://qiita.com/kekkepy/items/81bfa5d542c9160d430b)
1. [Webサーバが立ち上がる際にWebサーバソフトをインストールするように設定する](https://qiita.com/kekkepy/items/209f7ddb29fb5af65a6e)

#### 今回の到達点
TerraformでEC2サーバを立ち上げてみる

##### Step0. 作業ディレクトリの作成
ユーザディレクトリ配下の任意の場所にterraformディレクトリを作成する。
(ユーザディレクトリ配下でないと権限問題が発生するため)
C:\Users\[ユーザ名]\Documents\MyProject\terraform

##### Step1. tfファイルの作成
ファイル名 : main.tf(ファイル名は任意なので他の名前でも問題ない)
以下のようにファイルを作成
```terraform:main.tf
provider "aws" {
  profile = "terraform"
  region  = "ap-northeast-1"
}

resource "aws_instance" "web_server" {
  ami                         = "ami-0cfc97bf81f2eadc4"
  instance_type               = "t2.micro"

  tags = {
    Name    = "terraform-web-server"
  }
```

##### Step2. Terraformの初期化
コマンドを実行すれば諸々の設定ファイルなどを作成してくれる。
途中「yes」と入力する必要がある。
```
$ terraform init
Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v5.5.0...
- Installed hashicorp/aws v5.5.0 (self-signed, key ID 34365D9472D7468F)       

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

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.
```

##### Step3. tfファイルのフォーマット
インデントとかを一発で揃えてくれる便利コマンドがあるので、ファイルを編集して切りがいいタイミングで都度フォーマットを行うことをオススメ。
```
$ terraform fmt
main.tf
```
↑main.tfのファイルをフォーマットしてくれたことがわかる。

##### Step4. tfファイルを実行した場合の変更内容を確認
Terraformを実行するとAWSリソースに変更がかかるが、その変更内容だけを確認し変更自体は適用しないコマンドがある。
AWSはお金もかかるし大切な資産もあるので、まずはTerraformの内容を実際に適用して問題無いかを実行前に確認する癖をつける。
```
$ 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.web_server will be created
  + resource "aws_instance" "web_server" {
      + ami                                  = "ami-0cfc97bf81f2eadc4"
      + 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)
      + disable_api_stop                     = (known after apply)
      + disable_api_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      + id                                   = (known after apply)
      + instance_initiated_shutdown_behavior = (known after apply)
      + instance_lifecycle                   = (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)
      + monitoring                           = (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      + placement_partition_number           = (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)
      + secondary_private_ips                = (known after apply)
      + security_groups                      = (known after apply)
      + source_dest_check                    = true
      + spot_instance_request_id             = (known after apply)
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "terraform-web-server"
        }
      + tags_all                             = {
          + "Name" = "terraform-web-server"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id                 = (known after apply)
              + capacity_reservation_resource_group_arn = (known after apply)
            }
        }

      + cpu_options {
          + amd_sev_snp      = (known after apply)
          + core_count       = (known after apply)
          + threads_per_core = (known after apply)
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + instance_market_options {
          + market_type = (known after apply)

          + spot_options {
              + instance_interruption_behavior = (known after apply)
              + max_price                      = (known after apply)
              + spot_instance_type             = (known after apply)
              + valid_until                    = (known after apply)
            }
        }

      + maintenance_options {
          + auto_recovery = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
          + instance_metadata_tags      = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_card_index    = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + private_dns_name_options {
          + enable_resource_name_dns_a_record    = (known after apply)
          + enable_resource_name_dns_aaaa_record = (known after apply)
          + hostname_type                        = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (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.
```
terraform-web-serverという名前でEC2サーバを作成するよ！
ということが詳細情報と共に書いてあります。

##### Step5. tfファイルを実行してみる(create編)
いよいよTerraformからEC2サーバを立ててみます。
マネジメントコンソール上で現在はEC2サーバは存在しないことを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1221536/387511f0-dbc9-f25f-03a8-7aca0796df78.png)


terraform applyコマンドに-auto-approve オプションを付与することで、yesを入力する必要がなくなる。
(心配な場合は-auto-approve オプションは付与しない)
```
$ terraform apply -auto-approve

aws_instance.web_server: Creating...
aws_instance.web_server: Still creating... [10s elapsed]
aws_instance.web_server: Still creating... [20s elapsed]
aws_instance.web_server: Still creating... [30s elapsed]
aws_instance.web_server: Creation complete after 32s [id=i-032d287a9619a06fe]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
```
しばらく待つと1つのリソース(今回はEC2インスタンス)が追加されたよ！というメッセージが表示される。

マネジメントコンソール上でterraform-web-serverという名前でEC2サーバが作成されたことがわかる。
コマンド一発でクラウド環境が構築できるのは気持ちいい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1221536/5d1d7f2e-961e-df58-16f9-1e3fbf50a860.png)

##### Step6. tfファイルを実行してみる(destroy編)
EC2サーバは立ち上げているとお金がかかるので、削除しておく。
削除もコマンド１つで簡単に可能。
途中「yes」と入力する必要があるが、-auto-approve オプションを付与することで、yesを入力する必要がなくなる。
```
$ terraform destroy

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

Terraform will perform the following actions:

  # aws_instance.web_server will be destroyed
  - resource "aws_instance" "web_server" {
      - ami                                  = "ami-0cfc97bf81f2eadc4" -> null
      - arn                                  = "arn:aws:ec2:ap-northeast-1:146193870787:instance/i-032d287a9619a06fe" -> null
      - associate_public_ip_address          = true -> null
      - availability_zone                    = "ap-northeast-1a" -> null
      - cpu_core_count                       = 1 -> null
      - cpu_threads_per_core                 = 1 -> null
      - disable_api_stop                     = false -> null
      - disable_api_termination              = false -> null
      - ebs_optimized                        = false -> null
      - get_password_data                    = false -> null
      - hibernation                          = false -> null
      - id                                   = "i-032d287a9619a06fe" -> null
      - instance_initiated_shutdown_behavior = "stop" -> null
      - instance_state                       = "running" -> null
      - instance_type                        = "t2.micro" -> null
      - ipv6_address_count                   = 0 -> null
      - ipv6_addresses                       = [] -> null
      - monitoring                           = false -> null
      - placement_partition_number           = 0 -> null
      - primary_network_interface_id         = "eni-09c10b073115e15d8" -> null
      - private_dns                          = "ip-172-31-46-191.ap-northeast-1.compute.internal" -> null
      - private_ip                           = "172.31.46.191" -> null
      - public_dns                           = "ec2-13-113-106-156.ap-northeast-1.compute.amazonaws.com" -> null
      - public_ip                            = "13.113.106.156" -> null
      - secondary_private_ips                = [] -> null
      - security_groups                      = [
          - "default",
        ] -> null
      - source_dest_check                    = true -> null
      - subnet_id                            = "subnet-0bf5fa8ca16b2b02e" -> null
      - tags                                 = {
          - "Name" = "terraform-web-server"
        } -> null
      - tags_all                             = {
          - "Name" = "terraform-web-server"
        } -> null
      - tenancy                              = "default" -> null
      - user_data_replace_on_change          = false -> null
      - vpc_security_group_ids               = [
          - "sg-01a0b7a001e3c013e",
        ] -> null

      - capacity_reservation_specification {
          - capacity_reservation_preference = "open" -> null
        }

      - cpu_options {
          - core_count       = 1 -> null
          - threads_per_core = 1 -> null
        }

      - credit_specification {
          - cpu_credits = "standard" -> null
        }

      - enclave_options {
          - enabled = false -> null
        }

      - maintenance_options {
          - auto_recovery = "default" -> null
        }

      - metadata_options {
          - http_endpoint               = "enabled" -> null
          - http_put_response_hop_limit = 2 -> null
          - http_tokens                 = "required" -> null
          - instance_metadata_tags      = "disabled" -> null
        }

      - private_dns_name_options {
          - enable_resource_name_dns_a_record    = false -> null
          - enable_resource_name_dns_aaaa_record = false -> null
          - hostname_type                        = "ip-name" -> null
        }

      - root_block_device {
          - delete_on_termination = true -> null
          - device_name           = "/dev/xvda" -> null
          - encrypted             = false -> null
          - iops                  = 3000 -> null
          - tags                  = {} -> null
          - throughput            = 125 -> null
          - volume_id             = "vol-07d3c71387a48c176" -> null
          - volume_size           = 8 -> null
          - volume_type           = "gp3" -> null
        }
    }

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

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

aws_instance.web_server: Destroying... [id=i-032d287a9619a06fe]
aws_instance.web_server: Still destroying... [id=i-032d287a9619a06fe, 10s elapsed]
aws_instance.web_server: Still destroying... [id=i-032d287a9619a06fe, 20s elapsed]
aws_instance.web_server: Destruction complete after 30s

Destroy complete! Resources: 1 destroyed.
```
terraform-web-serverという名前のEC2サーバを削除したよ！
ということが詳細情報と共に書いてあります。

マネジメントコンソール上でterraform-web-serverという名前のEC2サーバが削除されたことがわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1221536/c2817683-26fc-6374-aaa1-0e8f4defc381.png)