第1回：AWSのWebアプリ環境を生成AIを使ってterraformを書いてみたら想像以上に書いてくれた、VPCサブネット編

## 狙い、目的とか
第0回に書いたので、そちらを参照
https://qiita.com/michi_taka/items/55ec466f99d0d87e08b7

## 作りたいアプリの環境

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/710930e1-d3d2-fdd6-c63a-6a71318960c4.png)

## 第一回の目標

- VPCの作成
- VPCに紐づくprivateとpiblicのsubnetを作る
- インターネットゲートウェイとpublic_subnetを作る

## ざっくりと作ってもらう

>AWSでWebアプリを作りたい。その為に、AWSの基本的なネットワークを構築したいのだけど、terraformのmain.tfで書いてほしい

```terraform:出てきたmain.tf
# プロバイダの設定
provider "aws" {
  region = "ap-northeast-1" # リージョンを指定
}

# VPCの作成
resource "aws_vpc" "vpc" {
  cidr_block = "10.0.0.0/16" # VPCのCIDRブロック
}

# インターネットゲートウェイの作成
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id
}

# パブリックサブネットの作成
resource "aws_subnet" "public_subnet" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.1.0/24"
  availability_zone = "ap-northeast-1a"
}

# プライベートサブネットの作成
resource "aws_subnet" "private_subnet" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.2.0/24"
  availability_zone = "ap-northeast-1b"
}

# NATゲートウェイの作成
resource "aws_nat_gateway" "nat" {
  subnet_id = aws_subnet.public_subnet.id
}

# ルートテーブルの作成
resource "aws_route_table" "public_route_table" {
  vpc_id = aws_vpc.vpc.id
}

# インターネットへのルートの設定
resource "aws_route" "public_route" {
  route_table_id = aws_route_table.public_route_table.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id = aws_internet_gateway.igw.id
}

# プライベートサブネット用のルートテーブルの作成
resource "aws_route_table" "private_route_table" {
  vpc_id = aws_vpc.vpc.id
}

# NATゲートウェイへのルートの設定
resource "aws_route" "private_route" {
  route_table_id = aws_route_table.private_route_table.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id = aws_nat_gateway.nat.id
}

# パブリックサブネットとルートテーブルの関連付け
resource "aws_subnet_route_table_association" "public_subnet_association" {
  subnet_id = aws_subnet.public_subnet.id
  route_table_id = aws_route_table.public_route_table.id
}

# プライベートサブネットとルートテーブルの関連付け
resource "aws_subnet_route_table_association" "private_subnet_association" {
  subnet_id = aws_subnet.private_subnet.id
  route_table_id = aws_route_table.private_route_table.id
}
```

>これにあわせたoutput.tfをください

```terraform:出てきたoutput.tf
output "vpc_id" {
  value = aws_vpc.vpc.id
}

output "public_subnet_id" {
  value = aws_subnet.public_subnet.id
}

output "private_subnet_id" {
  value = aws_subnet.private_subnet.id
}

output "nat_gateway_id" {
  value = aws_nat_gateway.nat.id
}

output "public_route_table_id" {
  value = aws_route_table.public_route_table.id
}

output "private_route_table_id" {
  value = aws_route_table.private_route_table.id
}
```

す、すごい、VPCとサブネットくらいかなと思ったら、「よしなに」ってプロンプトで、インターネットゲートウェイやNATゲートウェイを作り、さらにルートテーブルで紐付けるというところまでやってくれているっぽい。賢い。

しかも、作ったものが何者かも説明してくれている。初心者がなんとなく作っても、何をしてくれたのかも分かるの。これは結構オススメ出来る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293892/152fb001-9785-1c67-4db0-581830e3d605.png)


## 検証:本当に動くのか？

とりあえずproviderだけ外して`terragrunt plan`してみた。

```terraform: enviroments/staging/network/terragrunt.tf
include {
  path = find_in_parent_folders()
}

terraform {
  source   = "../../../modules/network"
}

locals {
  vars = read_terragrunt_config(find_in_parent_folders()).locals
}

inputs =  {
}
```

```bash:terminal
$ terragrunt plan
╷
│ Error: Invalid resource type
│ 
│   on main.tf line 55, in resource "aws_subnet_route_table_association" "public_subnet_association":
│   55: resource "aws_subnet_route_table_association" "public_subnet_association" {
│ 
│ The provider hashicorp/aws does not support resource type
│ "aws_subnet_route_table_association".
╵
╷
│ Error: Invalid resource type
│ 
│   on main.tf line 61, in resource "aws_subnet_route_table_association" "private_subnet_association":
│   61: resource "aws_subnet_route_table_association" "private_subnet_association" {
│ 
│ The provider hashicorp/aws does not support resource type
│ "aws_subnet_route_table_association".
╵
ERRO[0006] terraform invocation failed in /terraform/environments/staging/network/.terragrunt-cache/B4qCgWcRI8RFWZ4IAZOsmqc-PTw/X6RMdv6Ei411VzKlVvHwgWkiheE  error=[/terraform/environments/staging/network/.terragrunt-cache/B4qCgWcRI8RFWZ4IAZOsmqc-PTw/X6RMdv6Ei411VzKlVvHwgWkiheE] exit status 1 prefix=[/terraform/environments/staging/network] 
ERRO[0006] 1 error occurred:
	* [/terraform/environments/staging/network/.terragrunt-cache/B4qCgWcRI8RFWZ4IAZOsmqc-PTw/X6RMdv6Ei411VzKlVvHwgWkiheE] exit status 1

```

