Terramateを既存のTerraformプロジェクトに導入してみる
序論
何回かTerramateについてブログで書いてきました。
ただ新しいツールを導入する際に苦労するのが、すでに出来上がっている既存構成にどのように組み込めばいいのか悩まれた人も多いと思います。
Terramateの開発者も同じ考えを持ち、TerramateにはTerraformおよびOpenTofuの既存プロジェクトにワンコマンドで導入できる機能を実装しております。
we added a feature to Terramate that allows you to onboard Terramate in existing Terraform and OpenTofu projects with a single command and without touching any of your existing configurations to avoid hard lock-in and breaking changes.
機械翻訳:) Terramateに、既存のTerraformおよびOpenTofuプロジェクトにTerramateを1つのコマンドでオンボードできる機能を追加しました。既存の構成に触れることなく、ハードロックインや破壊的変更を回避できます。
今回は、どのようにTerraform(OpenTofu)の既存プロジェクトにTerramateを導入できるかを紹介いたします。
対象読者
- 既存のTerraformプロジェクトにTerramateを導入してみたい人
- Terramateを検証してみたい人
Terraformディレクトリ構成
今回Terramateを導入するTerraformのディレクトリ構成は以下の通りです。
├── env
│ ├── prod
│ │ ├── database
│ │ │ ├── aurora.tf
│ │ │ ├── backend.tf
│ │ │ └── provider.tf
│ │ ├── network
│ │ │ ├── backend.tf
│ │ │ ├── provider.tf
│ │ │ └── vpc.tf
│ │ └── storage
│ │ ├── backend.tf
│ │ ├── provider.tf
│ │ └── s3.tf
│ └── stg
│ ├── database
│ │ ├── aurora.tf
│ │ ├── backend.tf
│ │ └── provider.tf
│ ├── network
│ │ ├── backend.tf
│ │ ├── provider.tf
│ │ └── vpc.tf
│ └── storage
│ ├── backend.tf
│ ├── provider.tf
│ └── s3.tf
└── module
├── database
│ ├── aurora.tf
│ └── variables.tf
├── network
│ ├── variables.tf
│ └── vpc.tf
└── storage
├── s3.tf
└── variables.tf
module "network" {
source = "../../../module/network"
vpc_name = "main"
env = "stg"
cidr_block = "10.0.0.0/16"
}
リソース別にモジュールを構築し、環境別にそれぞれのリソースフォルダを分けて、モジュールを呼び出す標準的なモジュール構造のTerraformプロジェクトとなっております。[1]
このような構成でTerraformを導入し、ローカルでTerraformを実行またはHCP Terraform[2]などでCI/CDパイプラインを実装している企業も多いのではないでしょうか。
Terramateの導入
既存のTerraformプロジェクトにTerramateを導入するにはルートディレクトリで以下のコマンドを実行します。
$ terramate create --all-terraform
Created stack /terraform/terramate-import/env/prod/network
Created stack /terraform/terramate-import/env/prod/storage
Created stack /terraform/terramate-import/env/stg/network
Created stack /terraform/terramate-import/env/stg/storage
.....
$ terramate list
env/prod/network
env/prod/storage
env/stg/network
env/stg/storage
コマンドを実行すると環境ディレクトリ配下のリソースフォルダにstack.tm.hcl
[3]ファイルが生成されます。terramate list
コマンドでTerramateがStackの存在を認識していることが確認できます。
後はterramate run ~
コマンドでTerraformコマンドを実行することで環境別リソース別のStateファイルへのTerraform実行を一発で実行できます。
$ terramate run -C env/ terraform plan #envディレクトリ配下のStateファイルに対して一括でTerraformコマンド実行
terramate: Entering stack in /terraform/terramate-import/env/prod/network
terramate: Executing command "terraform plan"
module.network.aws_vpc.vpc: Refreshing state... [id=vpc-0ee9712cef5a53f91]
No changes. Your infrastructure matches the configuration. Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
terramate: Entering stack in /terraform/terramate-import/env/prod/storage
terramate: Executing command "terraform plan"
module.storage.random_id.storage_suffix: Refreshing state... [id=F8rPSPmzFAw]
module.storage.aws_s3_bucket.main_bucket: Refreshing state... [id=main-17cacf48f9b3140c]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
terramate: Entering stack in /terraform/terramate-import/env/stg/network
terramate: Executing command "terraform plan"
module.network.aws_vpc.vpc: Refreshing state... [id=vpc-00e3d58c70328ce9f]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# module.network.aws_vpc.vpc will be updated in-place
~ resource "aws_vpc" "vpc" {
id = "vpc-00e3d58c70328ce9f"
~ tags = {
~ "Name" = "main" -> "sub"
"env" = "stg"
}
~ tags_all = {
~ "Name" = "main" -> "sub"
# (1 unchanged element hidden)
}
# (18 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply"
now.
terramate: Entering stack in /terraform/terramate-import/env/stg/storage
terramate: Executing command "terraform plan"
module.storage.random_id.storage_suffix: Refreshing state... [id=tTlsrqAitmI]
module.storage.aws_s3_bucket.main_bucket: Refreshing state... [id=sub-b5396caea022b662]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
ただこの方法でStackファイルを作成してTerramateコマンドを実行したところ通常よりもかなりの時間がかかりました。
コマンド実行完了までに15分近くもかかったのですが、原因はよくわかりません。
既存プロジェクトへの導入の場合に時間がかかったのか、モジュール構造のTerraformプロジェクトだと時間がかかるのかは要検証が必要です。
所感
既存TerraformプロジェクトにTerramateを組み込む方法について紹介しました。
新ツールを導入すると既存のシステムにどう組み込むかが課題となります。今回紹介したワンコマンドですぐに導入できそうで良さそうとは思いましたが、Terramateのコマンド実行にかなり時間がかかりモジュール構造のTerraformプロジェクトと相性が悪い場合使い道が限られそうな気がしますので仕事で使うには検証の余地が出てくると思いました。
私の実行環境(ローカルPC)の問題かもしれないのでこのTerraformプロジェクトをGitHub Actions上で実行してみ比較してみようと思います。
参考文献
Discussion