👁

TerraformでシンプルなAWS構成を作ろう

この章では、Terraformを使ったシンプルなAWSインフラの構築をハンズオン形式で学習します。これにより、VPC・サブネット・セキュリティグループ・EC2をコードで構築できるようになります。

1. 本章の概要

1.1 本章の目的

これまで学んだTerraformの基本を1つのシステム構成として組み立ててみる集大成のハンズオンです。VPC・サブネット・EC2など複数リソースを組み合わせて、AWS講座で手動で作成したものと同様の構成をコードで再現します。

1.2 ハンズオンの流れ

VPC・サブネット・インターネットゲートウェイ・ルートテーブル・セキュリティグループ・EC2インスタンスをTerraformで定義し、terraform applyで一括構築します。

1.3 事前準備

必要なツール

この章では、以下のツールを使用します。まだインストールしていない場合は、リンク先の手順に沿って準備をお願いします。

ツール名 関連箇所 理由
Visual Studio Code Visual Studio Codeのインストール Terraformコードを記述するエディタとして使用する
AWS CLI AWS CLIのインストール TerraformがAWSに接続する際の認証情報を設定するために使用する
Terraform Terraformのインストール 本章で扱うIaCツール本体

必要なアカウント

この章では、以下のアカウントを使用します。まだ用意していない場合は、リンク先の手順に沿って準備をお願いします。

アカウント名 関連箇所 理由
AWSアカウント AWSアカウントの作成 Terraformでリソースを構築するAWS環境として使用する

2. プロジェクトの準備

2.1 作業フォルダの作成

任意の場所にterraform-aws-basicフォルダを作成し、Visual Studio Codeの「ファイル」→「フォルダーを開く」から、作成したterraform-aws-basicフォルダを開きます。

terraform-aws-basic  ← このフォルダを作成

3. プロバイダーの設定

最初に、AWSプロバイダーを設定するmain.tfファイルを作成します。Visual Studio Codeのエクスプローラーでterraform-aws-basicフォルダを右クリックし、「新しいファイル」を選択してmain.tfという名前で作成してください。

terraform-aws-basic
└── main.tf  ← このファイルを作成

作成したファイルに以下の内容を記述して保存します。

# AWSプロバイダーの設定
provider "aws" {
  region = "ap-northeast-1"
}

4. Terraformの初期化

プロバイダーの設定が完了したら、Terraformを初期化します。ターミナルでterraform-aws-basicフォルダに移動し、以下のコマンドを実行してください。

terraform init

以下のような出力が表示されれば成功です。

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v5.x.x...
- Installed hashicorp/aws v5.x.x (signed by HashiCorp)

Terraform has been successfully initialized!
⚠️ 「error configuring Terraform AWS Provider」エラーが出る場合
AWS CLIの認証情報が正しく設定されているか確認してください。aws configureコマンドで設定を確認・更新できます。

これで、コードを追加するたびにterraform planで差分を確認し、terraform applyで反映できる状態になりました。

5. VPCの作成

5.1 コードの記載

ここでは、AWSのネットワークの土台となるVPC(Virtual Private Cloud)を作成します。Terraformでは、resource "aws_vpc"を使ってVPCを定義します。以下の内容をmain.tfに追記してください。

# ====================
# VPC
# ====================
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "terraform-vpc"
  }
}

今回設定した内容について解説します。

設定項目 設定の基準
cidr_block(VPCのIPv4 CIDRブロック) 10.0.0.0/16 約65,000個のIPアドレスを確保できる範囲のため
enable_dns_hostnames(DNSホスト名の有効化) true EC2インスタンスにDNSホスト名を付与するため
enable_dns_support(DNS解決の有効化) true VPC内でDNS解決を有効にするため
tags.Name(AWSコンソールに表示される名前タグ) terraform-vpc リソースを識別するため

5.2 差分の確認

terraform planで作成されるリソースを確認します。

terraform plan

