Terraform HCL入門 2回目 moduleの作り方
皆さん、こんにちは。技術開発グループのn-ozawanです。
最近知って驚いた話。ハムスターは1日に1kgあたり20gのアルコールを分解します。これは標準的な男性が1日にワイン21本を摂取するのに匹敵します。ハムスターは動物界一の酒豪です。
本題です。
前回、Terraformのresourceの作り方をお話ししました。今回はHCL入門2回目ということで、moduleの作り方についてお話しします。moduleはTerraformでコード化する際には必要になる重要な要素です。
目次
module ブロック
module
Terraformでは、複数のresourceブロックを1つのモジュールにまとめることが出来ます。moduleブロックは、そのモジュールを使用する際に使うブロックです。
よく使うリソースの構成などをモジュール化することで再利用が可能になりますので、環境の複製や、複数のmoduleを組み合わせることで、複雑な環境も簡単に構築することが出来るようになります。
moduleの作り方
moduleを作るための文法はありません。フォルダに格納されたtfファイルが1つのモジュールとして認識されます。フォルダとファイルの構成でmoduleが作られます。以下はその一例です。

moduleの使い方
moduleブロックの構文は以下の通りです。
module "識別子" { source = "moduleの在り処" # argument... }
“識別子”はモジュールの名前です。一意にする必要があります。sourceはmoduleブロックで必須の引数です。そのモジュールのtfファイルがどこに格納されているのかを指定します。sourceはローカル環境から、Git、Terraformのレジストリまで、幅広く指定することが出来ます。詳細は公式サイトを参照して欲しいですが、ここではいくつか紹介します。
ローカル環境にあるモジュールを使用する場合は、sourceにはそのモジュールへのパスを指定します。先ほどの一例で提示したフォルダ構成であれば、以下のようになります。
module "sample" {
source = "./modules/sample"
}
Terraformのレジストリには、公式のHashiCorp社はもちろんのこと、多くの有志により沢山のmoduleが公開されています。それら公開されたmoduleを利用したい場合は以下のように記述します。
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
# (省略)
}
terraform-aws-modules/vpc/aws
はAWSにおけるネットワーク全般をいい感じに構築してくれるモジュールです。このモジュール1つで、VPCからSubnet、Gatewayなどの必要なリソースが構築されます。ドキュメントはこちらにありますので、興味ある方は覗いてみてください。
variableとoutput
前回、variableブロックとoutputブロックについてお話ししました。variableブロックは外部から値を受け取る引数であり、outputブロックはコンソールへの出力でしたね。moduleでのvariableとoutputは少し違う動きをします。
variableブロックはmoduleの呼び出し元から受け取る引数となります。また、outputブロックはmoduleの呼び出し元へ渡す戻り値となります。実際にコードを見てみましょう。以下はAWSでNAT Gatewayを構築するコードです。引数にSubnetのIDと、戻り値にElastic IPで割り振られたIPアドレスを返却しています。
# 引数
variable "subnet_id" {} # 呼び出し元からSubnetのIDを受け取る
# Elastic IP
resource "aws_eip" "eip" {
vpc = true
}
# NAT Gateway
resource "aws_nat_gateway" "nat" {
subnet_id = var.subnet_id # NAT Gatewayを配置するSubnetを指定
allocation_id = aws_eip.eip.id # 紐付けるElasti IP
}
# 戻り値
output "elastic_public_ip" {
value = aws_eip.eip.public_ip # 呼び出し元へElastic IPで割り振られたIPアドレスを返却する
}
モジュールの呼び出し元は以下のようになります。呼び出し元でモジュールの戻り値を参照するには、module.”moduleの識別子”.”outputの識別子”で参照できます。
# VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
# Subnet
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id # VPCとSubnetの紐付け
cidr_block = "10.0.1.0/24"
availability_zone = "ap-northeast-1a"
}
# NAT Gateway
module "nat_gateway" {
source = "./modules/nat_gateway"
subnet_id = aws_subnet.public.id # SubnetのIDをmoduleへ渡す
}
output "elastic_public_ip" {
value = module.nat_gateway.elastic_public_ip # 戻り値をコンソールへ出力する
}
おわりに
今回はTerraformのmoduleブロックについてお話ししました。AWSでちょっとした環境を作ろうとしただけでresourceは50を超えます。もちろん、50を超えるresourceを1つのモジュールで構築することは出来ますが、可読性や可用性の観点からお勧めできません。いかに綺麗にモジュール化するかがTerraformの腕の見せ所でもあるかと思います。
次回ですが、似たようなresourceやmoduleを複製しようとしたとき、律儀にコードで記述すると大変ですよね。次回はTerraformにおける繰り返しについてお話しします。
ではまた。