module 是 terraform 执行与调用的基本单位。本章简单介绍 module 的内容与使用。
课程内容与代码会放在 Github 上: https://github.com/chechiachang/terraform-30-days
赛後文章会整理放到个人的部落格上 http://chechia.net/
module 在 Terraform 中的定义很简单,就是一个 container,里头有一组一起使用的 resource .tf。然而除了容纳一组 resource 以外,module 还有须多额外的功能。
我们看一下 _poc/container_registry_module
这边的范例
module "test" {
source = "../../..//azure/modules/container_registry"
registry_name = "chechiatest"
resource_group_name = local.resource_group_name
location = local.location
public_network_access_enabled = true
}
module "registry" {
for_each = toset(local.environments) # convert tuple to set of string
source = "../../..//azure/modules/container_registry"
registry_name = "chechia${each.value}"
...
}
这里使用 module block,来宣告一组 child module
使用另外一组 module block,来宣告另一组 child module
for_each
meta-argument,来宣告这组 module 里面,由多个 instance 组成${each.value}
,将 registry name eval 成为 "chechiadev", "chechiastag", "chechiaprod" 三个名称,给三个 instance 使用执行 Terraform init,会在 init
.terraform/providers
中只有 azurerm.terraform/providers
中terraform init
Initializing modules...
- registry in ../../../azure/modules/container_registry
- test in ../../../azure/modules/container_registry
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/azurerm from the dependency lock file
- Installing hashicorp/azurerm v2.65.0...
- Installed hashicorp/azurerm v2.65.0 (signed by HashiCorp)
...
我们可以看一下 .terraform
内容
cat .terraform/modules/modules.json | jq
{
"Modules": [
{
"Key": "",
"Source": "",
"Dir": "."
},
{
"Key": "registry",
"Source": "../../..//azure/modules/container_registry",
"Dir": "../../../azure/modules/container_registry"
},
{
"Key": "test",
"Source": "../../..//azure/modules/container_registry",
"Dir": "../../../azure/modules/container_registry"
}
]
}
_poc/container_registry_module
root module 本身../../../azure//azure/modules/container_registry
module
如果 module 有任何新增删除,或是设定改动,都需要重新 init,因为 module 的初始化在 init 步骤处理。
初始化完成,进行 plan,看看是否如我们预期
terraform plan
# module.registry["dev"].azurerm_container_registry.acr will be created
+ resource "azurerm_container_registry" "acr" {
+ location = "southeastasia"
+ name = "chechiadev"
# module.registry["prod"].azurerm_container_registry.acr will be created
+ resource "azurerm_container_registry" "acr" {
+ location = "southeastasia"
+ name = "chechiaprod"
# module.registry["stag"].azurerm_container_registry.acr will be created
+ resource "azurerm_container_registry" "acr" {
+ location = "southeastasia"
+ name = "chechiastag"
# module.test.azurerm_container_registry.acr will be created
+ resource "azurerm_container_registry" "acr" {
+ location = "southeastasia"
+ name = "chechiatest"
Plan: 4 to add, 0 to change, 0 to destroy.
plan 结果
module.test.azurerm_container_registry.acr
module.registry
object,内容为三个 instance,依字母排序分别为
module.registry["dev"]
module.registry["prod"]
module.registry["stag"]
Terraform apply,terraform 便会平行化处理产生这四个 registry
terraform apply
...
module.registry["stag"].azurerm_container_registry.acr: Creating...
module.registry["dev"].azurerm_container_registry.acr: Creating...
module.registry["prod"].azurerm_container_registry.acr: Creating...
module.test.azurerm_container_registry.acr: Creating...
...
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Terraform 官方文件 对 module 的说明
_poc/container_registry
中操作,本身便是一组 root module。换句话说,当资料夹中只有一组,便不会产生 .terraform/modules/ 资料夹及档案。这里跟程序码的实作比较有关,使用上不用额外注意。
随着 Terraform 使用越久,我们会开始产生越来越复杂的 .tf 档案,以满足我们的需求,而这些需求有可能是类似的功能,不断重复。例如:
_poc/container_registry
中,我们设定了一组 container registry。在现实的应用中,我们可能会产生多组 Registry,给不同服务使用。一个实际的例子:开发流程中产生多组功能相同的 infrastructure resources,作为测试环境与生产环境,除了 poc-registry 外,我们可能会产生 dev-registry,stag-registry,prod-registry,内容完全相同,承载开发流程中不同用途的软件环境。
使用截至目前所学,可能是把 .tf 档案复制多份,更改成名称等参数,apply 上去就获得多组不同的 registry。
resource "azurerm_container_registry" "acr" {
name = "chechia-poc"
resource_group_name = "terraform-30-days-poc"
location = "southeastasia"
}
resource "azurerm_container_registry" "acr" {
name = "chechia-dev"
resource_group_name = "terraform-30-days-poc"
location = "southeastasia"
}
resource "azurerm_container_registry" "acr" {
name = "chechia-stag"
resource_group_name = "terraform-30-days-poc"
location = "southeastasia"
}
resource "azurerm_container_registry" "acr" {
name = "chechia-prod"
resource_group_name = "terraform-30-days-poc"
location = "southeastasia"
}
这个做法十分直观,而且确实能用。Terraform 对相同 directory 中的 .tf 数量也没有限制,也就是说我们可以使用无限的复制贴上,来解决。
可以尝试更改 _poc/container_registry
的资料夹,试着 apply。完全没问题,是吧?
我们很快发现
Don't Repeat Yourself (DRY),是软件工程中不同领域共通的最佳实践。不断重复的代码,本身就代表而外的维护成本。那在 Terraform 中我们有没有可能重复使用 .tf 中的内容?
使用的本地 module 会有一些问题
开头提到 module 可以方便程序码重用,可以使用社群维护的 module,然而到目前我们还是无法使用社群维护的 terraform module,例如:
我想使用 Azure 维护的 AKS module,可以让我直接建立 Azure Kubernetes Service
目前使用本地 module 的话,我就要把整个 AKS module 里面的 .tf copy 到本地 repository 中使用。如此确实可以运作,但 copy 等於失去远端的 reference,如果後续远端有更新,本地也很难使用
另外,本地的 module 很难给另外一个 repository 使用,例如:
我又开一个 github.com/chechiachang/terraform-30-weeks 的 repository,那要如何使用 terraform-30-days 中的 module?
我们写成 module 是希望尽可能量重复使用相同程序码,但希望是类似 git submodule 的方式,保留对远端的 reference,有更新可以 git pull 下来使用
module 会随着使用持续修改,如果我今天希望修改 module 内容,但 module 已经在使用中了,该如何处理?例如:
开发 //azure/modules/container_registry
中的新功能
module "test" {
source = "../../..//azure/modules/container_registry"
...
}
module "registry" {
for_each = toset(local.environments) # convert tuple to set of string
source = "../../..//azure/modules/container_registry"
...
}
以上面的 .tf 档案,改了 //azure/modules/container_registr
的话,所有使用到的内容都会一起改变。实务上会希望可以把现有的程序码锁在旧的版本,新的程序码使用本地 module 继续开发新功能。例如打 version tag:
module "registry" {
for_each = toset(local.environments) # convert tuple to set of string
source = "../../..//azure/modules/container_registry?ref=v0.1.0"
...
}
事实上,Terraform 不只支援本地的 module,还有许多类型的 module 可以解决上述问题(请见下章)
对於 terraform init module 的程序码,有兴趣请见 Terraform Github
_poc/container_registry_module
,使用其他的 module argument count
,取代 for_each
,达成一样的效果至此,我们已经学会使用 module 来重用(reuse) .tf 档案,这边只完成课程目标的一半。熟悉开源专案,我们很自然会想到,有没有可以使用社群维护的 module,来让我们使用。下堂课将分享,module 各种不同的 ㄩodule remote source,以及如何分享及使用远端的 module?
<<: 每个人都该学的30个Python技巧|技巧 5:各种运算子(上)(字幕、衬乐、练习)
一开始学习时用Sublime,久了之後也成为一种习惯(,,・ω・,,) 但是初学者很喜欢写一步骤就要...
讲完最基础的Route设置之後, 来学习如何更准确的经由path来渲染画面上的元件。 Route标签...
昨天帮我们用 Reactive Forms 所撰写的登入系统写完单元测试之後,今天则是要来为它写整...
MySQL 是免费的关联式资料库,具有轻量级速度快的优点,适合小型网站架设使用。 目前最流行的 Wo...
哈罗大家好~ 今天要跟大家介绍 Microsoft Form 问卷调查工具,不过相信目前云端问卷工具...