《Terraform 101 從入門到實踐》這本小冊在南瓜慢說官方網站和GitHub兩個地方同步更新,書中的範例程式碼也是放在GitHub上,方便大家參考檢視。
模組化是Terraform實現程式碼重用的方式。模組可以理解為一個包含多個資源的容器模板。封裝好之後,可以給大家使用。也可以理解為程式碼中的函數或方法,它接收入參,經過一些宣告式的呼叫後,輸出一些結果變數。
從Terraform的程式碼層面來看,模組其實就是一個包含多個.tf或.tf.json檔案的目錄。任何一個Terraform專案,都是一個目錄,所以也都是一個模組,我們把它稱為根模組(Root Module)。而在它目錄下的其它模組,都是子模組。我們可以呼叫多個模組,也可以多次呼叫同一個子模組。在子模組中,也可以呼叫其它模組。這些特點,與函數無異。
呼叫模組有兩種方式,一種是在當前專案定義一個模組,另一種是引入外部的模組。而外部模組的方式也很多種,如Git的倉庫、壓縮檔案等。
我們先來使用第一種方式,參照當前專案中的模組。
子模組的功能很簡單,建立一個檔案,檔名有隨機字串,以避免衝突。寫入檔案的內容可以通過引數指定。
子模組:
定義入參:建立一個檔案叫variables.tf,專門用來定義入參:
variable "prefix" {
type = string
default = "pkslow"
description = "File name prefix"
}
variable "content" {
type = string
default = "www.pkslow.com"
description = "File content"
}
這裡輸入有兩個變數,都是字串型別,分別是檔名字首prefix和檔案內容context。
定義模組功能,主要設定這個模組用管理的資源,一般會放在main.tf檔案中,內容如下:
resource "random_string" "random" {
length = 6
lower = true
special = false
}
resource "local_file" "file" {
content = var.content
filename = "${path.root}/${var.prefix}.${random_string.random.result}.txt"
}
這裡定義了兩個resource,第一個是生成6位的隨機字串。第二個是生成一個檔案,第二個resource使用了輸入引數,還使用了第一個資源生成的結果。所以第二個resource是依賴於第一個的。輸入的變數參照方式為var.xxx
。
定義返回值:
可以不需要返回值,也可以定義一個或多個返回值。建立一個outputs.tf檔案,內容如下:
output "file_name" {
value = local_file.file.filename
}
它返回的是前面第二個resource中的值。
現在,模組random-file已經定義完成了。現在我們在根模組呼叫這個子模組。程式碼如下:
module "local-file" {
source = "./random-file"
prefix = "pkslow"
content = "Hi guys, this is www.pkslow.com\nBest wishes!"
}
這個source是被呼叫模組的地址。prefix
和content
都是入參,之前已經定義了。
在根模組也可以定義輸出變數:
output "fileName" {
value = module.local-file.file_name
}
這裡直接輸出子模組的檔名,也就是子模組的返回變數file_name。
apply
後通過terraform output
檢視輸出:
$ terraform output
fileName = "./pkslow.B2UwmR.txt"
我們說過模組是為了實現程式碼複用,Terraform允許一個模組被多次呼叫。我們修改根模組的呼叫程式碼:
module "pkslow-file" {
source = "./random-file"
prefix = "pkslow"
content = "Hi guys, this is www.pkslow.com\nBest wishes!"
}
module "larry-file" {
source = "./random-file"
prefix = "larrydpk"
content = "Hi guys, this is Larry Deng!"
}
這裡兩個呼叫的source都是一樣的,都呼叫了random-file
這個模組,只是入參不同。
根模組的輸出也修改一下:
output "pkslowPileName" {
value = module.pkslow-file.file_name
}
output "larryFileName" {
value = module.larry-file.file_name
}
執行apply
後output輸出結果為:
$ terraform output
larryFileName = "./larrydpk.txoV34.txt"
pkslowPileName = "./pkslow.WnJVMm.txt"
多次呼叫一個模組還有另一種方式就是迴圈呼叫,通過count
來實現,具體如下:
module "pkslow-file" {
count = 6
source = "./random-file"
prefix = "pkslow-${count.index}"
content = "Hi guys, this is www.pkslow.com\nBest wishes!"
}
這裡會呼叫6次子模組random-file
,下標索引為count.index
,它是從0開始的索引。
因此,執行後,會生成以下6個檔案:
pkslow-0.JBDuhH.txt
pkslow-1.Z6QmPV.txt
pkslow-2.PlCK5u.txt
pkslow-3.a70sWN.txt
pkslow-4.UnxYue.txt
pkslow-5.8bSNxg.txt
這裡根模組的輸出就需要修改了,它成了一個List,通過*
參照所有元素:
output "pkslowPileNameList" {
value = module.pkslow-file.*.file_name
}
通過for_each
也可以實現迴圈呼叫:
Map的情況:
resource "azurerm_resource_group" "rg" {
for_each = {
a_group = "eastus"
another_group = "westus2"
}
name = each.key
location = each.value
}
Set的情況:
resource "aws_iam_user" "the-accounts" {
for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
name = each.key
}
除了在本專案中定義並參照模組之外,還可以參照外部的模組。在官方的倉庫中已經有非常多的可重用的模組了,可以到上面查詢:https://registry.terraform.io/browse/modules
比如我參照了( https://registry.terraform.io/modules/matti/resource/shell/latest )這個模組:
module "echo-larry-result" {
source = "matti/resource/shell"
version = "1.5.0"
command = "cat ${module.larry-file.file_name}"
}
執行terraform get
會從倉庫下載模組:
$ terraform get
Downloading matti/resource/shell 1.5.0 for echo-larry-result...
- echo-larry-result in .terraform/modules/echo-larry-result
- larry-file in random-file
- pkslow-file in random-file
在.modules
目錄下可以檢視模組內容。
這個模組可以執行shell命令,並返回結果。我這裡執行的命令是讀取之前生成檔案的內容。輸出呼叫結果:
output "larryFileResult" {
value = module.echo-larry-result.stdout
}
執行結果如下:
larryFileName = "./.result/larrydpk.GfgMyh.txt"
larryFileResult = "Hi guys, this is Larry Deng!"
引入模組的來源很多:
非常方便。我們已經介紹過比較常用的前兩種了,其它更多細節可以參考:https://www.terraform.io/docs/language/modules/sources.html