💡

TerraformでEC2を構築してみた

2023/02/26に公開

今回はTerraformを使用してEC2を構築してみます。Harshicorpの公式サイトに載っているチュートリアルを元にやってみます。AWSの無料利用枠範囲内で行いますが、利用料金が発生する場合がありますので、そこは自己責任でお願いします。

前提条件

  • Terraform CLI (1.2.0以上)がインストール済み。
  • AWS CLIインストール済み。
  • AWSアカウントとそれに紐づくIAMの認証も設定済み。

構成の記述

Terraformの構成は自分のディレクトリー内に記述する必要があるので、先ずはディレクトリーを作成します。自分の好きな所にディレクトリーを作成して下さい。

% mkdir learn-terraform-aws-instance
% cd learn-terraform-aws-instance

構成を記述するためのmain.tfファイルを作成します。

% touch main.tf
% ls
main.tf

tfファイルを開いて下記をコピーして追記し、保存します。

% vim main.tf 
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region  = "ap-northeast-1"
}

resource "aws_instance" "app_server" {
  ami           = "ami-830c94e3"
  instance_type = "t2.micro"

  tags = {
    Name = "ExampleAppServerInstance"
  }
}

これはEC2の設定をTerraform形式で記述したものです。これで実際にEC2をデプロイ出来ます。次のセクションから構成の内容をみていきます。

Terraformブロック

terraformブロック{}には各種設定が入ります。AWSやAzureのようなベンダー名やその設定値などです。今回はAWSがサービスプロバイダーなのでrequired_providersがAWSでsourceは"hashicorp/aws"となっています。これは"registry.terraform.io/hashicorp/aws"を省略した書き方ですが、terraformレジストリーにデフォルトで設定されているため、省略化しても大丈夫みたいです。

Providers

providerブロック{}には先ほど上記したようにawsが今回のケースでは入ります。他のベンダーを記述すればawsと一緒に使用する事も可能です。DataDogなどのベンダーにAWS EC2のIPアドレスを渡すことも出来ます。

Resources

resourceブロックにはコンポーネントを記述します。resourceブロック{}の前には2つの文字列を記載します。resource typeとresource nameです。今回はaws_instanceがresource typeでnameがapp_serverです。
また、ブロックにはリソースを定義するための引数も記述します。今回はEC2を構築するので、AMIのIDとインスタンスタイプを記載しています。

ディレクトリーの初期化

tfファイルなどの構成を作った時はディレクトリーの初期化をします。初期化はtfファイルの構成を読み込んで、プロバイダーをインストールします。今回はhashicorp/awsがインストールされました。

% terraform init

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 4.16"...
- Installing hashicorp/aws v4.56.0...
- Installed hashicorp/aws v4.56.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.

公式サイトによると初期化によって.terraformと.terraform.lock.hclができるみたいです。このファイルでプロバイダーのバージョン管理をするみたいです。

% ls -lha
drwxr-xr-x  3 atsushiambo  staff    96B Feb 26 17:58 .terraform
-rw-r--r--  1 atsushiambo  staff   1.4K Feb 26 17:58 .terraform.lock.hcl

Terraformファイルの検証

terraformではファイルが正しく記述されているか確認出来るコマンドがあります。下記のコマンドはファイルのフォーマットが正しいか確認します。修正したファイルがなければ何も表示しません。あれば、そのファル名が表示されます。

% terraform fmt
main.tf

チュートリアルでは表示されていないですが、私の場合はmain.tfファイルのフォーマットがおかしかったみたいなので、表示されました。再度実行すると何も表示されなかったです。
次のコマンドは構文が正しいか確認するためのコマンドです。

% terraform validate
Success! The configuration is valid.

今回は問題なかったようです。

EC2の構築

main.tfの構成を下記のコマンドで適用します。

% 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_instance.app_server will be created
  + resource "aws_instance" "app_server" {
      + ami                                  = "ami-830c94e3"
      + 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_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
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "ExampleAppServerInstance"
        }
      + tags_all                             = {
          + "Name" = "ExampleAppServerInstance"
        }
      + 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)
            }
        }

      + 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)
        }

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

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.app_server: Creating...
╷
│ Error: creating EC2 Instance: InvalidAMIID.NotFound: The image id '[ami-830c94e3]' does not exist
│       status code: 400, request id: 6fef4b34-2ce3-40e7-8391-22c5406b8afa
│ 
│   with aws_instance.app_server,
│   on main.tf line 16, in resource "aws_instance" "app_server":
│   16: resource "aws_instance" "app_server" {

エラーが出ました。AMI IDが正しくなかったみたいです。チュートリアルでは"us-west-2"だった所を東京リージョンに変更したため、AMI IDも変える必要がありました。UbuntuのIDを新たに探して、main.tfファイルに追記します。

% aws ec2 describe-images --owners 099720109477 \
      --filters "Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64*" \
      --region ap-northeast-1 \
      --query "reverse(sort_by(Images, &CreationDate))[0].[ImageId,CreationDate,Name]" \
      --output table
--------------------------------------------------------------------
|                          DescribeImages                          |
+------------------------------------------------------------------+
|  ami-08347baaec0755352                                           |
|  2023-02-13T23:08:42.000Z                                        |
|  ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20230213  |
+------------------------------------------------------------------+

このID ami-08347baaec0755352をmain.tfに追記して、再度applyします。

% 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_instance.app_server will be created
  + resource "aws_instance" "app_server" {
      + ami                                  = "ami-08347baaec0755352"
      + 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_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
      + subnet_id                            = (known after apply)
      + tags                                 = {
          + "Name" = "ExampleAppServerInstance"
        }
      + tags_all                             = {
          + "Name" = "ExampleAppServerInstance"
        }
      + 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)
            }
        }

      + 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)
        }

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

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

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

