背景
こんにちは、キュービックでSREをやっているYuhta28です。キュービック内のテック技術について発信します。
過去何回かTerraformに関する記事を執筆しました。
この頃はTerraformを使い始めて日が浅く、作成リソースは全部手動で書かないといけないと考えていました。しかし、別のプロジェクトでAWS CDK1に触れる機会があり、AWS CDKのL2コンストラクトで構築してみたところ少ない記述量で必要な構成をすぐに用意してくれる便利さに魅了されました。
Terraformでも同じことがしたいと考え調べてみると、Terraform Registryで公開されているモジュールを使えば少ない記述量でリソースを作成できるみたいでしたのでモジュールを使ったTerraform IaCについて紹介いたします。
対象読者
- TerraformでIaCしている人
- 記述量が多くてもっと効率化したいと考えている人
- Terraform Modulesの使い方を知りたい人
Terraform Modulesについて
TerraformにはTerraform Registyという自由にダウンロードして使えるモジュールがいくつか存在します。例えばAWS関連のモジュールにはVPCを関連リソースを含めて作成してくれたり、EC2やRDSならセキュリティグループやIAMロールもセットに作成してくれるモジュールがあります。
https://registry.terraform.io/browse/modules?provider=aws
セットで書けるというのはどういうことかと言いますと一例を出します。
Amazon VPCを作成する場合、Terraformで書くと以下のようになります。
resource "aws_vpc" "main" { cidr_block = "10.0.0.0/16" tags = { Name = "Cuebic-VPC" } }
これをデプロイすればAWSにCuebic-VPC
というVPCが作成されます。しかしVPCにはサブネット、ルートテーブル、インターネットゲートウェイなど付随するリソースが数多くあり、Terraformはそれらすべてを別々のリソースとして記述しなければ作成されません。
パブリックサブネットとプライベートサブネットを含めた一般的なVPC関連リソースをTerraformでコード化すると、記述量が多くなり煩雑化してしまいます。
モジュールを使わないVPC作成
resource "aws_vpc" "terraform-vpc" { cidr_block = var.cidr_block enable_dns_hostnames = true tags = { Name = "${var.Tag_Name}-vpc" } } resource "aws_internet_gateway" "terraform-igw" { vpc_id = aws_vpc.terraform-vpc.id tags = { Name = "${var.Tag_Name}-igw" } } #-------------------------------------------------- # パブリックサブネットリソース resource "aws_subnet" "terraform-public-subnet" { for_each = var.public-AZ vpc_id = aws_vpc.terraform-vpc.id cidr_block = each.value availability_zone = "ap-northeast-1${each.key}" map_public_ip_on_launch = true tags = { Name = "terraform-${var.Tag_Name}-public-subnet-${each.key}" } } resource "aws_route_table" "terraform-public-rt" { for_each = var.public-AZ vpc_id = aws_vpc.terraform-vpc.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.terraform-igw.id } tags = { Name = "${var.Tag_Name}-public-rt-${each.key}" } } resource "aws_route_table_association" "terraform-public-rt-assoc" { for_each = var.public-AZ subnet_id = aws_subnet.terraform-public-subnet[each.key].id route_table_id = aws_route_table.terraform-public-rt[each.key].id } resource "aws_nat_gateway" "terraform-nat" { for_each = toset(var.eip-NAT-AZ) subnet_id = aws_subnet.terraform-public-subnet[each.key].id depends_on = [ aws_internet_gateway.terraform-igw ] allocation_id = aws_eip.terraform-nat-eip[each.key].id tags = { Name = "${var.Tag_Name}-nat-${each.key}" } } resource "aws_eip" "terraform-nat-eip" { for_each = toset(var.eip-NAT-AZ) tags = { Name = "${var.Tag_Name}-eip-${each.key}" } depends_on = [ aws_internet_gateway.terraform-igw ] } #-------------------------------------------------- #-------------------------------------------------- # プライベートサブネットリソース resource "aws_subnet" "terraform-private-subnet" { for_each = var.private-AZ vpc_id = aws_vpc.terraform-vpc.id cidr_block = each.value availability_zone = "ap-northeast-1${each.key}" tags = { Name = "terraform-${var.Tag_Name}-private-subnet-${each.key}" } } resource "aws_route_table" "terraform-private-rt" { for_each = var.private-AZ vpc_id = aws_vpc.terraform-vpc.id route { cidr_block = "0.0.0.0/0" nat_gateway_id = var.Tag_Name == "dev" ? aws_nat_gateway.terraform-nat["a"].id : aws_nat_gateway.terraform-nat[each.key].id } tags = { Name = "${var.Tag_Name}-private-rt-${each.key}" } } resource "aws_route_table_association" "terraform-private-rt-assoc" { for_each = var.public-AZ subnet_id = aws_subnet.terraform-private-subnet[each.key].id route_table_id = aws_route_table.terraform-private-rt[each.key].id }
サブネットとルートテーブルは2つをアタッチするためのリソースとしてaws_route_table_association
も必要となり手作業で作成するとかなり苦労します。VPC関連リソースはサービス毎に大きく構成が変わるものではなく、基本的にパブリックサブネット、プライベートサブネット、データベースサブネットを各AZ毎内に作成されれば十分であるケースも多いです。
先程のTerraform RegistryにはVPC向けのモジュールもありましたのでモジュールを使ったリソース作成がどのようなものか見ていきましょう。
モジュールを使ったVPC作成
https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/lates
モジュールを使う場合、resource
ブロックではなくmodules
ブロックを使用します。source
にはTerraform Registryで公開されているモジュールのパスを指定し、パラメーターに必要な値を入力しterraform apply
すればVPC関連リソースが作成されます。
module "vpc" { source = "terraform-aws-modules/vpc/aws" name = "my-vpc" cidr = "10.0.0.0/16" azs = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"] public_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] private_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"] database_subnets = ["10.0.11.0/24", "10.0.12.0/24", "10.0.13.0/24"] enable_nat_gateway = true tags = { Terraform = "true" Environment = "dev" } }
上記のコードを記述しますと3つのAZにパブリックサブネット、プライベートサブネット、データベースサブネット及びNATゲートウェイが作成されます。
パラメーターも多くはデフォルト値が設定されていますので最初から多く書く必要はなく必要なリソースを作成したいときに適宜パラメーターを変更すればOKです。
VPNゲートウェイを追加したい場合
enable_vpn_gateway = true
所感
Terraform Registryで公開されているモジュールを活用したTerraform運用について紹介しました。
最初の頃は頑張ってリソースをすべて書いていましたが、記述量が多くなりしんどいと感じていたところにモジュールを活用した方法を見つけられてTerraform開発が楽になりました。
Terraform Cloud2を使えば社内限定のプライベートモジュールも作成できますのでオリジナルモジュールを作成してぜひTerraform開発を効率化してみてください。