以下のような実行結果が表示されます。

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_vpc.main will be created
  + resource "aws_vpc" "main" {
      + arn                                  = (known after apply)
      + cidr_block                           = "10.0.0.0/16"
      + default_network_acl_id               = (known after apply)
      + default_route_table_id               = (known after apply)
      + default_security_group_id            = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_dns_hostnames                 = true
      + enable_dns_support                   = true
      + enable_network_address_usage_metrics = (known after apply)
      + id                                   = (known after apply)
      + instance_tenancy                     = "default"
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + ipv6_cidr_block_network_border_group = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + tags                                 = {
          + "Name" = "terraform-vpc"
        }
      + tags_all                             = {
          + "Name" = "terraform-vpc"
        }
    }

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

+ createの記号が示すとおり、VPCが1つ新規作成されることがわかります。cidr_blockenable_dns_hostnamesなど、コードで指定した値が反映されていることを確認してください。(known after apply)と表示されている項目は、実際にリソースが作成された後にAWSから割り当てられる値です。

5.3 AWSへの反映

問題なければterraform applyで反映します。

terraform apply

確認プロンプトが表示されたら、yesと入力して実行します。以下のように、VPCが1件作成されたことを確認します。

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

5.4 AWSコンソールでの確認

AWSマネジメントコンソールで VPC のダッシュボードを開き、「terraform-vpc」という名前のVPCが作成されていることを確認してください。VPCを選択し、以下の項目がコードで設定した内容と一致していることも確認しましょう。

  • IPv4 CIDR が「10.0.0.0/16」であること
  • DNSホスト名 が「有効」であること
  • DNS解決 が「有効」であること

6. サブネットの作成

6.1 コードの記載

ここでは、VPC内にEC2インスタンスを配置するためのパブリックサブネットを作成します。Terraformでは、resource "aws_subnet"を使ってサブネットを定義します。以下の内容をmain.tfに追記してください。

# ====================
# サブネット
# ====================
# パブリックサブネット
resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.main.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "ap-northeast-1a"
  map_public_ip_on_launch = true

  tags = {
    Name = "terraform-public-subnet"
  }
}

今回設定した内容について解説します。

設定項目 設定の基準
vpc_id(サブネットを作成するVPC) aws_vpc.main.id 作成したVPCに所属させるため(リソース参照)
cidr_block(サブネットのIPv4 CIDRブロック) 10.0.1.0/24 約250個のIPアドレスを確保できる範囲のため
availability_zone(サブネットを配置するアベイラビリティゾーン) ap-northeast-1a 東京リージョンのAZを指定するため
map_public_ip_on_launch(パブリックIP自動割り当て) true EC2起動時に自動でパブリックIPを付与するため
tags.Name(AWSコンソールに表示される名前タグ) terraform-public-subnet リソースを識別するため
💡 ポイント
vpc_id = aws_vpc.main.idの部分で、先ほど定義したVPCのIDを参照しています。前の章 リソース間の参照 で学んだ考え方を活用しています。Terraformはこの参照を解析し、VPCが作成されてからサブネットを作成します。

6.2 差分の確認

terraform planで差分を確認します。

terraform plan

以下のような実行結果が表示されます。

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_subnet.public will be created
  + resource "aws_subnet" "public" {
      + arn                                            = (known after apply)
      + assign_ipv6_address_on_creation                = false
      + availability_zone                              = "ap-northeast-1a"
      + availability_zone_id                           = (known after apply)
      + cidr_block                                     = "10.0.1.0/24"
      + enable_dns64                                   = false
      + enable_resource_name_dns_a_record_on_launch    = false
      + enable_resource_name_dns_aaaa_record_on_launch = false
      + id                                             = (known after apply)
      + ipv6_cidr_block_association_id                 = (known after apply)
      + ipv6_native                                    = false
      + map_public_ip_on_launch                        = true
      + owner_id                                       = (known after apply)
      + private_dns_hostname_type_on_launch            = (known after apply)
      + tags                                           = {
          + "Name" = "terraform-public-subnet"
        }
      + tags_all                                       = {
          + "Name" = "terraform-public-subnet"
        }
      + vpc_id                                         = "vpc-xxxxxxxxxxxxxxxxx"
    }

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