今度は上手く出来ました。
マネージメントコンソールで確認すると、先ほどのEC2が稼働しているのが確認出来ます。

リソース管理

terraformでは適用後にterraform.tfstateというファイルを作成します。このファイルにはIDやプロパティ情報が記載されているので、取り扱いには注意が必要との事です。Harshicorpではこのファイルはローカルではなくリモートで管理し、アクセス制限をつける事を推奨しています。
下記のコマンドで現在のリソース状況を確認出来ます。

% terraform show
# aws_instance.app_server:
resource "aws_instance" "app_server" {
    ami                                  = "ami-08347baaec0755352"
    arn                                  = "arn:aws:ec2:ap-northeast-1:640363432844:instance/i-03e832adb6b58e0c8"
    associate_public_ip_address          = true
    availability_zone                    = "ap-northeast-1c"
    cpu_core_count                       = 1
    cpu_threads_per_core                 = 1
    disable_api_stop                     = false
    disable_api_termination              = false
    ebs_optimized                        = false
    get_password_data                    = false
    hibernation                          = false
    id                                   = "i-03e832adb6b58e0c8"
    instance_initiated_shutdown_behavior = "stop"
    instance_state                       = "running"
    instance_type                        = "t2.micro"
    ipv6_address_count                   = 0
    ipv6_addresses                       = []
    monitoring                           = false
    placement_partition_number           = 0
    primary_network_interface_id         = "eni-0337e2ecd3f8be9e5"
    private_dns                          = "ip-172-31-13-81.ap-northeast-1.compute.internal"
    private_ip                           = "172.31.13.81"
    public_dns                           = "ec2-52-199-48-199.ap-northeast-1.compute.amazonaws.com"
    public_ip                            = "52.199.48.199"
    secondary_private_ips                = []
    security_groups                      = [
        "default",
    ]
    source_dest_check                    = true
    subnet_id                            = "subnet-0ba9fe5d56e18b0e4"
    tags                                 = {
        "Name" = "ExampleAppServerInstance"
    }
    tags_all                             = {
        "Name" = "ExampleAppServerInstance"
    }
    tenancy                              = "default"
    user_data_replace_on_change          = false
    vpc_security_group_ids               = [
        "sg-0036a3f30dae167a6",
    ]

    capacity_reservation_specification {
        capacity_reservation_preference = "open"
    }

    credit_specification {
        cpu_credits = "standard"
    }

    enclave_options {
        enabled = false
    }

    maintenance_options {
        auto_recovery = "default"
    }

    metadata_options {
        http_endpoint               = "enabled"
        http_put_response_hop_limit = 1
        http_tokens                 = "optional"
        instance_metadata_tags      = "disabled"
    }

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

    root_block_device {
        delete_on_termination = true
        device_name           = "/dev/sda1"
        encrypted             = false
        iops                  = 100
        tags                  = {}
        throughput            = 0
        volume_id             = "vol-0fc1a5de161b8c2c9"
        volume_size           = 8
        volume_type           = "gp2"
    }
}

下記のコマンドで現在のリソースのリストを表示させる事も出来ます。

% terraform state list
aws_instance.app_server

構成の変更

それではAMI IDを変更して、terraformがどのような動作をするかみてみます。
先ほどとは違うIDを入れてみます。

% vim main.tf 
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_instance" "app_server" {
  ami           = "ami-0822295a729d2a28e"
  instance_type = "t2.micro"

  tags = {
    Name = "ExampleAppServerInstance"
  }
}

Applyをした後の結果は省略しますが、AMI IDを途中で変更する事はできないので、terraformはまず先に既存のEC2を削除し、新しいIDでEC2を作成したみたいです。
terraform showで実際に作成されたEC2を見てみます。

