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における繰り返しについてお話しします。

ではまた。

Recommendおすすめブログ