📝

Terragrunt を使ってみよう

2025/01/27に公開

初めての技術ブログの投稿を行うため温かい目で見てくれたらありがたいです。
Terraformは知っているけどTerragruntってなんぞやって思う方もいると思います。備忘録の為まとめてみました!

Terraformとは

そもそもTerraformって何?って思われる方もいると思います。
AWSなどでクラウド環境を構築する際には、手動でコンソールから構築する際にめんどくさいや効率をもっと良くしたいリソースを復活させたたいなど思う時があります。
それをコード化して、リソースを簡単に構築できるようにしたのがTerraformになります。
主に導入する事で以下の効率化のメリットがあります。

  • リソースをコードで管理
    • リソースの削除、更新、追加の差分をコードでのバージョン管理ができる
  • インフラの構成を管理
    • リソースのスペックをコードから一目で確認出来る
  • 自動化でのオペレーションコストの削減
    • 手動でリソース構築を行なっていた作業をコマンドでできるので作業ミスを減らせる

機能性の前に、Terraagruntについて記載します。

Terragruntとは

Terragruntは Gruntwork.io が出しているOSSであり、Terraformの設定を簡素化し、効率的に管理するためのツールです。

特に、複数の環境や大規模なインフラを扱う場合に、コードの再利用性、依存関係管理、DRY原則の実現、State管理の簡素化、マルチ環境での適用効率の向上、柔軟なオーバーライドといった点でTerraformよりも優れています。

Terragruntの機能性とは

  1. コードの再利用性向上

    • Terraformはモジュールを活用してコードの再利用を可能にしますが、大規模プロジェクトになると、モジュール間の依存関係や共通設定を管理するのが複雑になります。
    • Terragruntはこれを簡素化するために以下の機能を提供します。
      • terragrunt.hcl ファイルを用いて、共通設定(バックエンド、プロバイダー設定など)を一元管理。
      • 複数の環境(開発、ステージング、本番)に同じモジュールを簡単に適用可能。
  2. 依存関係の管理

    • Terraformではモジュール間の依存関係を手動で指定する必要がありますが、Terragruntは以下を自動化します.
      • dependencies ブロックで依存関係を明示的に定義可能。
      • 実行順序を自動的に管理(例:ネットワークを作成してからEC2インスタンスをデプロイ)。
  3. DRY原則(Don’t Repeat Yourself)の実現

    • Terraformで複数環境を管理する場合、設定ファイルの重複が発生しやすいですが、Terragruntでは以下により重複を減らします.
      • 共通設定を親ディレクトリで定義し、子ディレクトリで継承。
      • 環境ごとに必要な値だけをオーバーライドする仕組み(inputs)。
  4. State管理の簡素化

    • Terraformでは各環境のStateファイルを手動で管理する必要がありますが、Terragruntでは自動作成が可能になります。
      • Stateファイルのリモートバックエンド設定を簡略化。
      • 環境ごとに自動的に適切なStateファイルを作成・管理。
  5. マルチ環境での適用効率

    • Terraformで複数の環境を管理する場合、各環境で個別にコマンドを実行する必要があります。Terragruntでは以下が可能です。
    • run-allコマンドを使い、複数環境やモジュールを一括で実行。
    • 並列処理によるデプロイ時間の短縮。
  6. 柔軟なオーバーライド

    • Terragruntでは、環境や条件に応じて動的に変数を設定できます(例:terraform { extra_arguments }を使った柔軟なフラグ追加)。

Terragruntを使う場面

  • Terragruntが特に有効な場面

    • 環境ごとに似たような構成(開発、本番など)を持つ場合。
    • 複数チームでTerraformコードを管理し、設定の一貫性を保つ必要がある場合。
    • 依存関係が複雑なインフラを管理する場合。
  • 以下のような各環境毎に設定を分けることによって、環境毎のリソースの設定状況も一目でわかります。

