インフラ

terraform-aws-modules使ってますか?

mackey

こんにちは。エンジニアのmackeyです。

今回はTerraformでAWSのリソースを作成するときに役に立つterraform-aws-modulesを紹介しようと思います。

terraform-aws-modulesとは

terraform-aws-modulesは、コミュニティによって作られた、Terraformで様々なAWSリソースを作成するためのモジュール群です。Terraform Registry で公開されています。記事執筆時点で52個のモジュールが使えるようになっています。

モジュールとは?

Terraformにおけるモジュールは、複数のリソースをまとめて扱うための仕組みです。

モジュールがよく使われる例として、開発環境と本番環境で同じリソースを作りたいが、一部の設定項目だけ環境ごとに分けたいといった場合があります。この場合、作りたいリソースをまとめたモジュールを作成し、それぞれの環境で設定項目を指定してモジュールを利用することができます。

この例におけるモジュールは、同じローカル環境に存在するファイルを参照していますが、Terraformにはインターネットを通して他人が公開したモジュールを使える仕組みが用意されています。Terraform Registry ではパブリックなモジュールが公開されており、この後紹介する例のように外部のモジュールを利用することができます。

terraform-aws-modulesの使用例

実際の例を見たほうが早いと思うので、TerraformでVPC(とVPCエンドポイント)を作成するとして、通常どおりにリソースを書いた場合とterraform-aws-modulesを使用した場合を比べてみましょう。

実行環境

  • Terraform : v1.6.3
  • hashicorp/aws : v5.26.0

モジュールを使わずに書いた場合

resource "aws_vpc" "default" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "sample-vpc"
  }
}

resource "aws_subnet" "private_a" {
  vpc_id            = aws_vpc.default.id
  cidr_block        = "10.0.0.0/24"
  availability_zone = "ap-northeast-1a"
  tags = {
    "Name" = "sample-vpc-private-ap-northeast-1a"
  }
}

resource "aws_subnet" "private_c" {
  vpc_id            = aws_vpc.default.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = "ap-northeast-1c"
  tags = {
    "Name" = "sample-vpc-private-ap-northeast-1c"
  }
}

resource "aws_route_table" "private_a" {
  vpc_id = aws_vpc.default.id
  tags = {
    Name = "sample-vpc-private-ap-northeast-1a"
  }
}

resource "aws_route_table" "private_c" {
  vpc_id = aws_vpc.default.id
  tags = {
    Name = "sample-vpc-private-ap-northeast-1c"
  }
}

resource "aws_route_table_association" "private_a" {
  subnet_id      = aws_subnet.private_a.id
  route_table_id = aws_route_table.private_a.id
}

resource "aws_route_table_association" "private_c" {
  subnet_id      = aws_subnet.private_c.id
  route_table_id = aws_route_table.private_c.id
}

resource "aws_vpc_endpoint" "s3" {
  vpc_id            = aws_vpc.default.id
  service_name      = "com.amazonaws.ap-northeast-1.s3"
  route_table_ids   = [aws_route_table.private_a.id, aws_route_table.private_c.id]
  vpc_endpoint_type = "Gateway"
}

resource "aws_vpc_endpoint" "ecs" {
  vpc_id             = aws_vpc.default.id
  service_name       = "com.amazonaws.ap-northeast-1.ecs"
  security_group_ids = [aws_security_group.vpc_endpoint.id] # このコード上ではセキュリティグループは省略しています
}

terraform-aws-modulesを使用した場合

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.2.0"

  name = "sample-vpc"
  cidr = "10.0.0.0/16"

  azs = ["ap-northeast-1a", "ap-northeast-1c"]
  private_subnets = [
    "10.0.0.0/24",
    "10.0.1.0/24",
  ]
}

module "endpoints" {
  source  = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
  version = "5.2.0"

  vpc_id             = module.vpc.vpc_id
  security_group_ids = [aws_security_group.vpc_endpoint.id] # このコード上ではセキュリティグループは省略しています
  subnet_ids         = module.vpc.private_subnets

  endpoints = {
    s3 = {
      service         = "s3"
      service_type    = "Gateway"
      route_table_ids = module.vpc.private_route_table_ids
    },
    ecs = {
      service = "ecs"
    },
  }
}

terraform-aws-modulesを利用するメリット

上の例を比べても分かると思いますが、terraform-aws-modulesを使用するメリットは、簡潔に書けて視認性が良いことでしょう。