% terraform show
# aws_instance.app_server:
resource "aws_instance" "app_server" {
    ami                                  = "ami-0822295a729d2a28e"
    arn                                  = "arn:aws:ec2:ap-northeast-1:640363432844:instance/i-06ac60d00835a6313"
    associate_public_ip_address          = true
    availability_zone                    = "ap-northeast-1c"
    cpu_core_count                       = 1
    cpu_threads_per_core                 = 1
    disable_api_stop                     = false
    disable_api_termination              = false
    ebs_optimized                        = false
    get_password_data                    = false
    hibernation                          = false
    id                                   = "i-06ac60d00835a6313"
    instance_initiated_shutdown_behavior = "stop"
    instance_state                       = "running"
    instance_type                        = "t2.micro"
    ipv6_address_count                   = 0
    ipv6_addresses                       = []
    monitoring                           = false
    placement_partition_number           = 0
    primary_network_interface_id         = "eni-012aab17071550f6a"
    private_dns                          = "ip-172-31-11-119.ap-northeast-1.compute.internal"
    private_ip                           = "172.31.11.119"
    public_dns                           = "ec2-13-114-245-6.ap-northeast-1.compute.amazonaws.com"
    public_ip                            = "13.114.245.6"
    secondary_private_ips                = []
    security_groups                      = [
        "default",
    ]
    source_dest_check                    = true
    subnet_id                            = "subnet-0ba9fe5d56e18b0e4"
    tags                                 = {
        "Name" = "ExampleAppServerInstance"
    }
    tags_all                             = {
        "Name" = "ExampleAppServerInstance"
    }
    tenancy                              = "default"
    user_data_replace_on_change          = false
    vpc_security_group_ids               = [
        "sg-0036a3f30dae167a6",
    ]

    capacity_reservation_specification {
        capacity_reservation_preference = "open"
    }

    credit_specification {
        cpu_credits = "standard"
    }

    enclave_options {
        enabled = false
    }

    maintenance_options {
        auto_recovery = "default"
    }

    metadata_options {
        http_endpoint               = "enabled"
        http_put_response_hop_limit = 1
        http_tokens                 = "optional"
        instance_metadata_tags      = "disabled"
    }

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

    root_block_device {
        delete_on_termination = true
        device_name           = "/dev/sda1"
        encrypted             = false
        iops                  = 100
        tags                  = {}
        throughput            = 0
        volume_id             = "vol-09e1092be28602ba4"
        volume_size           = 8
        volume_type           = "gp2"
    }
}

AMI IDがちゃんと変わっていましたね。
こんな感じでterraformで構成の変更が出来ます。
最後の今日作成したリソースを削除して終わります。

リソースの削除

下記のコマンドで削除できます。destroyコマンドはこのプロジェクト内のリソースの削除なので、他の所で作成したリソースは削除しません。

% terraform destroy
aws_instance.app_server: Refreshing state... [id=i-06ac60d00835a6313]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following
symbols:
  - destroy

Terraform will perform the following actions:

  # aws_instance.app_server will be destroyed
  - resource "aws_instance" "app_server" {
      - ami                                  = "ami-0822295a729d2a28e" -> null
      - arn                                  = "arn:aws:ec2:ap-northeast-1:640363432844:instance/i-06ac60d00835a6313" -> null
      - associate_public_ip_address          = true -> null
      - availability_zone                    = "ap-northeast-1c" -> 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-06ac60d00835a6313" -> 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-012aab17071550f6a" -> null
      - private_dns                          = "ip-172-31-11-119.ap-northeast-1.compute.internal" -> null
      - private_ip                           = "172.31.11.119" -> null
      - public_dns                           = "ec2-13-114-245-6.ap-northeast-1.compute.amazonaws.com" -> null
      - public_ip                            = "13.114.245.6" -> null
      - secondary_private_ips                = [] -> null
      - security_groups                      = [
          - "default",
        ] -> null
      - source_dest_check                    = true -> null
      - subnet_id                            = "subnet-0ba9fe5d56e18b0e4" -> null
      - tags                                 = {
          - "Name" = "ExampleAppServerInstance"
        } -> null
      - tags_all                             = {
          - "Name" = "ExampleAppServerInstance"
        } -> null
      - tenancy                              = "default" -> null
      - user_data_replace_on_change          = false -> null
      - vpc_security_group_ids               = [
          - "sg-0036a3f30dae167a6",
        ] -> null

      - capacity_reservation_specification {
          - capacity_reservation_preference = "open" -> 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 = 1 -> null
          - http_tokens                 = "optional" -> 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/sda1" -> null
          - encrypted             = false -> null
          - iops                  = 100 -> null
          - tags                  = {} -> null
          - throughput            = 0 -> null
          - volume_id             = "vol-09e1092be28602ba4" -> null
          - volume_size           = 8 -> null
          - volume_type           = "gp2" -> 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.app_server: Destroying... [id=i-06ac60d00835a6313]
aws_instance.app_server: Still destroying... [id=i-06ac60d00835a6313, 10s elapsed]
aws_instance.app_server: Still destroying... [id=i-06ac60d00835a6313, 20s elapsed]
aws_instance.app_server: Still destroying... [id=i-06ac60d00835a6313, 30s elapsed]
aws_instance.app_server: Destruction complete after 31s

Destroy complete! Resources: 1 destroyed.

無事に削除されました。コンソールからも削除されているのが確認出来ました。

今回EC2シングルインスタンスのみでしたので普通に削除されましたが、複雑な構成だった場合も、順番にterraformは削除してくれるみたいです。以上で今回のTerraformでEC2を構築してみたは完了です。
ありがとうございました。

Discussion