1. はじめに
はじめまして、サインSREのfujiyaです。現在はサイン全体のインフラを担当しており、基盤の構築や監視などをメインに働いています。今回はサインのインフラ管理で利用しているTerragruntというツールについて、紹介したいと思います。
対象読者
- Terragruntってなんだ?という人
- Terragruntについて聞いたことがあるが、詳細はわからない人
- Terraformの知識があり、Terragruntの基本的な利用方法を学びたい人
ゴール
- Terragruntの基礎を学ぶ:Terragruntの基本的な概念、主要機能と使用方法について理解する。
- インフラ管理の効率化を学ぶ:Terragruntを用いてインフラコードをDRYに書く方法を紹介。
2. Terragruntとは?
概要
Terragrunt は Gruntwork 社が公開している Terraform のラッパーツールです。Terraformが提供する機能を拡張し、重複を減らしたり、設定管理を簡素化したりすることで、DRYに保ち、インフラコードをより効率的に管理できるようになります。
また、TerragruntはTerraformの構文をそのまま利用できるため、Terraformに慣れている開発者にとっては、非常に使いやすいツールなのも特徴です。
インストール
インストールは公式サイトのインストールページを参考にインストールしましょう。
使い方
CLIでの使い方は簡単で、コマンドを terraform
のかわりに terragrunt
に置き換えるだけです。Terragrunt特有のコマンド以外は直接Terraformに転送するため、Terraformのコマンドをそのまま利用することができます。Terragrunt特有のコマンドについては後の章で説明します。
terraform plan ↓ terragrunt plan
参考
3. プロジェクトのフォルダ構造と実装の基本
ここでは、Terragruntプロジェクトの基本について説明します。
基本のフォルダ構造
一般的なTerragruntプロジェクトのフォルダ構造は次のようになります。
my-terraform-project/ ├── terragrunt.hcl # ルートレベルの設定 ├── environments/ │ ├── production/ │ │ ├── app/ │ │ │ └── terragrunt.hcl # 本番環境のアプリ用設定ファイル │ │ ├── database/ │ │ │ └── terragrunt.hcl # 本番環境のデータベース用設定ファイル │ │ └── network/ │ │ └── terragrunt.hcl # 本番環境のネットワーク用設定ファイル │ └── staging/ │ ├── app/ │ │ └── terragrunt.hcl # ステージング環境のアプリ用設定ファイル │ ├── database/ │ │ └── terragrunt.hcl # ステージング環境のデータベース用設定ファイル │ └── network/ │ └── terragrunt.hcl # ステージング環境のネットワーク用設定ファイル └── modules/ ├── app/ ├── database/ └── network/
この構造では、modules
ディレクトリが実際のTerraformコードを含み、environments
ディレクトリが特定の環境(例:production
、staging
)に対するTerragruntの設定を持っています。
terragrunt.hcl
ファイル
terragrunt.hcl
ファイルは、TerragruntとTerraformの設定を定義します。基本的な設定では、以下の要素が含まれます。
- リモートステートの設定:Terraformのステートファイルを保存する場所(例:S3バケット)を定義
- 入力変数:Terraformモジュールに必要な入力変数を記述
- 依存関係:他のTerraformモジュールへの依存関係を定義
以下はterragrunt.hcl
ファイルの記述例です。
# terragrunt.hcl (例:production/app/terragrunt.hcl) terraform { source = "../../modules/app" # Terraformモジュールへのパス # リモートステート設定 backend "s3" { bucket = "my-terraform-state" key = "production/app/terraform.tfstate" region = "us-east-1" encrypt = true } } # 入力変数 inputs = { region = "us-east-1" name = "production-app" } # 依存関係 dependencies { paths = ["../database"] }
その他の設定項目については公式のConfigurationのページを参考にしてください。
4. 設定をDRYに保つ
Terragruntでは、共通の設定をルートレベルのterragrunt.hcl
ファイルに定義し、サブディレクトリのterragrunt.hcl
ファイルでこれらの設定を参照することで、設定をDRYに保つことができます。
先に紹介した、一般的なTerragruntプロジェクトのフォルダ構造を例に説明します。
my-terraform-project/ ├── terragrunt.hcl # ルートレベルの設定 ├── environments/ │ ├── production/ │ │ ├── app/ │ │ │ └── terragrunt.hcl # 本番環境のアプリ用設定ファイル │ │ ├── database/ │ │ │ └── terragrunt.hcl # 本番環境のデータベース用設定ファイル │ │ └── network/ │ │ └── terragrunt.hcl # 本番環境のネットワーク用設定ファイル │ └── staging/ │ ├── app/ │ │ └── terragrunt.hcl # ステージング環境のアプリ用設定ファイル │ ├── database/ │ │ └── terragrunt.hcl # ステージング環境のデータベース用設定ファイル │ └── network/ │ └── terragrunt.hcl # ステージング環境のネットワーク用設定ファイル └── modules/ ├── app/ ├── database/ └── network/
ルートレベルの terragrunt.hcl
このファイルでは、全ての環境で共通する設定を定義します。
以下では、共通の設定の例としてリージョンとリモートステートの設定を定義しています。
# my-terraform-project/terragrunt.hcl remote_state { backend = "s3" config = { bucket = "my-terraform-state" encrypt = true region = "us-east-1" key = "${path_relative_to_include()}/terraform.tfstate" } } inputs = { region = "us-east-1" }
path_relative_to_include()
は、サブディレクトリのパスを動的に生成し、各環境のステートファイルを別々に保持します。これにより、各フォルダで定義しなければならなかったリモートステートを一箇所で定義することができます。
サブディレクトリの terragrunt.hcl
サブディレクトリのterragrunt.hcl
ファイルでは、ルートのterragrunt.hcl
ファイルを参照し、その他の固有の設定を追加します。
# my-terraform-project/environments/production/app/terragrunt.hcl include { path = find_in_parent_folders() } terraform { source = "../../../modules/app" } inputs = { name = "my-app-production" }
この設定では、include
ブロックを使用してルートレベルのterragrunt.hcl
を含めています。これにより、リモートステートの設定が引き継がれます。また、terraform
ブロックでモジュールのソースを指定し、inputs
ブロックで固有の入力変数を設定します。
include
ブロック内で使用しているfind_in_parent_folders()
は Terragrunt のビルトイン関数で、現在のディレクトリから親ディレクトリを遡って、特定のファイルを探します。
find_in_parent_folders()
は以下のような特徴があります。
- 初めて見つかる
terragrunt.hcl
ファイルのパスをinclude
ブロックで使用 - 引数を渡すことで他のファイル名を指定することも可能
そのほかの設定をDRYに保つ
ここで紹介した設定項目以外に、プロバイダー構成を DRYに保つ なども存在します。公式ドキュメントを参考にしてみてください。
参考
- その他の設定項目 ⇒ Configuration - Terragrunt
- プロバイダー構成を DRYに保つ
5. TerraformとTerragruntを比較する
4 設定をDRYに保つで示したように、ルートレベルのterragrunt.hcl
に inputs
ブロックで共通の入力変数を設定することでDRYに保つことができます。ここでは、素のTerraformで書いた場合と比較しながらDRYに保つメリットを紹介します。
素のTerraformで書いた場合
以下はappモジュールの記述例です。このように共通の設定であるregion
やリモートステートは各種モジュールに記述が必要になってしまいます。
# my-terraform-project/environments/production/app/main.tf module "app" { source = "../../../modules/app" name = "production-app" region = "us-east-1" } # リモートステートの設定 terraform { backend "s3" { bucket = "my-terraform-state" key = "production/app/terraform.tfstate" region = "us-east-1" } }
Terragruntで書いた場合
ルートレベルのterragrunt.hcl
にregion
とリモートステートを記述しておけるため、appモジュールの記述は以下のように簡潔に済ませることができます。
# my-terraform-project/environments/production/app/terragrunt.hcl include { path = find_in_parent_folders() } terraform { source = "../../../modules/app" } inputs = { name = "production-app" }
比較
- DRY原則の適用
- 素のTerraform:各環境でTerraformの
backend
設定を繰り返し記述する必要がある。これは設定が重複し、変更があった場合に複数のファイルを更新する必要がある。 - Terragrunt:共通の設定(リモートステートの設定など)をルートの
terragrunt.hcl
に一度だけ記述し、include
を使用して各環境で継承できる。
- 素のTerraform:各環境でTerraformの
- コードの管理と再利用性
- 素のTerraform:各環境でモジュールを呼び出す際に、モジュールのソースと変数を指定する必要がある。
- Terragrunt:モジュール(
app
、database
、network
)を一度定義し、異なる環境で再利用。
- 保守性
- 素のTerraform:共通設定の変更には、各環境やモジュールのTerraformファイルを個別に編集する必要がある。また、誤ってほかのフォルダのステートファイルを指定してしまった場合、環境を破壊する可能性も出てくる。
- Terragrunt:共通設定の変更はルートの
terragrunt.hcl
で一度だけ行えば良いため、保守が容易
Terragruntを使用するとDRYに記述ができるため、設定の変更が容易になり、全体的なコードベースの保守性が向上します。
6. Terragruntのコマンド
ここでは、Terragrunt特有のコマンドを紹介します。
これより前の章でも書きましたが、Terragrunt特有のコマンド以外は直接Terraformに転送します。
Terragrunt Command | 説明 |
---|---|
aws-provider-patch | ネストされたAWSプロバイダーの設定を上書きして、Terraformのバグを回避 |
graph-dependencies | terragruntの依存関係グラフを標準出力に出力 |
hclfmt | 再帰的にhclファイルを検索し、それらを正規形式に書き換える |
output-module-groups | コマンド(applyまたはdestroy)で順序付けられたモジュールのグループをJSONのリストとして出力(CIでに役立つ)。 |
render-json | すべての変数、インクルード、および機能が解決された最終的なterragrunt設定をjsonとしてレンダリング |
run-all | 指定されたコマンドを各サブフォルダで実行することにより、'stack'に対してterraformコマンドを実行 |
terragrunt-info | 限定的なterragruntの状態を標準出力に出力し、終了 |
validate-inputs | terragruntで設定された入力がterraformで定義された変数と整合しているかを確認 |
* | Terragruntは他のすべてのコマンドを直接Terraformに転送 |
コマンドやオプションに関しては以下で確認することができます。
terragrunt --help
ドキュメントはこちら
run-all
コマンド
run-all
コマンドは、複数の Terraform モジュールが含まれるディレクトリ構造において、指定された Terraform コマンドをすべてのサブモジュールに対して一度に実行することができます。
先に示したTerragruntProjectのフォルダ構造の一部を参考に説明します。
environmensts/production/ ├── app/ │ └── terragrunt.hcl ├── database/ │ └── terragrunt.hcl └── network/ └── terragrunt.hcl
run-all
コマンドの使い方
run-all
コマンドを使用するには、コマンドラインで environments/production
ディレクトリに移動し、以下のようにコマンドを実行することで利用できます。
terragrunt run-all apply
このコマンドは、my-terraform-infra
ディレクトリ内のすべてのサブディレクトリ(この場合はapp
、 database
、network
)に対して terraform apply
を実行します。
依存関係の管理
run-all
コマンドは、サブディレクトリ間の依存関係も考慮します。例えば、app
モジュールが database
モジュールに依存している場合、Terragrunt は database
の apply
が完了するまで app
の apply
を開始しません。これは terragrunt.hcl
ファイル内で依存関係を設定できます。
7. Terragruntについてより深く学ぶ
Terragruntの知識を深めたい方々に向けて、Terragruntについて学ぶための情報源を紹介します。
- 公式ドキュメント
- TerragruntのGitHub Actions(terragrunt-action)も存在し、CI/CDでの利用もできます。
- その他
- 書籍はTerragruntに特化した書籍は見当たりませんでした。
- 動画はいくつかコンテンツを見つけました。
8. さいごに
この記事では、Terragruntについての基礎とこれを用いてインフラコードをDRYに書く方法を紹介しました。Terragruntを用いることでTerraformのコードをDRYに保ち、インフラの設定管理を効率化できます。快適なTerraformライフを!