Module Design

4 件の記事

ルール

Do not create modules that only wrap a single resource; define resources directly in the caller when needed

(単一リソースを包むだけのモジュールは作らない。必要な場合は呼び出し元で直接リソースを定義する)

解説

特定の設定をまとめただけのリソースブロックをモジュールにしないようにします。

粒度が小さすぎるモジュールは保守性をかえって悪化させます。

サンプルコード

参考リンク

ルール

Group related resources logically and encapsulate by functional units like network foundation and data layer

(関連リソースを論理的にまとめ、ネットワーク基盤やデータ層のような機能単位でカプセル化する)

解説

モジュールは用途に沿ったリソースをまとめられるように勤めます。variableブロックを用いた外部への依存およびoutputブロックを用いた外部への情報提供は少ないに越したことはありません。

サンプルコード

# ネットワーク基盤を機能単位でまとめたモジュール
# modules/networking/main.tf
resource "aws_vpc" "main" {

}

resource "aws_subnet" "public" {

}

resource "aws_internet_gateway" "main" {

}

resource "aws_route_table" "public" {

}

参考リンク

ルール

Always expose reference values for resources within modules through outputs to make dependencies explicit

(モジュール内リソースの参照値は必ずoutputで公開し、依存関係を明示する)

解説

あるモジュール内で作成されたリソースの値を他のモジュールやリソースで使用する際は、outputブロックを通じて利用させます。 言い方を変えると、dataブロックやARNのハードコーディングを用いるコーディングは、保守性を落とすため避けるべきです。

サンプルコード

# outputで参照値を明示的に公開
# modules/networking/outputs.tf
output "vpc_id" {
  description = "The ID of the VPC"
  value       = aws_vpc.main.id
}

参考リンク

ルール

Keep module hierarchy to 1-2 levels and maintain flat inheritance

(モジュール階層を1〜2段階に保ち、フラットな継承を維持する)

解説

サブモジュールから別のサブモジュールを呼び出す構造は極力避けます。避けられない場合でも1度までとします。 コピペしたDRYではないベタ書きが増えるわけですが、Terraform用コードは結局それがバランスがいいようです。

サンプルコード

# フラットなモジュール階層
# main.tf(ルートモジュール)
module "networking" {
  source = "./modules/networking"

  vpc_cidr             = var.vpc_cidr
  availability_zones   = var.availability_zones
  public_subnet_cidrs  = var.public_subnet_cidrs
  private_subnet_cidrs = var.private_subnet_cidrs
}

module "application" {
  source = "./modules/application"

  vpc_id            = module.networking.vpc_id
  private_subnet_ids = module.networking.private_subnet_ids
  app_port          = var.app_port
}

# modules/networking/ と modules/application/ は
# さらに他のモジュールを呼ばず、直接リソースを定義

参考リンク