tfustomize
is yet another way to reuse resource configurations with Terraform.
tfustomize
is literally inspired by kustomize
, a Kubernetes manifests management tool.
Terraform Modules is looks almost the only way to reuse resource configurations with Terraform. There is other option terragrunt
, but it's looks expanding and wrapping the use of Terraform module.
Terraform modules are effective when they are widly spread as open sources, or when they are officially provided by kind of Platform Engineers for internal use in private environments. However, creating custom modules for one product seems like overkill.
It was quite labor-intensive to transition from a copy-paste style of management to using custom modules, so I created something like a Terraform version of kustomize as a proof of concept.
Override Files feature is looks similar concept with tfustomize
but overriding is not for reusing purpose.
# using Go
go install github.com/tk3fftk/tfustomize@latest
# from Releases
curl -L https://github.com/tk3fftk/tfustomize/releases/download/v0.2.0/tfustomize_0.2.0_Linux_x86_64.tar.gz | tar xvz
💡example provides instructions for generating Terraform configuration files using tfustomize
.
tfustomize
reads a tfustomization.hcl
file and generated a directory and a file as a result of merging.
Users can use the output file to run terraform plan
and terraform apply
.
Usage:
tfustomize build [dir] [flags]
Flags:
-h, --help help for build
-o, --out string Output directory (default "generated")
-f, --outfile string Output filename (default "main.tf")
-p, --print Print the result to the console instead of writing to a file
Global Flags:
-d, --debug Enable debug mode
The format of tfustomization.hcl
is following.
tfustomize {
syntax_version = "v1"
}
resources {
paths = [
"../base",
]
}
patches {
paths = [
"./main.tf",
]
}
tfustomize
block:- Currently it's just a placeholder.
resources
block:- Specify "base" configuration files.
- directory or file name are available.
patches
block:- Specify "overlay" configuration files.
- directory or file name are available.
- A Top-level block has the same block type and labels in base and overlay will be merged.
- Except
moved
,import
,removed
block. These will be appended.
- Except
locals
blocks will be merged.- Within a top-level block, an attribute argument within an overlay block will be replaced any argument of the same name in the base block.
- Within a top-level block, any block will be appended by default.
- To merge a block, use an annotation
# tfustimize:merge_block:<key>
both a base and an overlay like below.
- To merge a block, use an annotation
# base
data "aws_ami" "ubuntu" {
filter {
# tfustomize:merge_block:name
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
}
# overlay
data "aws_ami" "ubuntu" {
filter {
name = "arch"
values = ["arm64"]
}
filter {
# tfustomize:merge_block:name
name = "name_is_updated"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-24.04-amd64-server-*"]
}
}
# output
data "aws_ami" "ubuntu" {
filter {
name = "arch"
values = ["arm64"]
}
filter {
name = "name_is_updated"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-24.04-amd64-server-*"]
}
}
- [Limitation] The output order is randomized inside block level order. (#6)
someApp
├── production
│ ├── backend.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── tfustomization.hcl
│ └── variables.tf
└── staging
├── backend.tf
├── main.tf
├── outputs.tf
├── tfustomization.hcl
└── variables.tf
staging/tfustomization.hcl
tfustomize {
syntax_version = "v1"
}
resources {
paths = [
"./",
]
}
patches {
paths = []
}
production/tfustomization.hcl
tfustomize {
syntax_version = "v1"
}
resources {
paths = [
"../staging",
]
}
patches {
paths = [
"./",
]
}