こちらの、Terragruntを使用したモジュール分割との比較記事となります。
本記事では、Terragruntを使用していないので、多少冗長な設定が増えていたり実行に手間がかかったりします。
ぜひTerragruntを使用した記事と比較しながら読んでみてください。
前提
Terraformのインストール
過去記事で紹介した、tfenvを使用してインストールします。
Terraformのソースコード
Terraformモジュール化についての記事のコードを流用します。
完成版のソースコードはこちらのGitHubにコミットしました。
Terragruntを使用したコードはこちらになります。
tfstateの管理方法
今回はTerraform,Terragrunt以外の設定の手間を省くため、tfstateはローカルファイルでの管理とします。
実際の現場では、S3や、Terraform Cloudを利用しての運用になると思います。
Terraformでtfstateのモジュール単位の分割
ディレクトリ・ファイルの構成
GitHubにコミットしているものをtreeコマンドで表示したものが以下になります。
実際にコミットしているファイルだけでなくTerraform実行時に自動で作成されるディレクトリ・ファイルも含めて記載しました。
また environments/dev と environments/prod の内容は同じなのでGitHubにはdev配下にのみファイルを用意しました。
$ tree -a terraform
terraform
├── environments
│ ├── dev ・・・ 開発環境ディレクトリ。この配下でTerraform を実行。
│ │ ├── .terraform-version ・・・ tfenv設定ファイル。Terraformバージョンを固定。
│ │ ├── hello-app-server ・・・ 便宜上、記事内ではリソースディレクトリと呼びます。
│ │ │ ├── .terraform ・・・ プロバイダなどの実行時に必要なデータ保存ディレクトリ。
│ │ │ │ │ terraform init時に自動生成。
│ │ │ │ ├── modules
│ │ │ │ │ └── modules.json
│ │ │ │ ├── providers
│ │ │ │ │ └── registry.terraform.io
│ │ │ │ │ └── hashicorp
│ │ │ │ │ └── aws
│ │ │ │ │ └── 3.58.0
│ │ │ │ │ └── darwin_amd64
│ │ │ │ │ └── terraform-provider-aws_v3.58.0_x5
│ │ │ │ └── terraform.tfstate
│ │ │ ├── .terraform.lock.hcl ・・・ プロバイダなどのチェックサムが記載。
│ │ │ │ terraform init時に自動生成。コミットを推奨。
│ │ │ ├── base.tf
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ ├── test-key
│ │ │ ├── test-key.pub
│ │ │ └── variables.tf
│ │ ├── network
│ │ │ ├── .terraform
│ │ │ │ └── ...
│ │ │ ├── .terraform.lock.hcl
│ │ │ ├── base.tf
│ │ │ ├── main.tf
│ │ │ └── outputs.tf
│ │ ├── security
│ │ │ │ └── ...
│ │ │ ├── .terraform.lock.hcl
│ │ │ ├── base.tf
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ └── variables.tf
│ │ └── tfstate.d ・・・ tfstate保存ディレクトリ。
│ │ ├── .gitkeep
│ │ ├── hello-app-server
│ │ │ └── terraform.tfstate
│ │ ├── network
│ │ │ └── terraform.tfstate
│ │ └── security
│ │ └── terraform.tfstate
│ └── prod ・・・ 本番環境ディレクトリ。dev配下と同じファイルを配置。
│ └── .gitkeep
└── modules ・・・ モジュール本体。機能ごとにそれぞれ分けたもの。
├── hello-app-server
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
├── network
│ ├── main.tf
│ └── outputs.tf
└── security
├── main.tf
├── outputs.tf
└── variables.tf
$
environments/dev配下の主要ファイル説明
modules配下と同じ粒度で、network、security、hello-app-serverをディレクトリを作成しています。便宜上、本記事内では、これらをリソース、リソースディレクトリと呼称します。
この単位でtfstateが分割されますが、分割のデメリットの1つとして、1部分だけ設定が異なるが、ほぼ同じ内容の設定ファイルが複数必要になってきます。
.terraform-version
こちらの記事で紹介したtfenvのバージョン固定用ファイルです。
base.tf
Terraformのベース部分となる基本的な設定をまとめました。(ファイル名は任意です)
networkでは以下のようなっています。
terraform {
required_version = "1.0.6"
backend "local" {
path = "../tfstate.d/network/terraform.tfstate"
}
}
provider "aws" {
region = "ap-northeast-1"
profile = "default"
}
tfstateはデフォルトではカレントディレクトリに作成されますが、今回はTerragruntとの比較のため1階層上のtfstate.dディレクトリ配下に作成します。
main.tf
モジュールを相対パスで記載します。
networkでは以下のようなっています。
module "network" {
source = "../../../modules/network"
}
serurityやhello-app-serverのmain.tfでは、別のモジュールの出力値を受け取るために、data “terraform_remote_state” を指定します。
以下例ではnetworkモジュールで出力した、vpc-id をsecurityリソースで受け取っています。
module "security" {
source = "../../../modules/security"
my-ip = var.my-ip
vpc-id = data.terraform_remote_state.network.outputs.vpc-id
}
data "terraform_remote_state" "network" {
backend = "local"
config = {
path = "../tfstate.d/network/terraform.tfstate"
}
}
outputs.tf
当該モジュールで作成したリソース情報を、別リソースに渡す場合に必要となります。
modulesディレクトリ配下の各outputs.tfで定義した変数名を更に、ここでoutputします。moduleのoutputと、リソースでのoutputの2段階必要になります。
networkでは以下のようなっています。
output "vpc-id" {
value = module.network.vpc-id
# 以下の記述はNG
#value = module.network.aws_vpc.test-vpc.id
}
output "subnet-east-id" {
value = module.network.subnet-east-id
}
output "subnet-west-id" {
value = module.network.subnet-west-id
}
以上、分割の上でのポイントでした。
Terraformの実行
こちらの記事のようにtfstate分割していない場合は、1回のterraform applyの実行で全リソースが作成されましたが、分割した場合はそれぞれのリソースディレクトリで実行する必要があります。
これも分割の1つのデメリットとなります。
事前準備
Githubからサンプルコードをダウンロードして、こちらの記事のように自分のIPアドレスへ書き換えます。
またEC2へ接続するためのssh鍵の作成も行います。
$ git clone git@github.com:zoo200/blog.git
$
$ cd manage-tfstate-per-module-only-with-terraform/environments/dev
$
## default のIPを自分のIPアドレスに変更
$ vi security/variables.tf
variable "my-ip" {
type = string
default = "192.168.1.1/32"
}
$
## ssh鍵を作成します
$ ssh-keygen -N "" -f hello-app-server/test-key
Generating public/private rsa key pair.
...
$
Terraform実行
実行ディレクトリの environments/dev 配下の各リソースディレクトリで、ディレクトリ移動 → terrafom init → terraform apply → yes の入力 をひたすら繰り返します。
## networkリソース作成
$ cd network
$
$ terraform init
..
$
$ terraform apply
...
Enter a value: yes ・・・ yesを入力
...
$
## securityリソース作成
$ cd ../security
$
$ terraform init
...
$
$ terraform apply
...
Enter a value: yes ・・・ yesを入力
...
$
## hello-app-serverリソース作成
$ cd ../hello-app-server
$
$ terraform init
...
$
$ terraform apply
...
Enter a value: yes ・・・ yesを入力
...
$
以上、Terragruntを使用した場合との違いを理解する助けになれば幸いです。
今回は以上です〜ノシ
参考
(*ゝω・)ノ ァリガトネー
tfstateを分割管理するためのTips
terraform_remote_state の説明