.
├── resources // 各環境毎の共通設定ファイル
│   ├── dev
│   │   ├── iam
│   │   │    └── main.yaml 
│   │   ├── elb
│   │   │    └── main.yaml 
│   │   └── ec2
│   │        └──  main.yaml
│   ├── stg
│   │   ├── iam
│   │   │    └── main.yaml
│   │   ├── elb
│   │   │    └── main.yaml 
│   │   └── ec2
│   │        └── main.yaml
│   └── prd
│       ├── iam
│       │    └── main.yaml
│       ├── elb
│       │    └── main.yaml
│       └── ec2
│            └── main.yaml
│
├── envs // 環境毎のリソースの実行ファイル
│   ├── terragrunt.hcl # 親
│   ├── provider.tf
│   ├── version.tf
│   ├── dev
│   │   ├── iam
│   │   │    └── terragrunt.hcl # 子
│   │   ├── elb
│   │   │    └── terragrunt.hcl # 子
│   │   └── ec2
│   │        └── terragrunt.hcl # 子
│   ├── stg
│   │   ├── iam
│   │   │    └── terragrunt.hcl # 子
│   │   ├── elb
│   │   │    └── terragrunt.hcl # 子
│   │   └── ec2
│   │        └── terragrunt.hcl # 子
│   └── prd
│       ├── iam
│       │    └── terragrunt.hcl # 子
│       ├── elb
│       │    └── terragrunt.hcl # 子
│       └── ec2
│            └── terragrunt.hcl # 子
│
└── modules // 各環境毎のモジュールの設定ファイル
        ├── iam
        │   ├── main.tf
        │   ├── variables.tf
        │   └── output.tf
        ├── elb
        │   ├── main.tf
        │   ├── variables.tf
        │   └── output.tf
        └── ec2
            ├── main.tf
            ├── variables.tf
            └── output.tf

Terragruntの使い方

親のtclファイルの設定

以下のように親のtclの設定を行います。

./envs/terragrunt.hcl
remote_state {
  backend = "s3"
  config = {
    bucket         = "my-terraform-state"
    encrypt        = true
    region         = "ap-northeast-1"
    key            = "${path_relative_to_include()}/terraform.tfstate"
  }
}

inputs = {
  region = "ap-northeast-1"
}

path_relative_to_include() は、サブディレクトリのパスを動的に生成し、各環境のステートファイルを別々に保持します。これにより、各フォルダで定義しなければならなかったリモートステートを一箇所で定義することができます。

サブディレクトリの設定

以下の様にサブディレクトリの設定を行います。

./envs/{dev | stg | prd}/{リソースフォルダ}/terragrunt.hcl
include {
  path = find_in_parent_folders()
}

terraform {
  source = "../../../modules/各リソースフォルダ指定"
}

inputs = {
  name = "my-app-{dev | stg | prd}"
}

TerraformとTerragruntを比較する

実際のコードでterraformとTerragruntを比較する

Terraformで書いた場合

./env/{dev | stg | prd}/main.tf

module "app" {
  source = "../../modules/{リソースフォルダ}"

  name    = "{dev | stg | prd}-app"
  region  = "ap-northeast-1"
}


terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "{dev | stg | prd}/{リソースフォルダ}/terraform.tfstate"
    region = "ap-northeast-1"
  }
}

Terragruntで書いた場合

ルートレベルのterragrunt.hclにregionとリモートステートを記述しておけるため、リソースフォルダのモジュールの記述は以下のように簡潔に済ませることができます。

include {
  path = find_in_parent_folders()
}

terraform {
  source = "../../modules/{リソースフォルダ}"
}

inputs = {
  name    = "{dev | stg | prd}--app"
}

yamlファイルについて

yamlファイルには、各モジュールの固定値を記載することで、更に見やすくなります。
例えばiamだと

iam
 - arn: 〇〇

上記で設定し、terragruntで呼び出して使用する様にするとyamlファイルの固定値のみ変更でよくなる為保守性も高くなります。

Terragruntのコマンドについて

環境に適応するには、以下のコマンドを使います。
以下のコマンドは、./envs/{dev | stg | prd}/{リソースフォルダ}/terragrunt.hcl で実行しなければエラーになります。

実行コード 実行後の動き 詳細
terragrunt init terragrunt環境の初期化 現在まで実行した terragruntの追跡状況をリセットする
terragrunt plan 構築するリソースの状況を返す 実行した時に、コードで書いたリソースの設定値を確認できる
terragrunt apply 構築するリソースを環境に適応させる 適適応させる環境に適応したリソースの成功有無を確認できる

さいごに

この記事では、terragrunについて備忘録を記載しました。調べた内容とかもあるので全て合っているかは謎ですが、実際に使うと便利なことを実感できます。

Discussion