课程内容与代码会放在 Github 上: https://github.com/chechiachang/terraform-30-days
赛後文章会整理放到个人的部落格上 http://chechia.net/
前六堂课程,我们简单认识 Terraform 的核心观念,包括 State & Backend,以及Module 使用,已经可以在工作上实际使用 Terraform。然而,随着使用时间越长,使用的 module 越多,开始会发现许多 Terraform 的程序码会不断的重复,违反 DRY 原则,例如:
_poc/container_registry/
这边的范例,一堆 soft link provider.tf 吗Ex. Registry 的 input arguments 中许多参数,跟别的 root module 重复
# _poc/container_registry/provider.tf
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 2.65.0"
}
}
required_version = ">= 1.0.1"
# remote Backend
backend "azurerm" {
resource_group_name = "terraform-30-days"
storage_account_name = "tfstatee903f2ef317fb0b4"
container_name = "tfstate"
key = "container_registry.tfstate" # 唯一不一样的设定
}
Ex. Registry 的 input arguments 中许多参数,跟别的 root module 重复
# _poc/container_registry/registry.tf
location = "southeastasia"
resource_group_name = "terraform-30-days"
Don't Repeat Youself 是一个软件工程开发的基本原则,不断重复的程序码往往代表未来维护的困难,违反 DRY 不一定代表不好,在某些情形工程师可能会选择更好的可读性,而牺牲 DRY。Terraform Lanuguage 由於语言特性,有一部份重复的程序码。
这部分重复的程序码,会随团队使用 Terraform 的规模线性成长,对於管理大量 Terraform 的维护人员造成困扰,也拖慢开发进度。
因此,在开始接触大量复杂范例之前,我们选择先导入 Terragrunt 这个工具,来精简程序码。
Terragrunt 是 gruntwork 推出的一个 Terraform thin wrapper,在执行 Terraform 前可以先"调整" root module 内的 .tf 档案,保持程序码的精简,并提供许多而外工具,加速开发
这里附上 Gruntwork 官方的 Get Started Guide
可以直接到 Github release 页面 下载 binary
wget https://github.com/gruntwork-io/terragrunt/releases/download/v0.31.3/terragrunt_darwin_amd64
chmod +x terragrunt_darwin_amd64
sudo mv terragrunt_darwin_amd64 /usr/local/bin/terragrunt
如果使用 pkg manager 或其他工具,也可以直接使用
brew install terragrunt
安装完可以使用 terragrunt
terragrunt --help
VERSION:
v0.31.3
接下来我们要设定 terragrunt。由於Terragrunt 有非常多的功能,这边我们先专注在两个需求:
这边我们直接看范例,首先要说明整体资料夹结构:
tree -L 1 azure
azure
├── _poc
├── foundation
├── dev
│ └── southeastasia
├── modules
├── prod
├── stag
├── test
├── terragrunt.hcl
└── env.tfvars
azure/_poc
是使用 terragrunt 之前我们所有的范例那剩下两个东西是什麽?
这是与 terragrunt 设定有关,请见底下的说明。
首先我们可以在产生一组 terraform backend
到 azure/foundation/southeastasia/terraform_backend
,一看,里面只剩下一个档案
# terragrunt.hcl
# TERRAGRUNT CONFIGURATION
terraform {
source = "../../../..//azure/modules/terraform_backend"
}
# dependency cycle: terraform_backend is provisioned before all terragrunt usage. There is no terragrunt.hcl at that time.
#include {
# path = "${find_in_parent_folders()}"
#}
inputs = {
resource_group_name = "terraform-30-days"
location = "southeastasia" # Or use japaneast
}
接下来进行 init 与 plan。我们把新的 terraform backend 使用 terragrunt 产生出来
terragrunt init
terragrunt plan
terragrunt apply
到这边,使用起来跟直接使用 terraform 应该没有差异,上面这个例子并没有使用 terragrunt 的额外功能。terragrunt 单纯把 terraform 的 command 传递下去,底下还是执行 terraform。
terragrunt 的功能,下个例子就会展现。
网路 / VPC 网段的管理,是公有云的必要工作,这边以 provision 新的网段为例
到 azure/foundation/compute_network
,里面有两个档案
tree
.
├── compute_network.tf
└── terragrunt.hcl
provider.tf 在这边已经消失了
看一下 terragrunt.hcl 的设定,重点在 include {} 这个 code block
find_in_parent_folders()
是 terragrunt 提供的 function
# terragrunt.hcl
# TERRAGRUNT CONFIGURATION
# use terragrunt function to include .hcl file
# in this case, will find azure/terragrunt.hcl
include {
path = find_in_parent_folders()
}
terraform {
source = "../../..//azure/foundation/compute_network"
# use double-slash (//) after repository root path to avoid
# - WARN[0000] No double-slash (//) found in source URL
#source = "."
}
底下的 terraform {} code block 则跟上一个例子一样,指向 root module
../../../..//azure/modules/terraform_backend
其实就是 .
也就是当前所在路径接下来看上层 include 的 ~/terraform-30-days/azure/terragrunt.hcl
内容
首先是 provider.tf,这边使用 generate {} code block 来产生 provider.tf
# azure/terragrunt.hcl
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "azurerm" {
features {}
}
EOF
}
再来产生的事 backend.tf,使用 remote_state
{} code block 设定 remote backend
# azure/terragrunt.hcl
remote_state {
backend = "azurerm"
generate = {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
}
config = {
key = "${path_relative_to_include()}/terraform.tfstate"
resource_group_name = "terraform-30-days"
storage_account_name = "tfstate445d2966b56b5d05"
container_name = "tfstate"
}
}
path_relative_to_include()
是另一个 terragrunt function
azure/foundation/compute_network/terragrunt.hcl
azure/terragrunt.hcl
path_relative_to_include() = foundation/compute_network
├── terragrunt.hcl
├── env.tfvars
├── foundation
│ ├── compute_network
│ │ ├── compute_network.tf
│ │ └── terragrunt.hcl
所以整个效果等同於产生一个 backend.tf
# backend.tf
terraform {
backend "azurerm" {
key = "foundation/compute_network/terraform.tfstate"
resource_group_name = "terraform-30-days"
storage_account_name = "tfstate445d2966b56b5d05"
container_name = "tfstate"
}
}
为何 key 要设为 foundation/compute_network/terraform.tfstate
foundation/compute_network/terragrunt.hcl
blob//foundation/compute_network/terraform.tfstate
最後一段 terraform {} block,可以在 terragrunt 驱动的 terraform command 做许多调整,例如
extra_arguments
get_terraform_commands_that_need_vars()
,回传一串接受 -var 与 -var-file 参数的 terraform commandrequired_var_files
参数把 env.tfvars 档案,作为 terraform -var-file 的参数get_parent_terragrunt_dir()
使用,拿到上层 terragrunt.hcl 的绝对路径~/terraform-30-days/azure/env.tfvars
,作为 -var-file 的参数# azure/terragrunt.hcl
terraform {
extra_arguments "env" {
commands = get_terraform_commands_that_need_vars()
required_var_files = [
"${get_parent_terragrunt_dir()}/env.tfvars",
]
}
}
效果等同在 terraform plan 与 apply (以及其他 command) 执行时,多加参数
terraform plan -var-file ~/terraform-30-days/azure/env.tfvars
terraform apply -var-file ~/terraform-30-days/azure/env.tfvars
terragrunt 会将 terraform module cache 一分在本目录,cache
如果是在本地开发中的 module,有可能会 cache 到错误的 module,请把本地 cache 清除再重新 init
rm -rf .terragrunt-cache
terragrunt init
terraform 的命令在 terragrunt 上完全都能使用,所以才说 terragrunt 是一层 wrapper,意思是
使用 Terragrunt 是一个额外的选择,团队可以依据状况去选择
Pros
Cons
<<: Innodb资料页结构-Part2(页面目录、页面表头、档案表头、档案结尾)
>>: D7 - 如何用 Google Apps Script 将 Google 表单的回应即时同步在多个行事历上?
今天来讲JAVA的运算符号 JAVA的运算符号有分很多种,例如: " + "加 ...
前言: 大家好,这是我第一次参加铁人赛 主要是想记录一下自己学过的东西 并和大家分享一些我觉得很重要...
Guard 可以帮助你在开发时监听,并启用测试,让你在开发阶段可以顺便跑测试,当然我也是第一次玩XD...
常听说出事了就想找老大摆平, 结果在群内的地位越来越低, 如果能试着自己处理问题, 把事情Handl...
CLA以及bit乘法 tags: IT铁人 例题答案 就简单把答案打出来罗~ 小心转换成二位元不要粗...