パブリックサブネットが1つ作成されることがわかります。map_public_ip_on_launch = trueが設定されていることを確認してください。また、vpc_idには先ほど作成したVPCのIDが自動的に設定されています。

6.3 AWSへの反映

問題なければterraform applyで反映します。

terraform apply

確認プロンプトが表示されたら、yesと入力して実行します。以下のように、サブネットが1件作成されたことを確認します。

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

6.4 AWSコンソールでの確認

AWSマネジメントコンソールで VPC > サブネット を開き、「terraform-public-subnet」が作成されていることを確認してください。サブネットを選択し、以下の項目がコードで設定した内容と一致していることも確認しましょう。

  • VPC が「terraform-vpc」であること
  • IPv4 CIDR が「10.0.1.0/24」であること
  • アベイラビリティゾーン が「ap-northeast-1a」であること
  • パブリックIPv4アドレスを自動割り当て が「はい」であること

7. インターネットゲートウェイの作成

7.1 コードの記載

ここでは、VPCからインターネットへ接続するためのインターネットゲートウェイを作成します。Terraformでは、resource "aws_internet_gateway"を使ってインターネットゲートウェイを定義します。以下の内容をmain.tfに追記してください。

# ====================
# インターネットゲートウェイ
# ====================
resource "aws_internet_gateway" "main" {
  vpc_id = aws_vpc.main.id

  tags = {
    Name = "terraform-igw"
  }
}

今回設定した内容について解説します。

設定項目 設定の基準
vpc_id(アタッチするVPC) aws_vpc.main.id 作成したVPCにインターネットゲートウェイをアタッチするため
tags.Name(AWSコンソールに表示される名前タグ) terraform-igw リソースを識別するため

7.2 差分の確認

terraform planで差分を確認します。

terraform plan

以下のような実行結果が表示されます。

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_internet_gateway.main will be created
  + resource "aws_internet_gateway" "main" {
      + arn      = (known after apply)
      + id       = (known after apply)
      + owner_id = (known after apply)
      + tags     = {
          + "Name" = "terraform-igw"
        }
      + tags_all = {
          + "Name" = "terraform-igw"
        }
      + vpc_id   = "vpc-xxxxxxxxxxxxxxxxx"
    }

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

インターネットゲートウェイが1つ作成されることがわかります。vpc_idに先ほど作成したVPCのIDが設定されていることを確認してください。

7.3 AWSへの反映

問題なければterraform applyで反映します。

terraform apply

確認プロンプトが表示されたら、yesと入力して実行します。以下のように、インターネットゲートウェイが1件作成されたことを確認します。

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

7.4 AWSコンソールでの確認

AWSマネジメントコンソールで VPC > インターネットゲートウェイ を開き、「terraform-igw」が作成されていることを確認してください。以下の項目がコードで設定した内容と一致していることも確認しましょう。

  • 状態 が「Attached」であること
  • VPC ID が「terraform-vpc」のVPCであること

8. ルートテーブルの作成

8.1 コードの記載

ここでは、パブリックサブネットからインターネットへの通信経路を定義するルートテーブルを作成し、サブネットに関連付けます。Terraformでは、resource "aws_route_table"でルートテーブルを定義し、resource "aws_route_table_association"でサブネットとの関連付けを行います。以下の内容をmain.tfに追記してください。

# ====================
# ルートテーブル
# ====================
# パブリックサブネット用ルートテーブル
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.main.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.main.id
  }

  tags = {
    Name = "terraform-public-rt"
  }
}

# ルートテーブルとサブネットの関連付け
resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}

今回設定した内容について解説します。

