AWSでWebアプリを動かす場合、stagingやproductionといった環境ごとにVPCを分けるケースが多いと思います。VPCを作ったことがある方なら分かると思いますが、Webアプリを動かすために作成しなければならないVPC関連のリソースは結構多いです。
- VPC
- インターネットゲートウェイ
- ルートテーブル
- サブネット
- ルートテーブルとインターネットゲートウェイの関連付け
- ルートテーブルとサブネットの関連付け
- セキュリティグループ(本記事では説明しません)
パブリックに公開するなら最低限これくらいは必要ですが、管理コンソールでポチポチ作るのも大変ですし、Terraformの AWS Provider を使っても各リソースごとに設定を記述する必要があり、面倒ですしコード量も大きくなります。
そこで、Terraform Registry に登録されている AWS VPC Terraform module を使うと、少しの記述で必要なリソースをすべて作成することができます。
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "example"
cidr = "10.0.0.0/16"
azs = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
public_subnets = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"]
}
たったこれだけで、以下のリソースがすべて作成されます。便利ですね
- VPC
- インターネットゲートウェイ
- ルートテーブル
- サブネット
- ルートテーブルとインターネットゲートウェイの関連付け
- ルートテーブルとサブネットの関連付け
と、ここまでの内容は、すでに他で紹介されていたりしますw
ゼロベースならこれでいいのですが、最初からTerraformによるIaC (Infrastructure as Code) を実践していて、AWS上のあらゆるリソースがちゃんとTerraform管理下にある現場というのはそうそうありません(私の観測範囲内では)。管理コンソールで作ったリソースをTerraformにインポートして管理下におくことになりますが、AWSモジュールを使いつつインポートする方法がまとまっていなかったので、実際にやってみます
各リソースをインポートする
作業ディレクトリに main.tf
というファイルを以下の内容で作成します。
provider "aws" {
region = "ap-northeast-1"
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "example"
cidr = "10.0.0.0/16"
azs = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
public_subnets = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"]
}
インポートする際にどのリソースに対してインポートするかを指定しますが、Terraform Registryに登録されているモジュールにどんなリソースが含まれるかは、モジュールのページの「Resources」タブに書いてあります。
また、インポートする際にモジュールに含まれるリソースを指定するには、以下のように記述します。
$ terraform import module.vpc.xxx RESOURCE_ID
module.vpc
の vpc
は、モジュールに付けた名前です。
ここから各リソースをインポートしていきますが、IDが明示されているリソースについては、IDが記載されている場所のスクリーンショットとコマンドのみで簡単に説明します。なお、各リソースのIDは私の環境でのものなので、皆さんのものとは異なります。
VPC
$ terraform import module.vpc.aws_vpc.this vpc-03f02e915443e60c7
インターネットゲートウェイ
$ terraform import module.vpc.aws_internet_gateway.this igw-0b5c3992d5c6ccc91
ルートテーブル
$ terraform import module.vpc.aws_route_table.public rtb-0ab109683bef62f88
サブネット
サブネットはアベイラビリティーゾーンの数と同じく3つ作っていたので、3つすべてインポートする必要があります。
$ terraform import module.vpc.aws_subnet.public[0] subnet-021d6a31421d45dcd # ap-northeast-1a
$ terraform import module.vpc.aws_subnet.public[1] subnet-0a973037681ff7d9b # ap-northeast-1c
$ terraform import module.vpc.aws_subnet.public[2] subnet-057fefa3d5d6fe102 # ap-northeast-1d
ルートテーブルとインターネットゲートウェイの関連付け
管理コンソールにIDが記載されていませんね こういう場合に何を指定してインポートすればいいのかは、各リソースのページの「Import」セクションに記載されています。
ルートテーブルのIDと送信先のCIDRをアンダースコア _
で繋いで指定すればいいようです。
$ terraform import module.vpc.aws_route.public_internet_gateway rtb-0ab109683bef62f88_0.0.0.0/0
ルートテーブルとサブネットの関連付け
こちらも、管理コンソールにIDが記載されていません。リソースのページのImportセクションを見てみましょう。
サブネットのIDとルートテーブルのIDをスラッシュ /
で繋いで指定すればいいようです。サブネットの数と同じく3つインポートする必要があります。
$ terraform import module.vpc.aws_route_table_association.public[0] subnet-021d6a31421d45dcd/rtb-0ab109683bef62f88
$ terraform import module.vpc.aws_route_table_association.public[1] subnet-0a973037681ff7d9b/rtb-0ab109683bef62f88
$ terraform import module.vpc.aws_route_table_association.public[2] subnet-057fefa3d5d6fe102/rtb-0ab109683bef62f88
TerraformのStateと実際のリソースが合っていることを確認する
$ terraform plan
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
ということで、無事にVPCをTerraformの管理下におくことができました
このVPCはあくまで例なので削除してしまいますが、Terraformの管理下なら削除もコマンド一発です。
$ terraform destroy
最後に
VPCに限らず、最初からIaCを実践してあらゆるリソースをコードで管理するというのは、現実的には難しいと思います。私自身、リソースを操作するときには先に管理コンソールで操作して、ある程度落ち着いてから帳尻を合わせることが多いです。
インフラは一度構築すると変更する機会がアプリケーションほど多くないので、時間が経つとメンバーが増えたときにどんな構成なのか分かりにくかったり、構築した本人ですら忘れていることはよくあります。長期運用するなら、早い段階でIaCの仕組みを整えておきたいですね。