TerraformやOpenTofuを用いたインフラ管理において、Terragruntを活用することでコードの再利用性を高め、環境ごとの設定を効率的に管理できます。本記事では、Terragruntを使用してAWSのECR(Elastic Container Registry)モジュールを管理する実装例を紹介し、各設定ファイルの内容を丁寧に解説します。
ディレクトリ構造
まず、以下のディレクトリ構造を用いてプロジェクトを構築します。
.
├── environments/
│ ├── dev/
│ │ ├── ecr/
│ │ │ └── terragrunt.hcl
│ │ ├── ecs/
│ │ │ └── terragrunt.hcl
│ │ ├── terragrunt.hcl
│ │ └── env_vars.yaml
│ ├── stg/
│ │ ├── ecr/
│ │ │ └── terragrunt.hcl
│ │ ├── ecs/
│ │ │ └── terragrunt.hcl
│ │ ├── terragrunt.hcl
│ │ └── env_vars.yaml
│ ├── prd/
│ │ ├── ecr/
│ │ │ └── terragrunt.hcl
│ │ ├── ecs/
│ │ │ └── terragrunt.hcl
│ │ ├── terragrunt.hcl
│ │ └── env_vars.yaml
│ ├── common_vars.yaml
│ └── terragrunt.hcl
└── modules/
├── ecr/
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
└── ecs/
├── main.tf
├── outputs.tf
└── variables.tf
ディレクトリ説明
- environments/: 各環境(dev, stg, prd)ごとの設定を格納。
- dev/, stg/, prd/: 開発、ステージング、本番環境のディレクトリ。
- ecr/: ECR関連のTerragrunt設定ファイル。
- ecs/: ECS関連のTerragrunt設定ファイル(今回は詳細を省略)。
- terragrunt.hcl: 環境全体の親設定ファイル。
- env_vars.yaml: 環境固有の変数定義。
- dev/, stg/, prd/: 開発、ステージング、本番環境のディレクトリ。
- common_vars.yaml: すべての環境で共通の変数定義。
- modules/: 再利用可能なTerraform/OpenTofuモジュールを格納。
- ecr/: ECRリポジトリを管理するモジュール。
- ecs/: ECSクラスターを管理するモジュール(詳細は省略)。
実装例:開発環境(dev)のECR設定
ここでは、**environments/dev/**ディレクトリ内の設定ファイルを中心に解説します。
1. 共通変数の定義 (environments/common_vars.yaml
)
region: ap-northeast-1
name: fumis-infra
解説:
- region: AWSリージョンを指定(ここでは東京リージョン)。
- name: インフラ全体の名前(ここでは
fumis-infra
)。
これらの変数は、すべての環境で共通して使用されます。
2. 環境固有変数の定義 (environments/dev/env_vars.yaml
)
env: dev
解説:
- env: 現在の環境を指定(ここでは開発環境
dev
)。
3. 環境全体のTerragrunt設定 (environments/dev/terragrunt.hcl
)
# environments/dev/terragrunt.hcl
remote_state {
backend = "s3"
generate = {
path = "_backend.tf"
if_exists = "overwrite_terragrunt"
}
config = {
bucket = "terragrunt-${local.env}-${local.name}-terraform-tfstate-s3-bucket"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "${local.region}"
encrypt = true
bucket_sse_algorithm = "AES256"
s3_bucket_tags = {
"Environment" = "${local.env}"
"ServiceName" = "${local.name}"
"CreatedByTerragrunt" = "true"
}
}
}
generate "provider" {
path = "_provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
region = "${local.region}"
default_tags {
tags = {
Environment = "${local.env}"
ServiceName = "${local.name}"
ManagedByTerraform = true
}
}
}
EOF
}
generate "version" {
path = "_terraform.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
terraform {
required_version = "~> 1.9.0"
required_providers {
aws = {
version = "~> 5.59.0"
source = "hashicorp/aws"
}
}
}
EOF
}
locals {
env_vars = yamldecode(file(find_in_parent_folders("env_vars.yaml")))
common_vars = yamldecode(file(find_in_parent_folders("common_vars.yaml")))
env = local.env_vars.env
region = local.common_vars.region
name = local.common_vars.name
}
解説:
- locals ブロック:
- env_vars: 環境固有の変数を
env_vars.yaml
から読み込む。 - common_vars: 共通変数を
common_vars.yaml
から読み込む。 - env: 環境名(
dev
)。 - region: AWSリージョン(
ap-northeast-1
)。 - name: インフラの名前(
fumis-infra
)。
- env_vars: 環境固有の変数を
- remote_state ブロック:
- backend: S3をバックエンドに指定。
- generate:
backend.tf
を自動生成。 - config:
- bucket: S3バケット名。
terragrunt-dev-fumis-infra-terraform-tfstate-s3-bucket
のように環境と名前を組み合わせ。 - key: 各モジュールの状態ファイルのキー。
- region: AWSリージョン。
- encrypt: S3バケットの暗号化を有効化。
- bucket_sse_algorithm: 暗号化アルゴリズムを指定。
- s3_bucket_tags: S3バケットにタグを付与。
- bucket: S3バケット名。
- generate "provider" ブロック:
- path:
provider.tf
を自動生成。 - contents: AWSプロバイダーの設定を記述。
- region: AWSリージョン。
- default_tags: 全リソースに共通のタグを付与。
- path:
- generate "version" ブロック:
- path:
terraform.tf
を自動生成。 - contents: Terraformのバージョンとプロバイダーの設定。
- required_version: Terraformのバージョン指定。
- required_providers: AWSプロバイダーのバージョンとソース指定。
- path:
4. ECRモジュールのTerragrunt設定 (environments/dev/ecr/terragrunt.hcl
)
# environments/dev/ecr/terragrunt.hcl
include "root" {
path = find_in_parent_folders()
}
terraform {
source = "../../modules/ecr"
}
inputs = {
env = local.env
name = local.name
}
locals {
env_vars = yamldecode(file(find_in_parent_folders("env_vars.yaml")))
common_vars = yamldecode(file(find_in_parent_folders("common_vars.yaml")))
env = local.env_vars.env
name = local.common_vars.name
}
解説:
- include ブロック:
- 親設定ファイル(
environments/dev/terragrunt.hcl
)を継承。
- 親設定ファイル(
- terraform ブロック:
- source: ECRモジュールのパスを指定(ここでは相対パス
../../modules/ecr
)。
- source: ECRモジュールのパスを指定(ここでは相対パス
- inputs ブロック:
- モジュールに渡す入力パラメータを指定。
- env: 環境名(
dev
)。 - name: インフラの名前(
fumis-infra
)。
- env: 環境名(
- モジュールに渡す入力パラメータを指定。
- locals ブロック:
- 親ファイルと同様に、環境固有と共通の変数を読み込み、ローカル変数として定義。
5. ECRモジュールのTerraform設定 (modules/ecr/main.tf
)
# modules/ecr/main.tf
resource "aws_ecr_repository" "this" {
name = "${var.name}-ecr-${var.env}"
image_tag_mutability = "MUTABLE"
tags = {
Environment = var.env
Service = var.name
}
}
解説:
- aws_ecr_repository リソース:
- name: ECRリポジトリの名前を
fumis-infra-ecr-dev
のように設定。 - image_tag_mutability: タグの不変性を設定(ここでは変更可能)。
- tags: リポジトリにタグを付与(環境名とサービス名)。
- name: ECRリポジトリの名前を
6. ECRモジュールの変数定義 (modules/ecr/variables.tf
)
# modules/ecr/variables.tf
variable "env" {
description = "The environment name (e.g., dev, stg, prd)"
type = string
}
variable "name" {
description = "The name of the service or infrastructure"
type = string
}
解説:
- env: 環境名を受け取る変数。
- name: サービス名やインフラの名前を受け取る変数。
7. ECRモジュールの出力定義 (modules/ecr/outputs.tf
)
# modules/ecr/outputs.tf
output "repository_url" {
description = "The URL of the ECR repository"
value = aws_ecr_repository.this.repository_url
}
解説:
- repository_url: 作成したECRリポジトリのURLを出力。
実装の流れ
以下のステップでTerragruntを使用してECRリポジトリをデプロイします。
ステップ1: 環境設定の確認
開発環境の変数定義を確認します。
- common_vars.yaml
region: ap-northeast-1 name: fumis-infra
- env_vars.yaml
env: dev
ステップ2: Terragruntの設定ファイルを確認
- environments/dev/terragrunt.hcl
- リモート状態の設定をS3に一元化。
- AWSプロバイダーの設定を共通化。
- Terraformのバージョンとプロバイダーのバージョンを指定。
- environments/dev/ecr/terragrunt.hcl
- 親設定を継承。
- ECRモジュールのソースを指定。
- モジュールに環境名とインフラ名を入力パラメータとして渡す。
ステップ3: Terraformモジュールの準備
- modules/ecr/main.tf
- AWS ECRリポジトリを作成。
- 環境名とインフラ名を組み合わせてリポジトリ名を生成。
- タグを付与。
- modules/ecr/variables.tf
- 環境名とインフラ名を受け取る変数を定義。
- modules/ecr/outputs.tf
- 作成したリポジトリのURLを出力。
ステップ4: Terragruntコマンドの実行
開発環境のECRリポジトリをデプロイするために、以下のコマンドを実行します。
cd environments/dev/ecr
terragrunt init
terragrunt apply
解説:
- terragrunt init:
- Terragruntが指定されたリモート状態の設定を読み込み、必要な初期化を実行します。
- S3バケットが存在しない場合、自動的に作成されます。
- terragrunt apply:
- Terraform/OpenTofuがECRリポジトリを作成します。
terraform.tfstate
がS3に保存され、DynamoDBテーブルで状態のロックが管理されます。
ステップ5: 出力結果の確認
コマンド実行後、以下のような出力が得られます。
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
repository_url = "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/fumis-infra-ecr-dev"
解説:
- repository_url: 作成されたECRリポジトリのURLが出力されます。
CI/CDパイプラインとの統合
この設定をAWS CodePipelineなどのCI/CDツールに統合することで、コードの変更に応じて自動的にインフラをデプロイできます。以下は、簡単な統合手順の概要です。
ステップ1: CodePipelineの設定
- ソースステージ:
- GitHubやCodeCommitなど、コードリポジトリをソースとして設定。
- ビルドステージ:
- CodeBuildを使用して、Terragruntコマンドを実行。
environments/dev/ecr/terragrunt.hcl
ディレクトリに移動し、terragrunt apply
を実行。
ステップ2: CodeBuildのビルド仕様 (buildspec.yml
)
version: 0.2
phases:
install:
runtime-versions:
python: 3.8
commands:
- curl -LO <https://github.com/gruntwork-io/terragrunt/releases/download/v0.45.0/terragrunt_linux_amd64>
- chmod +x terragrunt_linux_amd64
- mv terragrunt_linux_amd64 /usr/local/bin/terragrunt
pre_build:
commands:
- terragrunt --version
build:
commands:
- cd environments/dev/ecr
- terragrunt init
- terragrunt apply -auto-approve
解説:
- install フェーズ:
- Terragruntのバイナリをダウンロードし、実行可能に設定。
- pre_build フェーズ:
- Terragruntのバージョンを確認。
- build フェーズ:
- ECRモジュールのディレクトリに移動し、Terragruntコマンドを実行。
ステップ3: CodePipelineの実行
CodePipelineがトリガーされると、CodeBuildが自動的にTerragruntを実行し、ECRリポジトリをデプロイします。成功すれば、CI/CDパイプラインが完了します。
まとめ
本記事では、Terragruntを使用してAWSのECRリポジトリを管理する実装例を紹介しました。Terragruntを活用することで、以下のメリットが得られます。
- コードの再利用性向上: モジュール化により、共通コードを一元管理。
- 設定の一貫性確保: リモート状態の一元管理と自動生成による設定の統一。
- 効率的な環境管理: 複数環境(dev, stg, prd)での設定の簡素化。
- CI/CDとの統合: 自動デプロイによるインフラ管理の自動化と信頼性向上。
Terragruntを活用することで、インフラ管理がより効率的かつ安全になります。ぜひ本実装例を参考に、あなたのプロジェクトにもTerragruntを導入してみてください。