設定項目 設定の基準
vpc_id(ルートテーブルを作成するVPC) aws_vpc.main.id 作成したVPCに所属させるため
route.cidr_block(ルートの送信先) 0.0.0.0/0 すべてのトラフィックを対象にするため
route.gateway_id(ルートのターゲット) aws_internet_gateway.main.id インターネットゲートウェイに転送するため
tags.Name(AWSコンソールに表示される名前タグ) terraform-public-rt リソースを識別するため
subnet_id(関連付けるサブネット) aws_subnet.public.id パブリックサブネットにルートテーブルを適用するため
route_table_id(関連付けるルートテーブル) aws_route_table.public.id 作成したルートテーブルを使用するため
📝 ルートテーブルとは
ルートテーブルは、サブネット内のトラフィックの送信先を決定します。0.0.0.0/0(すべての宛先)をインターネットゲートウェイに向けることで、パブリックサブネットからインターネットへのアクセスが可能になります。

8.2 差分の確認

terraform planで差分を確認します。

terraform plan

以下のような実行結果が表示されます。

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_route_table.public will be created
  + resource "aws_route_table" "public" {
      + arn              = (known after apply)
      + id               = (known after apply)
      + owner_id         = (known after apply)
      + propagating_vgws = (known after apply)
      + route            = [
          + {
              + cidr_block                 = "0.0.0.0/0"
              + gateway_id                 = (known after apply)
              + carrier_gateway_id         = ""
              + core_network_arn           = ""
              + destination_prefix_list_id = ""
              + egress_only_gateway_id     = ""
              + ipv6_cidr_block            = ""
              + local_gateway_id           = ""
              + nat_gateway_id             = ""
              + network_interface_id       = ""
              + transit_gateway_id         = ""
              + vpc_endpoint_id            = ""
              + vpc_peering_connection_id  = ""
            },
        ]
      + tags             = {
          + "Name" = "terraform-public-rt"
        }
      + tags_all         = {
          + "Name" = "terraform-public-rt"
        }
      + vpc_id           = "vpc-xxxxxxxxxxxxxxxxx"
    }

  # aws_route_table_association.public will be created
  + resource "aws_route_table_association" "public" {
      + id             = (known after apply)
      + route_table_id = (known after apply)
      + subnet_id      = "subnet-xxxxxxxxxxxxxxxxx"
    }

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

ルートテーブルとサブネットの関連付けの2つが作成されることがわかります。ルートテーブルのroutecidr_block = "0.0.0.0/0"が設定されており、すべてのトラフィックがインターネットゲートウェイに向けられることを確認してください。

8.3 AWSへの反映

問題なければterraform applyで反映します。

terraform apply

確認プロンプトが表示されたら、yesと入力して実行します。以下のように、ルートテーブルとサブネットの関連付けの2件が作成されたことを確認します。

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

8.4 AWSコンソールでの確認

AWSマネジメントコンソールで VPC > ルートテーブル を開き、「terraform-public-rt」が作成されていることを確認してください。ルートテーブルを選択し、以下の項目がコードで設定した内容と一致していることも確認しましょう。

  • VPC が「terraform-vpc」であること
  • 「ルート」タブで、送信先0.0.0.0/0のターゲットが「terraform-igw」(インターネットゲートウェイ)になっていること
  • 「サブネットの関連付け」タブで、「terraform-public-subnet」が関連付けられていること

9. セキュリティグループの作成

9.1 コードの記載

ここでは、EC2インスタンスへの通信を制御するセキュリティグループを作成します。Terraformでは、resource "aws_security_group"を使ってセキュリティグループを定義し、ingressブロックで受信ルール、egressブロックで送信ルールを設定します。以下の内容をmain.tfに追記してください。

# ====================
# セキュリティグループ
# ====================
resource "aws_security_group" "ec2" {
  name        = "terraform-ec2-sg"
  description = "Security group for EC2 instance"
  vpc_id      = aws_vpc.main.id

  # SSH接続を許可
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    description = "Allow SSH"
  }

  # HTTP接続を許可
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
    description = "Allow HTTP"
  }

  # アウトバウンド通信を全て許可
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    description = "Allow all outbound traffic"
  }

  tags = {
    Name = "terraform-ec2-sg"
  }
}

