将 Makefile 与 Terraform 结合使用并拆分项目布局
Using Makefile with Terraform and split project layout
我有一个类似于
的 Terraform 项目布局
stage
└ Makefile
└ terraform.tfvars
└ vpc
└ services
└ frontend-app
└ backend-app
└ vars.tf
└ outputs.tf
└ main.tf
└ data-storage
└ mysql
└ redis
其中Makefile
的内容与
相似
.PHONY: all plan apply destroy
all: plan
plan:
terraform plan -var-file terraform.tfvars -out terraform.tfplan
apply:
terraform apply -var-file terraform.tfvars
destroy:
terraform plan -destroy -var-file terraform.tfvars -out terraform.tfplan
terraform apply terraform.tfplan
据我了解,Terraform
只会在当前目录中的模板上 运行。所以我需要 cd stage/services/backend-app
和 运行 terraform apply
那里。
但是我希望能够从 Makefile 管理整个堆栈。我还没有看到将参数传递给 make
的好方法。
我的目标是
make s3 plan # verify syntax
make s3 apply # apply plan
除非有更好的方法从父目录 运行 terraform?有没有类似于:
make all plan # create stage plan
make all apply # apply stage plan
我们使用 shell 脚本来处理这个确切的用例,它可以更好地处理 cd
周围。
但是,您可以通过使用环境变量或直接在目标后面的命令行上设置 Make 变量,如下所示:
make target FOO=bar
所以在你的情况下,你可能需要这样的东西:
ifndef LOCATION
$(error LOCATION is not set)
endif
.PHONY: all plan apply destroy
all: plan
plan:
cd $(LOCATION) && \
terraform plan -var-file terraform.tfvars -out terraform.tfplan
apply:
cd $(LOCATION) && \
terraform apply -var-file terraform.tfvars
destroy:
cd $(LOCATION) && \
terraform plan -destroy -var-file terraform.tfvars -out terraform.tfplan
terraform apply terraform.tfplan
我可能倾向于有一个运行 terraform get
并且还配置远程状态的目标,但现在设置起来应该很简单。
另一种解决方案是在每个 运行 上创建一个 tmp 文件夹并使用 terraform init ...
和 terraform get...
,就像这样(该示例还显示了使用部分配置的远程状态管理) :
readonly orig_path=$(pwd) && \
mkdir tmp && \
cd tmp && \
terraform init -backend=true -backend-config="$tf_backend_config" -backend-config="key=${account}/${envir}/${project}.json" $project_path && \
terraform get $project_path && \
terraform apply && \
cd $orig_path && \
rm -fR tmp
或者将上面的代码包装到 shell 脚本中,然后从 "apply" 等下的 make 文件中调用它
-- 添加此部分以解决来自 Sam Hammamy 的 comment/question --
总的来说,根据当前版本的 Terraform 处理项目的方式,我们确实想提前考虑如何构建我们的项目,以及如何将它们分解成可管理的、仍然有效的部分。这就是为什么我们通常将它们分解为 "foundational" 项目,如 VPC、VPN、SecurityGroups、IAM-Policies、Bastions 等,而不是像 "db"、"web-cluster" 等“功能性”项目。我们通常 run/deploy/modify "fundamental" 件一次或偶尔,而 "functional" 件我们可能每天重新部署几次。
这意味着随着我们的 IaC 代码的碎片化,我们也将相应地结束远程状态的碎片化,以及项目部署的执行。
对于反映"philosophy"的项目结构,我们通常会得到类似这样的项目结构(未显示公共模块):
├── projects
│ └── application-name
│ ├── dev
│ │ ├── bastion
│ │ ├── db
│ │ ├── vpc
│ │ └── web-cluster
│ ├── prod
│ │ ├── bastion
│ │ ├── db
│ │ ├── vpc
│ │ └── web-cluster
│ └── backend.config
└── run-tf.sh
每个项目都是一个子文件夹,对于每个 application_name/env/component = 文件夹(即 dev/vpc),我们添加了一个占位符后端配置文件:backend.tf:
terraform {
backend "s3" {
}
}
每个组件的文件夹内容将包含类似于以下文件:
│ ├── prod
│ │ ├── vpc
│ │ │ ├── backend.tf
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ └── variables.tf
在 "application_name/" 或 "application_name/env" 级别,我们添加了一个 backend.config 文件,内容为:
bucket = "BUCKET_NAME"
region = "region_name"
lock = true
lock_table = "lock_table_name"
encrypt = true
我们的包装器 shell 脚本需要参数应用程序名称、环境、组件和实际的 terraform cmd 运行。
运行-tf.sh脚本内容(简体):
#!/bin/bash
application=
envir=
component=
cmd=
tf_backend_config="root_path/$application/$envir/$component/backend.config"
terraform init -backend=true -backend-config="$tf_backend_config" -backend-config="key=tfstate/${application}/${envir}/${component}.json"
terraform get
terraform $cmd
这是典型的 运行-tf.sh 调用的样子(从 Makefile 执行):
$ run-tf.sh application_name dev vpc plan
$ run-tf.sh application_name prod bastion apply
我有一个类似于
的 Terraform 项目布局stage
└ Makefile
└ terraform.tfvars
└ vpc
└ services
└ frontend-app
└ backend-app
└ vars.tf
└ outputs.tf
└ main.tf
└ data-storage
└ mysql
└ redis
其中Makefile
的内容与
.PHONY: all plan apply destroy
all: plan
plan:
terraform plan -var-file terraform.tfvars -out terraform.tfplan
apply:
terraform apply -var-file terraform.tfvars
destroy:
terraform plan -destroy -var-file terraform.tfvars -out terraform.tfplan
terraform apply terraform.tfplan
据我了解,Terraform
只会在当前目录中的模板上 运行。所以我需要 cd stage/services/backend-app
和 运行 terraform apply
那里。
但是我希望能够从 Makefile 管理整个堆栈。我还没有看到将参数传递给 make
的好方法。
我的目标是
make s3 plan # verify syntax
make s3 apply # apply plan
除非有更好的方法从父目录 运行 terraform?有没有类似于:
make all plan # create stage plan
make all apply # apply stage plan
我们使用 shell 脚本来处理这个确切的用例,它可以更好地处理 cd
周围。
但是,您可以通过使用环境变量或直接在目标后面的命令行上设置 Make 变量,如下所示:
make target FOO=bar
所以在你的情况下,你可能需要这样的东西:
ifndef LOCATION
$(error LOCATION is not set)
endif
.PHONY: all plan apply destroy
all: plan
plan:
cd $(LOCATION) && \
terraform plan -var-file terraform.tfvars -out terraform.tfplan
apply:
cd $(LOCATION) && \
terraform apply -var-file terraform.tfvars
destroy:
cd $(LOCATION) && \
terraform plan -destroy -var-file terraform.tfvars -out terraform.tfplan
terraform apply terraform.tfplan
我可能倾向于有一个运行 terraform get
并且还配置远程状态的目标,但现在设置起来应该很简单。
另一种解决方案是在每个 运行 上创建一个 tmp 文件夹并使用 terraform init ...
和 terraform get...
,就像这样(该示例还显示了使用部分配置的远程状态管理) :
readonly orig_path=$(pwd) && \
mkdir tmp && \
cd tmp && \
terraform init -backend=true -backend-config="$tf_backend_config" -backend-config="key=${account}/${envir}/${project}.json" $project_path && \
terraform get $project_path && \
terraform apply && \
cd $orig_path && \
rm -fR tmp
或者将上面的代码包装到 shell 脚本中,然后从 "apply" 等下的 make 文件中调用它
-- 添加此部分以解决来自 Sam Hammamy 的 comment/question --
总的来说,根据当前版本的 Terraform 处理项目的方式,我们确实想提前考虑如何构建我们的项目,以及如何将它们分解成可管理的、仍然有效的部分。这就是为什么我们通常将它们分解为 "foundational" 项目,如 VPC、VPN、SecurityGroups、IAM-Policies、Bastions 等,而不是像 "db"、"web-cluster" 等“功能性”项目。我们通常 run/deploy/modify "fundamental" 件一次或偶尔,而 "functional" 件我们可能每天重新部署几次。
这意味着随着我们的 IaC 代码的碎片化,我们也将相应地结束远程状态的碎片化,以及项目部署的执行。
对于反映"philosophy"的项目结构,我们通常会得到类似这样的项目结构(未显示公共模块):
├── projects
│ └── application-name
│ ├── dev
│ │ ├── bastion
│ │ ├── db
│ │ ├── vpc
│ │ └── web-cluster
│ ├── prod
│ │ ├── bastion
│ │ ├── db
│ │ ├── vpc
│ │ └── web-cluster
│ └── backend.config
└── run-tf.sh
每个项目都是一个子文件夹,对于每个 application_name/env/component = 文件夹(即 dev/vpc),我们添加了一个占位符后端配置文件:backend.tf:
terraform {
backend "s3" {
}
}
每个组件的文件夹内容将包含类似于以下文件:
│ ├── prod
│ │ ├── vpc
│ │ │ ├── backend.tf
│ │ │ ├── main.tf
│ │ │ ├── outputs.tf
│ │ │ └── variables.tf
在 "application_name/" 或 "application_name/env" 级别,我们添加了一个 backend.config 文件,内容为:
bucket = "BUCKET_NAME"
region = "region_name"
lock = true
lock_table = "lock_table_name"
encrypt = true
我们的包装器 shell 脚本需要参数应用程序名称、环境、组件和实际的 terraform cmd 运行。
运行-tf.sh脚本内容(简体):
#!/bin/bash
application=
envir=
component=
cmd=
tf_backend_config="root_path/$application/$envir/$component/backend.config"
terraform init -backend=true -backend-config="$tf_backend_config" -backend-config="key=tfstate/${application}/${envir}/${component}.json"
terraform get
terraform $cmd
这是典型的 运行-tf.sh 调用的样子(从 Makefile 执行):
$ run-tf.sh application_name dev vpc plan
$ run-tf.sh application_name prod bastion apply