中村的雑記

技術に関する記事を書いていきます。iOSエンジニア->Railsエンジニア。

TerraformでAWSのsubnetを作る

はじめに

TerraformでのAWSvpcとsubnet部分の作り方をまとめておく。
間違いなどあれば、指摘していただけると幸いだ。 ちなみにIPやcidr_blockなどは実際に作成したものとは違うものを本記事のサンプルコード内で使っている。

ディレクトリ構成

勉強会で作成したインフラ全般のアーキテクチャは下記のようになっていて、
今回はココ、と書いてある所の作り方についてお話しする。

├── terraform
│   ├── environment
│   │   └── production
│   │       ├── locals.tf
│   │       └── main.tf
│   └── modules
│       ├── alb
│       │   ├── main.tf
│       │   ├── output.tf
│       │   └── variables.tf
│       ├── alb_listener
│       │   ├── main.tf
│       │   ├── output.tf
│       │   └── variables.tf
│       ├── ecs
│       │   ├── container_definitions.json
│       │   ├── execution-assume-role.json
│       │   ├── execution-policy.json
│       │   ├── main.tf
│       │   ├── output.tf
│       │   └── variables.tf
│       ├── private_subnet <=======ココ
│       │   ├── main.tf
│       │   ├── output.tf
│       │   └── variables.tf
│       ├── public_subnet  <=======ココ
│       │   ├── main.tf
│       │   ├── output.tf
│       │   └── variables.tf
│       ├── route53
│       │   ├── main.tf
│       │   ├── output.tf
│       │   └── variables.tf
│       ├── security_group
│       │   ├── main.tf
│       │   ├── output.tf
│       │   └── variables.tf
│       └── vpc <==============ココ
│           ├── main.tf
│           ├── output.tf
│           └── variables.tf

実装方針

上の構成の通り、
基本的に各機能ごとにmoduleを作り、

main.tf => moduleの機能実装

variables.tf => 外から入れたい変数etc

output.tf => 他のmoduleなどから呼び出したい当moduleの変数etc

といった形で定義している。

vpcの実装

resource "aws_vpc" "main" {
  cidr_block = var.cidr_block

  tags = {
    Name = "hogehoge-${var.env}-main-vpc"
  }
}
  • vpc/variables.tf
variable "env" {
  type        = string
  description = "Environment"
}

variable "cidr_block" {
  type        = string
  description = "VPCのCIDR Block"
}
  • vpc/output.tf
output "id" {
  value = aws_vpc.main.id
}

output "cidr_block" {
  value = aws_vpc.main.cidr_block
}

public_subnetの実装

  • public_subnet/main.tf
resource "aws_subnet" "main" {
  vpc_id            = var.vpc_id
  count             = length(var.availability_zones)
  cidr_block        = element(var.cidr_blocks, count.index)
  availability_zone = element(var.availability_zones, count.index)

  tags = {
    Name = "hogehoge-${var.env}-public-subnet-${element(var.availability_zones, count.index)}"
  }
}

resource "aws_route_table" "main" {
  vpc_id = var.vpc_id
}

resource "aws_route" "main" {
  route_table_id         = aws_route_table.main.id
  gateway_id             = var.internet_gateway_id
  destination_cidr_block = "0.0.0.0/0"
}

resource "aws_route_table_association" "main" {
  count          = length(var.availability_zones)
  subnet_id      = aws_subnet.main[count.index].id
  route_table_id = aws_route_table.main.id
}

resource "aws_eip" "nat_gateway" {
  vpc   = true
  count = length(aws_subnet.main)
}

resource "aws_nat_gateway" "main" {
  count         = length(aws_subnet.main)
  allocation_id = aws_eip.nat_gateway[count.index].id
  subnet_id     = aws_subnet.main[count.index].id
}
  • public_subnet/varaibles.tf
variable "env" {
  type = string
}

variable "availability_zones" {
  type = list(string)
}

variable "cidr_blocks" {
  type = list(string)
}

variable "vpc_id" {
  type = string
}

variable "internet_gateway_id" {
  type = string
}
  • public_subnet/output.tf
output "ids" {
  value = aws_subnet.main.*.id
}

output "nat_gateway_ids" {
  value = aws_nat_gateway.main.*.id
}

main.tf内で、countを指定することで、指定した数だけsubnetを作ることができる。
element(list, index)を使うことで、arrayのindexに対応するものを参照できる。
[参照元] www.terraform.io

またnat_gatewayはpublic_subnet内においておく必要があるのここで定義し、また静的なIPを付与するためaws_eipを指定する。

private_subnetの実装

  • private_subnet/main.tf
resource "aws_subnet" "main" {
  vpc_id            = var.vpc_id
  count             = length(var.availability_zones)
  cidr_block        = element(var.cidr_blocks, count.index)
  availability_zone = element(var.availability_zones, count.index)
}

resource "aws_route_table" "main" {
  vpc_id = var.vpc_id
  count  = length(var.availability_zones)
}

resource "aws_route_table_association" "main" {
  count          = length(aws_subnet.main)
  subnet_id      = aws_subnet.main[count.index].id
  route_table_id = aws_route_table.main[count.index].id
}

resource "aws_route" "main" {
  count                  = length(var.availability_zones)
  route_table_id         = aws_route_table.main[count.index].id
  nat_gateway_id         = element(var.nat_gateway_ids, count.index)
  destination_cidr_block = "0.0.0.0/0"
}
  • private_subnet/varaibles.tf
variable "env" {
  type = string
}

variable "availability_zones" {
  type = list(string)
}

variable "cidr_blocks" {
  type = list(string)
}

variable "vpc_id" {
  type = string
}

variable "nat_gateway_ids" {
  type = list(string)
}
  • private_subnet/output.tf
output "ids" {
  value = aws_subnet.main.*.id
}

public_subnetと違う点は、nat_gateway_idをmain.tf内で指定する所で、
これによって片方向通信をすることができるようになる。

次回

セキュリティグループmoduleについて書く。