今回設定した内容について解説します。

設定項目 設定の基準
name(セキュリティグループ名) terraform-ec2-sg リソースを識別するため
description(セキュリティグループの説明) Security group for EC2 instance セキュリティグループの用途を明示するため
vpc_id(セキュリティグループを作成するVPC) aws_vpc.main.id 作成したVPCに所属させるため
ingress(SSH用インバウンドルール) ポート22, TCP, 0.0.0.0/0 SSH接続を許可するため
ingress(HTTP用インバウンドルール) ポート80, TCP, 0.0.0.0/0 HTTP接続を許可するため
egress(アウトバウンドルール) 全ポート, 全プロトコル, 0.0.0.0/0 すべてのアウトバウンド通信を許可するため
tags.Name(AWSコンソールに表示される名前タグ) terraform-ec2-sg リソースを識別するため
💡 ポイント
このセクションでは簡略化のため、SSH接続を0.0.0.0/0(全世界)から許可しています。本番環境では、自分のIPアドレスのみを許可するなど、適切なセキュリティ設定を行ってください。

9.2 差分の確認

terraform planで差分を確認します。

terraform plan

以下のような実行結果が表示されます。

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_security_group.ec2 will be created
  + resource "aws_security_group" "ec2" {
      + arn                    = (known after apply)
      + description            = "Security group for EC2 instance"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = "Allow all outbound traffic"
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = "Allow HTTP"
              + from_port        = 80
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 80
            },
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = "Allow SSH"
              + from_port        = 22
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 22
            },
        ]
      + name                   = "terraform-ec2-sg"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags                   = {
          + "Name" = "terraform-ec2-sg"
        }
      + tags_all               = {
          + "Name" = "terraform-ec2-sg"
        }
      + vpc_id                 = "vpc-xxxxxxxxxxxxxxxxx"
    }

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

セキュリティグループが1つ作成されることがわかります。ingressにSSH(ポート22)とHTTP(ポート80)の2つのインバウンドルール、egressにすべてのアウトバウンドトラフィックを許可するルールが設定されていることを確認してください。

9.3 AWSへの反映

問題なければterraform applyで反映します。

terraform apply

確認プロンプトが表示されたら、yesと入力して実行します。以下のように、セキュリティグループが1件作成されたことを確認します。

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

9.4 AWSコンソールでの確認

AWSマネジメントコンソールで EC2 > セキュリティグループ を開き、「terraform-ec2-sg」が作成されていることを確認してください。セキュリティグループを選択し、以下の項目がコードで設定した内容と一致していることも確認しましょう。

  • セキュリティグループ名 が「terraform-ec2-sg」であること
  • 説明 が「Security group for EC2 instance」であること
  • VPC が「terraform-vpc」であること
  • 「インバウンドルール」タブで、SSH(ポート22, TCP, ソース0.0.0.0/0)が許可されていること
  • 「インバウンドルール」タブで、HTTP(ポート80, TCP, ソース0.0.0.0/0)が許可されていること
  • 「アウトバウンドルール」タブで、すべてのトラフィック(全プロトコル, 送信先0.0.0.0/0)が許可されていること

10. EC2インスタンスの作成

10.1 コードの記載

ここでは、パブリックサブネット上にEC2インスタンス(仮想サーバ)を作成します。Terraformでは、resource "aws_instance"を使ってEC2インスタンスを定義します。以下の内容をmain.tfに追記してください。

# ====================
# EC2インスタンス
# ====================
resource "aws_instance" "web" {
  ami                    = "ami-088b486f20fab3f0e"
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.public.id
  vpc_security_group_ids = [aws_security_group.ec2.id]

  tags = {
    Name = "terraform-ec2"
  }
}
💡 ポイント
本章ではAMI IDを直接指定しています。AMI IDはリージョンや更新によって変わるため、もしEC2の作成時にAMIが見つからないエラーが出た場合は、AWSコンソールの EC2 > AMIカタログ で「Amazon Linux 2023」の最新のAMI IDを確認し、値を置き換えてください。後の章で扱うデータソース(data source)を使うと、最新のAMI IDを動的に取得できるため、実際のプロジェクトではデータソースを使うのが適切です。

