概要
TerraformやOpenTofuを使用したインフラ管理では、環境ごとに似たようなコードが散在し、メンテナンスが困難になることが多々あります。本記事では、Terragruntを活用してコードの重複を減らし、管理の効率化とImmutable Infrastructureの実現方法を初学者向けに丁寧に解説します。具体的な設定例を交え、複数環境(dev, stg, prd)やCI/CDパイプライン(CodePipeline)での利用ケースを紹介します。
この記事で伝えたいこと
- Terragruntの基本概念と利点
- コードの重複削減と不変性の確保方法
- リモート状態の管理と自動化
- 共通設定のDRY化とモジュール固有設定の共通化
- CI/CDパイプラインにおけるTerragruntの活用方法
- 具体的な設定例とベストプラクティス
解決したい課題
- 環境ごとのインフラコードの重複とメンテナンスの煩雑化
- リモート状態管理の非効率性と一貫性の欠如
- 複数環境やAWSアカウント間での設定の一元管理の難しさ
- CI/CDパイプラインでのインフラデプロイの自動化と安定化
課題の原因
TerraformやOpenTofuを直接使用すると、環境ごとにほぼ同一のコードが繰り返されるため、コードの重複が発生しやすくなります。また、リモート状態の管理が手動になりがちで、一貫性を保つのが難しいです。さらに、複数のAWSアカウントや環境間での設定の一元管理が困難で、CI/CDパイプラインでの自動化も煩雑になります。
課題を解決する技術、手法
Terragruntの概要
Terragruntは、TerraformやOpenTofuの設定を簡素化し、再利用性と一貫性を高めるためのラッパーツールです。主に以下の機能を提供します:
- モジュールの分離:共通コードをモジュールリポジトリに分離し、環境固有の設定をライブリポジトリで管理。
- リモート状態の自動管理:リモート状態の設定を共通化し、S3やDynamoDBなどのリソースを自動で作成・管理。
- 設定のDRY化:
include
やread_terragrunt_config
を活用し、設定の重複を削減。 - CI/CD統合:Terragruntの
run-all
コマンドを使用して、複数モジュールの一括操作を実現。
技術、手法の効果
- コードの重複削減:共通部分をモジュール化することで、コードの再利用性が向上し、メンテナンスが容易になります。
- 不変性の確保:モジュールのバージョン管理を統一することで、一貫した環境を維持できます。
- リモート状態管理の効率化:リモート状態の設定を一元管理することで、状態の一貫性と安全性が向上します。
- CI/CDの安定化と自動化:複数環境やモジュールの一括操作が可能となり、デプロイの信頼性が向上します。
課題がどう解決されるか
Terragruntを活用することで、環境ごとのコードの重複を排除し、共通部分をモジュール化することでメンテナンス性が向上します。リモート状態の設定を一元化することで、状態管理の一貫性と安全性が確保されます。また、CI/CDパイプラインとの統合により、インフラのデプロイプロセスが自動化され、デプロイの信頼性と効率が向上します。
応用事例のカタログ化
- 複数環境(dev, stg, prd)のインフラ管理
- CodePipelineを使用したCI/CDパイプラインでの自動デプロイ
- 複数AWSアカウント間でのセキュアなインフラ管理
- 共通設定の一元管理とモジュール固有設定の共通化
Terragruntの主要機能と設定方法
以下では、Terragruntの重要な機能について詳しく解説し、具体的な設定例を交えて説明します。
1. モジュールの分離
背景と技術的課題
インフラコードが環境ごとに分散すると、コードの重複が発生し、メンテナンスが困難になります。また、バージョンの不整合が生じるリスクも高まります。
利用ケース
複数の環境(dev, stg, prd)で共通のインフラ構成を持ちつつ、環境ごとに異なる設定を適用したい場合。
設定例
モジュールリポジトリ構成
└── modules
├── app
│ └── main.tf
├── mysql
│ └── main.tf
└── vpc
└── main.tf
ライブリポジトリ構成
└── live
├── prod
│ ├── app
│ │ └── terragrunt.hcl
│ ├── mysql
│ │ └── terragrunt.hcl
│ └── vpc
│ └── terragrunt.hcl
├── qa
│ ├── app
│ │ └── terragrunt.hcl
│ ├── mysql
│ │ └── terragrunt.hcl
│ └── vpc
│ └── terragrunt.hcl
└── stage
├── app
│ └── terragrunt.hcl
├── mysql
│ └── terragrunt.hcl
└── vpc
└── terragrunt.hcl
terragrunt.hcl
の例
terraform {
source = "<git::git@github.com>:foo/modules.git//app?ref=v1.0.0"
}
inputs = {
instance_count = 3
instance_type = "t2.micro"
}
2. コードの重複削減と不変性
背景と技術的課題
コードの重複はメンテナンスの手間を増やし、バグの発生リスクを高めます。また、環境間で設定が異なると、不整合が生じる可能性があります。
利用ケース
共通のインフラコードを一元管理し、環境ごとに必要な設定のみを変更したい場合。
設定例
モジュールリポジトリ
└── modules
├── app
│ └── main.tf
├── mysql
│ └── main.tf
└── vpc
└── main.tf
ライブリポジトリの設定
live/prod/app/terragrunt.hcl
include "root" {
path = find_in_parent_folders()
}
terraform {
source = "<git::git@github.com>:foo/modules.git//app?ref=v1.0.0"
}
inputs = {
instance_count = 3
instance_type = "t2.micro"
}
live/qa/app/terragrunt.hcl
include "root" {
path = find_in_parent_folders()
}
terraform {
source = "<git::git@github.com>:foo/modules.git//app?ref=v1.0.0"
}
inputs = {
instance_count = 2
instance_type = "t2.small"
}
3. 生成ブロックでの共通コード注入
背景と技術的課題
共通の設定を各モジュールに手動で追加するのは手間がかかり、ミスが発生しやすいです。
利用ケース
全環境で共通のAWS IAMロールを使用する場合など。
設定例
terragrunt.hcl
の例
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
assume_role {
role_arn = "arn:aws:iam::0123456789:role/terragrunt"
}
}
EOF
}
include "root" {
path = find_in_parent_folders()
}
4. Terragruntでリモート状態設定を入力する
背景と技術的課題
Terraformのバックエンド設定は環境ごとに変数や式を使用できず、コードの重複が発生しやすいです。
利用ケース
S3バケットとDynamoDBテーブルを使用してリモート状態を管理する場合。
設定例
ルートファイルの設定 (live/terragrunt.hcl
)
generate "backend" {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "my-lock-table"
}
}
EOF
}
子ファイルの継承 (live/prod/app/terragrunt.hcl
)
include "root" {
path = find_in_parent_folders()
}
terraform {
source = "<git::git@github.com>:foo/modules.git//app?ref=v1.0.0"
}
inputs = {
instance_count = 3
instance_type = "t2.micro"
}
5. リモート状態とロックリソースを自動的に作成する
背景と技術的課題
リモート状態の管理に必要なS3バケットやDynamoDBテーブルを手動で作成するのは手間がかかります。
利用ケース
Terragruntのremote_state
ブロックを使用して、必要なリソースを自動的に作成したい場合。
設定例
remote_state {
backend = "s3"
generate = {
path = "backend.tf"
if_exists = "overwrite"
}
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "my-lock-table"
}
}
6. S3固有のリモート状態設定
背景と技術的課題
S3バックエンドの設定において、特定の要件(例:バージョニング不要、アクセスログの有効化)に対応した設定が必要です。
利用ケース
バージョニングをスキップし、アクセスログを有効にする場合。
設定例
remote_state {
config = {
skip_bucket_versioning = true
skip_bucket_encryption = true
skip_bucket_root_access = true
accesslogging_bucket_name = "my-logs"
}
}
7. 共通設定の管理: include
を使用して設定をDRY化
背景と技術的課題
各モジュールで同じ設定を繰り返し記述するのは非効率です。
利用ケース
複数のモジュールで共通のリモート状態やプロバイダー設定を使用する場合。
設定例
ルートファイル (live/terragrunt.hcl
)
remote_state {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "my-lock-table"
}
}
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
assume_role {
role_arn = "arn:aws:iam::0123456789:role/terragrunt"
}
}
EOF
}
子ファイルの継承 (live/prod/app/terragrunt.hcl
)
include "root" {
path = find_in_parent_folders()
}
terraform {
source = "<git::git@github.com>:foo/modules.git//app?ref=v1.0.0"
}
inputs = {
env = "prod"
}
8. モジュール固有の設定を共通化: _env
ディレクトリの活用
背景と技術的課題
環境ごとに異なるモジュール設定を一元管理する方法が必要です。
利用ケース
複数の環境で異なる設定を適用しつつ、共通部分を保持する場合。
設定例
ディレクトリ構成
└── live
├── terragrunt.hcl
├── _env
│ ├── app.hcl
│ ├── mysql.hcl
│ └── vpc.hcl
├── prod
│ ├── app
│ │ └── terragrunt.hcl
├── qa
│ ├── app
│ │ └── terragrunt.hcl
└── stage
├── app
│ └── terragrunt.hcl
_env/app.hcl
の内容
terraform {
source = "github.com/<org>/modules.git//app?ref=v0.1.0"
}
inputs = {
basename = "example-app"
}
子ファイルの継承 (live/prod/app/terragrunt.hcl
)
include "root" {
path = find_in_parent_folders()
}
include "env" {
path = "${get_terragrunt_dir()}/../../_env/app.hcl"
}
inputs = {
env = "prod"
}
9. 動的構成の管理: read_terragrunt_config
の活用
背景と技術的課題
動的に変化する環境設定を効率的に管理する方法が必要です。
利用ケース
環境ごとに異なる設定ファイルを動的に読み込み、適用する場合。
設定例
環境設定ファイル (live/prod/env.hcl
)
locals {
env = "prod"
}
親ファイルでの読み込み
locals {
env_vars = read_terragrunt_config(find_in_parent_folders("env.hcl"))
env_name = local.env_vars.locals.env
}
inputs = {
env = local.env_name
}
10. CI/CDパイプラインにおけるTerragruntの考慮事項
背景と技術的課題
CI/CDパイプラインで複数モジュールや環境を効率的にデプロイする方法が必要です。
利用ケース
CodePipelineを使用して、複数のTerragruntモジュールを順次デプロイする場合。
設定例
パイプライン内でのTerragrunt実行
terragrunt run-all plan --terragrunt-modules-that-include _env/app.hcl
terragrunt run-all apply --terragrunt-working-dir qa
terragrunt run-all plan --terragrunt-working-dir stage
terragrunt run-all apply --terragrunt-working-dir stage
11. TerragruntのScaffold機能でHCLファイルを自動生成する方法
背景と技術的課題
手動でHCLファイルを作成する手間とミスを削減する方法が必要です。
利用ケース
新しいモジュールの設定ファイルを迅速に生成したい場合。
設定例
Scaffoldコマンドの使用
terragrunt scaffold github.com/gruntwork-io/terragrunt-infrastructure-modules-example//modules/mysql
生成されるterragrunt.hcl
の例
# This is a Terragrunt module generated by boilerplate.
terraform {
source = "git::<https://github.com/gruntwork-io/terragrunt-infrastructure-modules-example.git//modules/mysql?ref=v0.8.1>"
}
inputs = {
# Required input variables
aws_region = "" # TODO: fill in value
name = "" # TODO: fill in value
instance_class = "" # TODO: fill in value
}
12. TerragruntでCLIフラグをDRYに保つ方法
背景と技術的課題
同じCLIフラグを複数のコマンドで繰り返し設定するのは非効率です。
利用ケース
リモートロックのタイムアウトやカスタム変数を共通で設定したい場合。
設定例
terragrunt.hcl
の設定
terraform {
extra_arguments "retry_lock" {
commands = [
"init",
"apply",
"refresh",
"import",
"plan",
"taint",
"untaint"
]
arguments = [
"-lock-timeout=20m"
]
}
extra_arguments "custom_vars" {
commands = [
"apply",
"plan",
"import",
"push",
"refresh"
]
arguments = [
"-var", "foo=bar",
"-var", "region=us-west-1"
]
}
}
13. Terragruntで複数のTerraformユニットを一括操作する方法
背景と技術的課題
複数のTerraformユニットを個別に管理するのは時間と手間がかかります。
利用ケース
複数のモジュールを一括でデプロイや削除したい場合。
設定例
run-all
コマンドの使用
terragrunt run-all apply
terragrunt run-all destroy
terragrunt run-all plan
terragrunt run-all output
依存関係の管理
# mysql/terragrunt.hcl
dependency "vpc" {
config_path = "../vpc"
}
inputs = {
vpc_id = dependency.vpc.outputs.vpc_id
}
14. Terragruntを使用して複数のAWSアカウントを効率的に管理する
背景と技術的課題
セキュリティ向上のために複数のAWSアカウントを管理する際、アクセスやロールの設定が煩雑になります。
利用ケース
security
アカウントから他のアカウントのIAMロールを引き受けてインフラを管理する場合。
設定例
terragrunt.hcl
でのIAMロール設定
iam_role = "arn:aws:iam::123456789012:role/ProdRole"
コマンドライン引数を使用
terragrunt apply --terragrunt-iam-role "arn:aws:iam::123456789012:role/ProdRole"
環境変数を使用
export TERRAGRUNT_IAM_ROLE="arn:aws:iam::123456789012:role/ProdRole"
terragrunt apply
15. Terragruntでモジュールの入力パラメータを設定する方法
背景と技術的課題
Terraformモジュールには多数の入力パラメータが存在し、これを効率的に管理する方法が必要です。
利用ケース
モジュールごとに異なる入力パラメータを設定し、環境ごとにカスタマイズしたい場合。
設定例
terragrunt.hcl
の設定
inputs = {
instance_type = "t2.micro"
instance_count = 5
environment = "dev"
}
16. Terragruntでローカル変数(locals)を活用する方法
背景と技術的課題
同じ値や計算式を複数回記述するのは非効率です。
利用ケース
共通のリージョンやタグを複数のモジュールで再利用したい場合。
設定例
terragrunt.hcl
でのローカル変数の定義
locals {
aws_region = "us-east-1"
}
inputs = {
aws_region = local.aws_region
s3_endpoint = "com.amazonaws.${local.aws_region}.s3"
}
17. TerragruntのAuto-Init機能: 初期化を自動化して効率化する
背景と技術的課題
terraform init
を毎回手動で実行するのは手間がかかります。
利用ケース
Terragruntコマンドを実行する際に、自動的に初期化を行いたい場合。
設定例
通常のterragrunt.hcl
を使用するだけで、自動的にterraform init
が実行されます。
terraform {
source = "git::<https://github.com/example/repo.git//module?ref=v1.0.0>"
}
inputs = {
example_variable = "value"
}
18. TerragruntのAWS認証とIAMポリシー設定ガイド
背景と技術的課題
AWSリソースを安全かつ効率的に管理するためには、適切な認証と権限設定が必要です。
利用ケース
S3バケットとDynamoDBテーブルを使用したリモート状態管理に必要なIAMポリシーを設定する場合。
設定例
IAMポリシー例
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAllDynamoDBActionsOnAllTerragruntTables",
"Effect": "Allow",
"Action": "dynamodb:*",
"Resource": [
"arn:aws:dynamodb:*:1234567890:table/terragrunt*"
]
},
{
"Sid": "AllowAllS3ActionsOnTerragruntBuckets",
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::terragrunt*",
"arn:aws:s3:::terragrunt*/*"
]
}
]
}
19. Terragruntでのロックファイル管理
背景と技術的課題
ロックファイル(.terraform.lock.hcl
)を使用することで、プロバイダーのバージョンを固定し、一貫性を保つことができます。しかし、Terragruntを使用すると一時ディレクトリにロックファイルが生成されるため、管理が難しくなります。
利用ケース
ロックファイルをバージョン管理に含め、チーム全体で同じプロバイダーを使用したい場合。
設定例
ロックファイルのコピー
Terragruntは、terraform
ブロックで以下の設定を行うことで、ロックファイルのコピーを自動化します。
terraform {
source = "<git::git@github.com>:acme/infrastructure-modules.git//networking/vpc?ref=v0.0.1"
copy_terraform_lock_file = true
}
ロックファイルの確認とコミット
Terragruntを各モジュールで実行後、ロックファイルをバージョン管理に追加します。
git add .terraform.lock.hcl
git commit -m "Add Terraform lock file"
まとめ
Terragruntを活用することで、TerraformやOpenTofuのインフラ管理が大幅に効率化されます。コードの重複を減らし、一貫性を保ちながら、複数環境やAWSアカウントを効率的に管理できます。また、CI/CDパイプラインとの統合により、インフラデプロイの自動化と安定化を実現します。初学者でも理解しやすいよう、具体的な設定例を交えながら解説しました。ぜひTerragruntを導入し、効率的なインフラ管理を目指しましょう。
留意点とデメリット
- 学習コスト:Terragruntの概念や設定方法を理解するための初期学習が必要です。
- ツール依存:Terragruntに依存することで、将来的にツールの変更が難しくなる可能性があります。
- 設定の複雑化:高度な設定を行うと、設定ファイルが複雑になりやすいです。
これらの点を考慮しつつ、Terragruntの利点を最大限に活用して効率的なインフラ管理を実現してください。
参考資料
まとめ
Terragruntは、TerraformやOpenTofuを使用したインフラ管理を効率化し、コードの重複を減らし、一貫性を保つための強力なツールです。本記事では、Terragruntの主要な機能とその設定方法について詳しく解説しました。初学者でも理解しやすいよう、具体的な設定例を交えながら説明しましたので、ぜひ実践に活かしてみてください。