モジュールを使わずに書いた場合は、必要なリソースを一つ一つ作成する必要がありますが、terraform-aws-modulesを使った場合は、一つのモジュール内で完結させることができます。構築にかかる時間を短縮できるとともに、構築時のミスを減らすこともできるでしょう。

また、一つのモジュールにまとまっていることによって、後から見たときにどのような設定がされているかがわかりやすいです。上の例の場合、VPCに対して作成されているサブネットやエンドポイントの全体が一目でわかります。視認性が良いことは運用上のメリットにもなるでしょう。

terraform-aws-modulesを利用するデメリット・注意点

terraform-aws-modulesを使用することにはいくつかのデメリットや注意点も存在します。ここでは筆者が実際に使ってみて感じたことを挙げてみます。

できるカスタマイズに限りがある

モジュールで変更可能な項目は、あらかじめ設定されているパラメーターのみです。もし、カスタマイズしたい項目がパラメーターとして定義されていなければ、カスタマイズすることはできません。また、モジュールにはlifecycleブロックは設定できないので、例えばモジュール内の特定のリソースにignore_changesを設定するといったようなことはできません。

これに対応する手段として、モジュールのコードをローカルに持ってきて、それを編集して使うという手はあります。外部のモジュールを使いたいがカスタマイズが必要な場合には選択肢となるでしょう。

意図しないリソースが作られる可能性がある

モジュールを外側から見ただけでは、実際に作成されるリソースが何かはわかりません。tamterraform-aws-modulesで注意しなければいけないのは、何も書かなくてもデフォルトで作成されるようになっているリソースです。これらはオプションで作成しないようにもできますが、気づかないと必要ないのに作成してしまう場合があります。

例えばEventBridgeの場合、デフォルトではEventBridge Busなどが作成されるようになっています。これらが必要ない場合は、create_bus = false のようにモジュール内で指定する必要があります。どのリソースがデフォルトで作成されているかはドキュメントを確認する必要があったり、時にはどういう作りになっているかモジュールの実装を見に行くこともあったりしたので、少々辛い部分ではありました。

また、terraform planによってterraform-aws-modulesが作成しようとしている個別のリソースを確認することができるので、意図しないリソースが作成されていないか確認するようにしましょう。

どのリソースに対してterraform-aws-modules を使うべきか

ここまでメリットやデメリットを紹介してきましたが、それではterraform-aws-modulesを使うべきリソースはどれなのでしょうか。基本的にはメリットがどれだけ大きいかだと思いますが、以下のポイントを考慮するのがいいと考えます。

  • 普通に書く場合と比べてどれくらい簡潔になるか・視認性がよくなるか?
  • モジュールを使う上での学習コストがメリットに見合いそうか?

一つ目に関しては、メリットで挙げた通りです。各モジュールのドキュメントに使用例があるので、実際にコードを見てどれほど簡潔に書けそうか確認するのがいいでしょう。

二つ目に関しては、モジュールによっては書き方に癖があったり、使いこなすのが難しかったりするので、そのような場合は普通に書く場合と比べて余計にコストがかかってしまうかもしれません。こればかりは実際に使ってみないとわからない部分もありますが…。ただ、一度構築してしまえばメリットの方が上回ることもあると思うので、そこは考慮が必要ですね。

リソースの具体例

これらのポイントを考慮した上で、terraform-aws-modulesを使うのが良いリソースの例の一つは、具体例にもある通りVPCでしょう。普通に書く場合と比べてかなり簡潔になると思います。他にもS3バケットは実際に使ってみて良かったと感じました。通常はS3バケット一つに対して色々なリソースを作る必要がありますが、terraform-aws-modulesを使うと一つのバケットが一つのモジュールにまとまるのでとても見やすいです。

逆にセキュリティーグループはあまり便利とは感じませんでした。普通に書く場合と比べてそこまでコード量の削減につながらないのと、用意されているルールの数が多くて使いこなす労力がメリットに見合っていないように思いました。

筆者もterraform-aws-modulesのモジュールは一部しか使用していないため、もし他に「このリソースを作るときは使うといいよ!」というものがあれば教えていただきたいです。

まとめ

今回はTerraformでAWSリソースを作成するときに便利なterraform-aws-modulesを紹介しました。いくつか使用上の注意はあるものの、使うことのメリットが大きいモジュールに関しては積極的に使っていきたいと感じています。

AUTHOR
mackey
mackey
記事URLをコピーしました