★★ 中級

10. モジュールバージョニング

共有モジュールを Git tag + semver でバージョン公開し、利用側は ?ref=v1.2.3 で固定する。これだけで「いつ誰が module を更新しても、すぐに本番に伝播しない」運用が成立。

なぜバージョニングが要るか

モジュールを source = "git::...?ref=main" のように main に向けると、「main が更新された瞬間に、そのモジュールを使う全プロジェクトが影響を受ける」状態になります。

tag でバージョン固定すれば、利用側は 「自分が選んだバージョン」を明示的にしか取り込まない

semver の基本

semver = Semantic Versioning。MAJOR.MINOR.PATCH の 3 数字。

区分変更内容
MAJOR後方互換のない破壊的変更1.4.0 → 2.0.0
MINOR後方互換のある機能追加1.4.0 → 1.5.0
PATCH後方互換のあるバグ修正1.4.0 → 1.4.1

Terraform module の場合 「MAJOR を上げる = 利用側の variable や output を変える」 と考えると分かりやすい。

Git tag で公開

モジュール側のリポジトリで:

# 開発が一段落したら tag を打つ
git tag v1.4.0
git push origin v1.4.0

# まとめて push
git push --tags

# 削除して打ち直し(push 前なら)
git tag -d v1.4.0

v プレフィックス(v1.4.0)を付ける慣例。v なしでも機能はするが、揃えておくと UI が綺麗。

GitHub Releases(任意だが推奨)

tag に加えて GitHub Releases で changelog を書くと、利用者が変更点を一目で確認できます。

# GitHub CLI で
gh release create v1.4.0 \
  --title "v1.4.0" \
  --notes "## Added\n- IPv6 support for VPC module\n## Fixed\n- ..."

利用側のバージョン固定

利用側(呼び出すプロジェクト)の HCL:

module "vpc" {
  source = "git::https://github.com/your-org/terraform-modules.git//vpc?ref=v1.4.0"

  cidr_block = "10.0.0.0/16"
  # ...
}

# モノレポでパスを使う場合
module "compute" {
  source = "git::https://github.com/your-org/terraform-modules.git//compute?ref=v2.0.1"
}

Terraform Registry の場合

公開/プライベート Registry で公開している module は version 制約が使える:

module "vpc" {
  source  = "your-org/vpc/aws"
  version = "~> 1.4"     # 1.4.x だけ許容、1.5 以上は来ない
  # ...
}
制約意味
1.4.0固定
~> 1.41.4.x の最新(1.5 を含まず)
~> 1.4.01.4.0〜1.4.x(1.5 を含まず)
>= 1.4, < 2.01.4 以上、2.0 未満

破壊的変更の扱い

例: VPC module の variable cidr_blockcidr にリネーム → これは MAJOR 変更(v1 → v2)。

  1. 新ブランチで variable をリネーム、内部対応も全部
  2. README / CHANGELOG に migration ガイド を書く(v1 → v2 で何を直すか)
  3. tag v2.0.0 を打つ
  4. 利用側は段階的に v2 へ移行(一度に全プロジェクトを切り替えなくていい)

後方互換を保つテクニック

# 旧 var を残しつつ新 var を追加。優先順位を持たせる
variable "cidr_block" {
  type        = string
  default     = null
  description = "Deprecated: use cidr instead"
}

variable "cidr" {
  type    = string
  default = null
}

locals {
  effective_cidr = coalesce(var.cidr, var.cidr_block)
}

Release PR フロー

「main にマージしたら自動で next version の tag が打たれる」自動化。release-pleasesemantic-release が代表。

運用イメージ:

  1. main にコミットを積んでいく(Conventional Commits 形式で)
  2. release-please が 「次のリリース内容をまとめた PR」 を自動生成・更新
  3. その PR をマージすると、自動で tag + GitHub Release が打たれる
# .github/workflows/release.yml
name: Release
on:
  push:
    branches: [main]

permissions:
  contents: write
  pull-requests: write

jobs:
  release-please:
    runs-on: ubuntu-latest
    steps:
      - uses: googleapis/release-please-action@v4
        with:
          release-type: terraform-module