`aws_subnet_route_table_association`を`aws_route_table_association`に変えるだけでplanが通った。

## 改造：CIDRの変数化

>VPCとサブネットのCIDRの値は変数化してほしい。

```terraform:main.tf ※修正・追加部分だけ
variable "public_subnet_cidr_block" {
  type = string
  default = "10.0.1.0/24"
}

variable "private_subnet_cidr_block" {
  type = string
  default = "10.0.2.0/24"
}

# VPCの作成
resource "aws_vpc" "vpc" {
  cidr_block = var.vpc_cidr_block
}

# インターネットゲートウェイの作成
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id
}

# パブリックサブネットの作成
resource "aws_subnet" "public_subnet" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = var.public_subnet_cidr_block
  availability_zone = "ap-northeast-1a"
}

# プライベートサブネットの作成
resource "aws_subnet" "private_subnet" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = var.private_subnet_cidr_block
  availability_zone = "ap-northeast-1b"
}
```

terraformのバージョンだと`"string"`→`string`にする必要があったので、それだけ修正したら通った。ここまでほとんど作業をしていない。



## 改造：タグの設定
> 各リソースにtagsを付けて欲しい。中身は、Name, Project, Envの3つ。NAMEには変数app_nameの後ろに、それぞれ要素を紐付けたものにしてほしい。Envは変数env、Projectには変数app_nameが入るようにしてほしい。

```terraform:出てきたoutput.tf
# プロバイダの設定
provider "aws" {
  region = "ap-northeast-1" # リージョンを指定
}

# 変数の定義
variable "app_name" {
  type = "string"
  default = "web-app"
}

variable "env" {
  type = "string"
  default = "dev"
}

# VPCの作成
resource "aws_vpc" "vpc" {
  cidr_block = var.vpc_cidr_block
  tags = {
    Name = var.app_name + "-vpc"
    Project = var.app_name
    Env = var.env
  }
}

# インターネットゲートウェイの作成
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id
  tags = {
    Name = var.app_name + "-igw"
    Project = var.app_name
    Env = var.env
  }
}

中略

# プライベートサブネット用のルートテーブルの作成
resource "aws_route_table" "private_route_table" {
  vpc_id = aws_vpc.vpc.id
  tags = {
    Name = var.app_name + "-private-route-table"
    Project = var.app_name
    Env = var.env
  }
}

# NATゲートウェイへのルートの設定
resource "aws_route" "private_route" {
  route_table_id = aws_route_table.private_route_table.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id = aws_nat_gateway.nat.id
  tags = {
    Name = var.app_name + "-private-route"
    Project = var.app_name
    Env = var.env
  }
}

# パブリックサブネットとルートテーブルの関連付け
resource "aws_subnet_route_table_association" "public_subnet_association" {
  subnet_id = aws_subnet.public_subnet.id
  route_table_id = aws_route_table.public_route_table.id
  tags = {
    Name = var.app_name + "-public-subnet-association"
    Project = var.app_name
    Env = var.env
  }
}

# プライベートサブネットとルートテーブルの関連付け
resource "aws_subnet_route_table_association" "private_subnet_association" {
  subnet_id = aws_subnet.private_subnet.id
  route_table_id = aws_route_table.private_route_table.id
  tags = {
    Name = var.app_name + "-private-subnet-association"
    Project = var.app_name
    Env = var.env
  }
}
```

ちょっと怪しくなってきた。

- せっかく作ってくれたCIDRの変数が消えた
- ルートテーブルとの関連付けなど、tagsが設置出来ないところにも設置している
- `var.app_name + "-private-subnet"`はエラーになる

この後、色々質問を繰り返したが、コードにhtmlコードが挿入されるなど、ちぐはぐな結果が帰ってきた為、タグの挿入は、AIでもらった物をベースに手で修正することにした。

## まとめ
- 非常にシンプルな質問でかなりのところまで作ってくれる
- 作業時間は10分程度
- 気に入らない部分をAIにやらせようとすると逆にコミュニケーションコストがかさみそう
- 基本はAIに作らせて、細かな部分は手でやったほうが良さそう
- 他にもVPCエンドポイントの設定やマルチAZ対応等、細かな事はやってくれなさそう
- 

## とりあえず作った物をgithub

最終的に作ったコード、参考にしたい方は以下よりご確認ください。

https://github.com/michihitoTakami/gemini-terraform-terragrunt/tree/1536eaec1f70510cf67b7e4791de1bd37eef0195

### 追記：ElasticIPの設定が無かったからApplyできなかった

nat gatewayにeip紐付けないとね…流石にココまではやってくれないか…。

```terraform
# NATゲートウェイの作成
resource "aws_eip" "nat_gateway_eip" {
  depends_on = [aws_internet_gateway.igw]

  tags = {
    Name = "${var.app_name}-nat-gateway-eip"
    Env     = var.env
    Project = var.app_name
  }
}

resource "aws_nat_gateway" "nat" {
  subnet_id = aws_subnet.public_subnet.id
  allocation_id = aws_eip.nat_gateway_eip.id

  tags = {
    Name = "${var.app_name}-nat-gateway"
    Project = var.app_name
    Env = var.env
  }
}
```