今回設定した内容について解説します。

設定項目 設定の基準
ami(AMI ID) ami-088b486f20fab3f0e Amazon Linux 2023を使用するため(AMI IDは環境により異なる)
instance_type(インスタンスタイプ) t2.micro 無料利用枠の範囲内に収めるため
subnet_id(配置先サブネット) aws_subnet.public.id パブリックサブネットに配置するため
vpc_security_group_ids(適用するセキュリティグループ) [aws_security_group.ec2.id] 作成したセキュリティグループを適用するため
tags.Name(AWSコンソールに表示される名前タグ) terraform-ec2 リソースを識別するため

11. 出力の定義

11.1 コードの記載

ここでは、作成したリソースのIDやIPアドレスなどの情報をterraform applyの実行結果に表示するための出力(output)を定義します。Terraformでは、outputブロックを使って出力値を定義します。以下の内容をmain.tfに追記してください。

# ====================
# 出力
# ====================
output "vpc_id" {
  description = "VPC ID"
  value       = aws_vpc.main.id
}

output "public_subnet_id" {
  description = "Public Subnet ID"
  value       = aws_subnet.public.id
}

output "ec2_public_ip" {
  description = "EC2 Public IP"
  value       = aws_instance.web.public_ip
}

output "ec2_instance_id" {
  description = "EC2 Instance ID"
  value       = aws_instance.web.id
}

11.2 差分の確認

terraform planで差分を確認します。

terraform plan

