🌎 Terraform で AWSのEC2インスタンスを作成するシンプルな手順

# 📌 概要
Terraform を使って EC2 インスタンスを作成し、AWS の Elastic IP (EIP) を EC2 に関連付ける方法を解説します

# 📌 事前に準備するもの

##### main.tf

main.tf の作成がまだの方は以下の記事を参考にファイルを作成してください。

https://qiita.com/nobumory/items/624275ac0b08660a2637

##### VPC

VPCを作成していない場合は以下を参考に作成します。

https://qiita.com/nobumory/items/72ab7a109b24b5a08287

##### サブネット

サブネット を作成していない場合は以下を参考に作成します。

https://qiita.com/nobumory/items/4626953585c964f12f73

##### セキュリティグループ 

セキュリティグループ を作成していない場合は以下を参考に作成します。

https://qiita.com/nobumory/items/359c5486b626f864cc6b

# 📌 ディレクトリ構成

```
terraform-project/
│── main.tf
│── modules/
│   ├── ec2/
│   │   ├── main.tf
│   ├── subnet/
│   │   ├── main.tf
│   ├── security_group/
│   │   ├── main.tf
│   ├── vpc/
│   │   ├── main.tf
```

# 📌 コード

### main.tf

AWS のプロバイダーを設定し、EC2 インスタンスの作成に必要なモジュールを読み込みます。

```hcl
# Terraform が操作する AWS のリージョンを指定
provider "aws" {
  region = "ap-northeast-1" # 東京リージョン
}

# VPC モジュールの読み込み

module "vpc" {
  source = "./vpc"
}

# サブネットモジュールの読み込み
module "subnet" {
  source = "./subnet"
  vpc_id = module.vpc.vpc_id
}

# セキュリティグループモジュールの読み込み
module "security_group" {
  source = "./security_group"
  vpc_id = module.vpc.vpc_id
}

# EC2 インスタンスモジュールの読み込み

module "ec2" {
  source       = "./ec2"
  vpc_id       = module.vpc.vpc_id
  subnet_id    = module.subnet.subnet_public_id  # パブリックサブネットに配置
  public_sg_id = module.security_group.public_sg_id  # パブリックセキュリティグループを適用
}
```

### security_group/main.tf

EC2に紐づける パブリック（インターネット向け）な セキュリティグループ（SG） を作成します。

```hcl
# VPC の ID を受け取る変数を定義
variable "vpc_id" {
  description = "Internet Gateway を関連付ける VPC の ID"
  type        = string
}

# ----------- グループの作成
resource "aws_security_group" "public" {
  name        = "sandbox-terraform-public"
  description = "Security group for public EC2 instances"
  vpc_id      = var.vpc_id

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

# ----------- ルールの設定

# プライベートSGからの全トラフィックを許可
resource "aws_security_group_rule" "public_private_sg" {
  type                     = "ingress"
  from_port                = 0
  to_port                  = 0
  protocol                 = "-1"
  security_group_id        = aws_security_group.public.id
  source_security_group_id = aws_security_group.private.id
  description              = "Allow all traffic from private security group"
}

# HTTPS (443) の外部アクセスを許可
resource "aws_security_group_rule" "public_https" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  security_group_id = aws_security_group.public.id
  cidr_blocks       = ["0.0.0.0/0"] # すべての IP からのアクセスを許可
  description       = "Allow HTTPS from everywhere"
}

# HTTP (80) の外部アクセスを許可
resource "aws_security_group_rule" "public_http" {
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  security_group_id = aws_security_group.public.id
  cidr_blocks       = ["0.0.0.0/0"] # すべての IP からのアクセスを許可
  description       = "Allow HTTP from everywhere"
}

# SSH (22) の外部アクセスを許可
# ※ セキュリティ上、特定の IP に制限するのが望ましい
resource "aws_security_group_rule" "public_ssh" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  security_group_id = aws_security_group.public.id
  cidr_blocks       = ["0.0.0.0/0"] # すべての IP から SSH 接続を許可
  description       = "Allow SSH from everywhere"
}

# 作成したパブリックセキュリティグループの ID を出力
# 他のリソース（EC2 インスタンスなど）で参照できるようにする
output "public_sg_id" {
  value = aws_security_group.public.id
}
```

### subnet/main.tf

VPC 内に パブリックサブネット を作成し、EC2 を配置できるようにします。

```hcl
# VPC の ID を受け取る変数を定義
variable "vpc_id" {
  description = "Internet Gateway を関連付ける VPC の ID"
  type        = string
}

# サブネットの作成
resource "aws_subnet" "public" {
  vpc_id                  = var.vpc_id
  cidr_block              = "192.168.250.128/25"  # サブネットのIP範囲
  availability_zone       = "ap-northeast-1a"  # 東京リージョンの特定のAZに配置

  tags = {
    Name = "sandbox-terraform-public"  # サブネットの識別用タグ
  }
}

# 作成したサブネットの ID を出力し、他のモジュールで利用できるようにする
output "subnet_public_id" {
  value = aws_subnet.public.id
}
```

### ec2/main.tf

EC2 インスタンスを作成し、Elastic IP を関連付けることで、インターネットからアクセスできる Web サーバーとします。

```hcl
# VPC の ID を受け取る変数を定義
variable "vpc_id" {
  description = "Internet Gateway を関連付ける VPC の ID"
  type        = string
}

# サブネット の ID を受け取る変数を定義
variable "subnet_id" {
  description = "Subnet の ID"
  type        = string
}

# セキュリティー の ID を受け取る変数を定義
variable "public_sg_id" {
  description = "Public Security Group の ID"
  type        = string
}

# ------ ec2 の作成

# インスタンスの作成
resource "aws_instance" "ec2" {
  ami                    = "ami-0b28346b270c7b165" # Amazon Linux 2023 の AMI ID
  instance_type          = "t2.nano" # 小規模な開発用インスタンス
  key_name               = "key-name" # SSH キーペアの指定
  subnet_id              = var.subnet_id # 指定したパブリックサブネットに配置
  associate_public_ip_address = true # インターネットに公開するためのパブリック IP を付与
  security_groups        = [var.public_sg_id] # 指定したセキュリティグループを適用

  # ルートボリューム（EBS）の設定
  root_block_device {
    volume_size = 8 # ルートボリュームのサイズ（GB）
    volume_type = "gp2" # 一般的な SSD ストレージ
  }

  tags = {
    Name = "sandbox-terraform-ec2" # EC2 の名前タグ
  }
}

# ------ Elastic IP の作成と関連付け

# Elastic IPの作成
resource "aws_eip" "main" {
  domain = "vpc"
  tags = {
    Name = "sandbox-terraform-eip"
  }
}

# Elastic IP を EC2 インスタンスに関連付け
resource "aws_eip_association" "ec2_eip_assoc" {
  instance_id   = aws_instance.ec2.id
  allocation_id = aws_eip.main.id
}

# -------------------------------- 出力

# EC2 のネットワークインターフェース ID
output "ec2_primary_network_interface_id" {
  value = aws_instance.ec2.primary_network_interface_id
}

# Elastic IP のパブリック IP アドレス
output "ec2_elastic_ip" {
  value = aws_eip.main.public_ip
}
```

[参考リポジトリ]

https://gitlab.com/Morykun/sandbox-terraform

# 📌 実行

準備ができたらコマンド実行しましょう！

1. `terraform init`
2. `terraform plan`
3. `terraform apply`

Terraform関連のコマンドについては以下の記事を参考にしてください ☺️

https://qiita.com/nobumory/items/9f3c84f016fbf37363ed