以下のような実行結果が表示されます。

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.web will be created
  + resource "aws_instance" "web" {
      + ami                                  = "ami-088b486f20fab3f0e"
      + 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                            = "subnet-xxxxxxxxxxxxxxxxx"
      + tags                                 = {
          + "Name" = "terraform-ec2"
        }
      + tags_all                             = {
          + "Name" = "terraform-ec2"
        }
      + tenancy                              = (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_destroy         = false
      + vpc_security_group_ids               = (known after apply)
    }

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

Changes to Outputs:
  + ec2_instance_id  = (known after apply)
  + ec2_public_ip    = (known after apply)
  + public_subnet_id = "subnet-xxxxxxxxxxxxxxxxx"
  + vpc_id           = "vpc-xxxxxxxxxxxxxxxxx"

EC2インスタンスが1つ作成されることがわかります。amiにはAmazon Linux 2023のAMI IDが、instance_typeにはt2.microが、subnet_idにはパブリックサブネットのIDが設定されていることを確認してください。末尾のChanges to Outputsには、outputで定義した出力値が表示されています。

11.3 AWSへの反映

問題なければterraform applyで反映します。

terraform apply

確認プロンプトが表示されたら、yesと入力して実行します。以下のように、EC2インスタンスが1件作成され、定義した出力が表示されることを確認します。

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

Outputs:

ec2_instance_id = "i-xxxxxxxxxxxxxxxxx"
ec2_public_ip = "xx.xx.xx.xx"
public_subnet_id = "subnet-xxxxxxxxxxxxxxxxx"
vpc_id = "vpc-xxxxxxxxxxxxxxxxx"

11.4 AWSコンソールでの確認

AWSマネジメントコンソールで EC2 > インスタンス を開き、「terraform-ec2」が作成されていることを確認してください。インスタンスを選択し、以下の項目がコードで設定した内容と一致していることも確認しましょう。

  • AMI が「Amazon Linux 2023」であること
  • インスタンスタイプ が「t2.micro」であること
  • サブネット が「terraform-public-subnet」であること
  • セキュリティグループ が「terraform-ec2-sg」であること
  • パブリックIPv4アドレス が割り当てられていること

💡 ポイント
ec2_public_ipに表示されたIPアドレスを使って、EC2インスタンスに接続できます。ただし、このセクションではキーペアを設定していないため、SSHログインはできません。接続が必要な場合は、EC2 Instance Connectやセッションマネージャーを使用してください。

Terraformでも現在の状態を確認できます。terraform showコマンドで、管理しているすべてのリソースの詳細を表示できます。

terraform show

特定の出力だけを確認したい場合は、以下のコマンドを使用します。

terraform output ec2_public_ip

12. リソースの変更

Terraformの強みは、コードを変更するだけでインフラを更新できることです。試しにEC2インスタンスの名前を変更してみましょう。

12.1 コードの変更

main.tfのEC2インスタンスのタグを以下のように編集します。Nameの値を"terraform-ec2"から"terraform-web-server"に変更してください。

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

12.2 差分の確認

変更を保存したら、terraform planで差分を確認します。

terraform plan

以下のような実行結果が表示されます。

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with
the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_instance.web will be updated in-place
  ~ resource "aws_instance" "web" {
        id                                   = "i-xxxxxxxxxxxxxxxxx"
      ~ tags                                 = {
          ~ "Name" = "terraform-ec2" -> "terraform-web-server"
        }
      ~ tags_all                             = {
          ~ "Name" = "terraform-ec2" -> "terraform-web-server"
        }
        # (30 unchanged attributes hidden)
        # (8 unchanged blocks hidden)
    }

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

~ update in-placeの記号は、リソースを削除・再作成せず、その場で更新されることを示しています。"terraform-ec2" -> "terraform-web-server"と表示され、名前タグだけが変更されることがわかります。

12.3 AWSへの反映

問題なければterraform applyで反映します。

terraform apply

確認プロンプトが表示されたら、yesと入力して実行します。以下のように、1件のリソースが変更されたことを確認します。

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

12.4 AWSコンソールでの確認

AWSマネジメントコンソールで EC2 > インスタンス を開き、インスタンスの名前が「terraform-web-server」に変更されていることを確認してください。

このように、Terraformではコードを変更してterraform planで差分を確認し、terraform applyで反映するだけで、インフラの変更が可能です。

13. 不要リソースの削除

ハンズオンが終わったら、課金を避けるため、作成したリソースを削除します。

terraform destroy

確認プロンプトが表示されたら、yesと入力して実行します。

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

削除が完了すると、以下のように表示されます。

Destroy complete! Resources: 6 destroyed.
💡 ポイント
terraform destroyは、Terraformで管理しているすべてのリソースを削除します。Terraformはリソース間の依存関係を理解しているため、正しい順序(EC2 → サブネット → VPCなど)で削除を行います。

13.1 作業フォルダの削除(任意)

プロジェクトフォルダを削除する場合は、以下のコマンドを実行します。

rm -rf ~/terraform-aws-basic

14. まとめ

この章では、TerraformでシンプルなAWS構成を作る流れを体験しました。

  • VPC・サブネット・インターネットゲートウェイをTerraformコードで定義し、AWS上に構築できる
  • ルートテーブルにより、パブリックサブネットからインターネットへのアクセス経路を設計できる
  • セキュリティグループにより、EC2への通信を制御する構成を組める
  • リソース間の参照により、依存関係のあるリソースを順序どおりに作成できる
  • terraform plan で差分を確認しつつ、terraform apply で反映、AWSコンソールで確認する開発サイクルを回せる
  • terraform plan~ update in-place により、リソースを再作成せずに変更を反映できる
  • terraform destroy により、作成したリソースを一括削除できる

次の章では、Terraformの制御構文を学びつつ、実際にコードで扱いを確かめます。

この教材は役に立ちましたか?

いいねをたくさんいただけると、制作者の励みになり、より多くのセクションが作れるようになります。

感想を一言(任意)

いただいたコメントは次の制作のヒントになります。ぜひお気軽にご投稿ください。

このコメントは他の受講生には公開されません。DevOps Camp運営が、教材改善のために確認します。

0 / 2000