原簡體中文教程連結: Introduction.《Terraform入門教程》
這裡講的仍然是 HCL 的語法,但我們只講一些關鍵語法。如果讀者有興趣了解完整資訊可以存取 HCL 語法規約
參數賦值就是將一個值賦給一個特定的名稱:
image_id = "abc123"
等號前的識別符就是參數名,等號後的表達式就是參數值。參數賦值時 Terraform 會檢查類型是否符合。參數名稱是確定的,參數值可以是確定的字面量硬編碼,也可以是一組表達式,用以透過其他的值加以計算結果值。
一個區塊是包含一組其他內容的容器,例如:
resource "aws_instance" "example" {
ami = "abc123"
network_interface {
# ...
}
}
一個區塊有一個類型(上面的例子裡類型就是 resource)。每個區塊類型都定義了類型關鍵字後面要跟多少標籤,例如 resource 區塊規定了後面要跟兩個標籤-在例子裡就是 aws_instance
和 example
。一個區塊類型可以規定任意多個標籤,也可以沒有標籤,例如內嵌的 network_interface
區塊。
在塊類型及其後續標籤之後,就是塊體。塊體必須被包含在一對花括號中間。在區塊體中可以進一步定義各種參數和其他的區塊。
Terraform 規範定義了有限多個頂級區塊類型,也就是可以遊離任何其他區塊獨立定義在設定檔中的區塊。大部分的 Terraform 功能(例如 resource, variable, output, data 等)都是頂級區塊。
參數名稱、區塊類型名稱以及其他 Terraform 規格中定義的結構的名稱,例如 resource、variable 等,都是識別碼。
合法的識別碼可以包含字母、數字、底線 (_) 以及減號 (-)。標識符首字母不可以為數字。
若要了解完整的識別碼規範,請造訪 Unicode 標識符語法。
Terraform 支援三種註釋:
#
單行註釋,其後的內容為註釋//
單行註釋,其後的內容為註釋/*
和 */
,多行註釋,可以註解多行Terraform 設定檔必須始終使用 UTF-8 編碼。分隔符號必須使用 ASCII 符號,其他識別碼、註解以及字串字面量均可使用非 ASCII 字元。
Terraform 相容於 Unix 風格的換行符以及 Windows 風格的換行符,但理想狀態下應使用 Unix 風格換行符。
在前面的例子中,我們在程式碼中都是使用字面量硬編碼的,如果我們想要在建立、修改基礎設施時動態傳入一些值呢?比如說在程式碼中定義 Provider 時用變數取代硬編碼的存取密鑰,或是由建立基礎架構的使用者來決定建立什麼樣尺寸的主機?我們需要的是輸入變數。
如果我們把一組 Terraform 程式碼想像成一個函數,那麼輸入變數就是函數的入參。輸入變數以 variable 區塊進行定義:
variable "image_id" {
type = string
}
variable "availability_zone_names" {
type = list(string)
default = ["us-west-1a"]
}
variable "docker_ports" {
type = list(object({
internal = number
external = number
protocol = string
}))
default = [
{
internal = 8300
external = 8300
protocol = "tcp"
}
]
}
這些都是合法的輸入參數定義。緊跟 variable
關鍵字的就是變數名。在一個 Terraform 模組(同一個資料夾中的所有 Terraform 程式碼文件,不包含子資料夾)中變數名稱必須是唯一的。我們在程式碼中可以透過 var.<NAME>
的方式引用變數的值。有一組關鍵字不可以被用來當作輸入變數的名字:
輸入變數只能在宣告該變數的目錄下的程式碼中使用。
輸入變數區塊中可以定義一些屬性。
可以在輸入變數區塊中透過 type
定義類型,例如:
variable "name" {
type = string
}
variable "ports" {
type = list(number)
}
定義了類型的輸入變數只能被賦予符合類型約束的值。
預設值定義了當 Terraform 無法獲得一個輸入變數得到值的時候會使用的預設值。例如:
variable "name" {
type = string
default = "John Doe"
}
當 Terraform 無法透過其他途徑獲得 name 的值時,var.name
的值為 "John Doe"
。
可以在輸入變數中定義一個描述,簡單地向呼叫者描述該變數的意義和用法:
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
}
如果在執行 terraform plan
或是 terraform apply
時 Terraform 不知道某個輸入變數的值,Terraform 會在命令列介面上提示我們為輸入變數設定一個值。例如上面的輸入變數程式碼,執行 terraform apply
時:
$ terraform apply
var.image_id
The id of the machine image (AMI) to use for the server.
Enter a value:
為了使的程式碼的使用者能夠準確地理解輸入變數的意義和用法,我們應該站在使用者而非程式碼維護者的角度編寫輸入變數的描述。描述並不是註解!
輸入變數的斷言是 Terraform 0.13.0 開始引入的新功能,在過去,Terraform 只能用類型約束確保輸入參數的類型是正確的,曾經有不少人試圖透過奇技淫巧來實現更加複雜的變量校驗斷言。如今 Terraform 終於正式加入了相關的功能。
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
validation {
condition = length(var.image_id) > 4 && substr(var.image_id, 0, 4) == "ami-"
error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
}
}
condition 參數是一個 bool 類型的參數,我們可以用一個表達式來定義如何界定輸入變數是合法的。當 contidion 為 true 時輸入變數合法,反之不合法。condition 表達式中只能透過 var.\ 引用目前定義的變量,並且它的計算不能產生錯誤。
假如表達式的計算產生一個錯誤是輸入變數驗證的一種判定手段,那麼可以使用 can 函數來判定表達式的執行是否拋錯。例如:
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
validation {
# regex(...) fails if it cannot find a match
condition = can(regex("^ami-", var.image_id))
error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
}
}
在上述例子中,如果輸入的 image_id
不符合正規表示式的要求,那麼 regex
函數呼叫就會拋出一個錯誤,這個錯誤就會被 can
函數捕獲,輸出 false
。
condition
表達式如果為 false
,Terraform 會傳 error_message
回中定義的錯誤訊息。error_message
應該完整描述輸入變數校驗失敗的原因,以及輸入變數的合法約束條件。
此功能於 Terraofrm v0.14.0 開始引入。
將變數設為 sensitive
可以防止我們在設定檔中使用變數時 Terraform 在 plan
和 apply
指令的輸出中展示與變數相關的值。
Terraform 仍然會將敏感資料記錄在狀態檔案中,任何可以存取狀態檔案的人都可以讀取到明文的敏感資料值。
宣告一個變數包含敏感資料值需要將 sensitive
參數設定為 true
:
variable "user_information" {
type = object({
name = string
address = string
})
sensitive = true
}
resource "some_resource" "a" {
name = var.user_information.name
address = var.user_information.address
}
任何使用了敏感變數的表達式都將被視為敏感的,因此在上面的範例中, resource “some_resource” “a”
的兩個參數也將在計劃輸出中被隱藏:
Terraform will perform the following actions:
# some_resource.a will be created
+ resource "some_resource" "a" {
+ name = (sensitive)
+ address = (sensitive)
}
Plan: 1 to add, 0 to change, 0 to destroy.
在某些情況下,我們會在巢狀區塊中使用敏感變量,Terraform 可能會將整個區塊視為敏感的。這發生在那些包含有要求值是唯一的內嵌區塊的資源中,公開這種內嵌區塊的部分內容可能會暗示兄弟區塊的內容。
# some_resource.a will be updated in-place
~ resource "some_resource" "a" {
~ nested_block {
# At least one attribute in this block is (or was) sensitive,
# so its contents will not be displayed.
}
}
Provider 還可以將資源屬性宣告為敏感屬性,這將導致 Terraform 將其從常規輸出中隱藏。
如果打算使用敏感值作為輸出值的一部分,Terraform 會要求您將輸出值本身標記為敏感值,以確認確實打算將其匯出。
sensitive
變數是一個以設定檔為中心的概念,值會毫無混淆地傳送給 Provider。如果該值包含在錯誤訊息中,則 Provider 報錯時可能會暴露該值。例如,即使「foo」 是敏感值,Provider 也可能傳回下列錯誤:"Invalid value 'foo' for field"
如果將資源屬性用作、或是作為 Provider 定義的資源 ID 的一部分,則 apply
將公開該值。在下面的範例中,前綴屬性已設定為 sensitive
變量,但隨後該值(“jae”)作為資源ID 的一部分公開:
# random_pet.animal will be created
+ resource "random_pet" "animal" {
+ id = (known after apply)
+ length = 2
+ prefix = (sensitive)
+ separator = "-"
}
Plan: 1 to add, 0 to change, 0 to destroy.
...
random_pet.animal: Creating...
random_pet.animal: Creation complete after 0s [id=jae-known-mongoose]
此功能自 Terraform v1.1.0 開始被引入
輸入變數的 nullable
參數控制模組呼叫者是否可以將 null 指派給變數。
variable "example" {
type = string
nullable = false
}
nullable
的預設值為 true
。當 nullable
為 true
時,null
是變數的有效值,且模組程式碼必須始終考慮變數值為 null
的可能性。將 null
作為模組輸入參數傳遞將覆蓋輸入變數上定義的預設值。
將 nullable
設為 false
可確保變數值在模組內永遠不會為空。如果 nullable
為 false
且輸入變數定義有預設值,則當模組輸入參數為 null
時,Terraform 將使用預設值。
nullable
參數僅控制變數的直接值可能為 null
的情況。對於集合或物件類型的變量,例如列表或對象,呼叫者仍然可以在集合元素或屬性中使用null,只要集合或物件本身不為 null
。
對輸入變數賦值有幾種途徑,一種是在呼叫 terraform plan
或是 terraform apply
指令時以參數的形式傳入:
$ terraform apply -var="image_id=ami-abc123"
$ terraform apply -var='image_id_list=["ami-abc123","ami-def456"]'
$ terraform plan -var='image_id_map={"us-east-1":"ami-abc123","us-east-2":"ami-def456"}'
可以在一條指令中使用多個 -var
參數。
第二種方法是使用參數檔。參數檔的後綴名可以是 .tfvars
或是 .tfvars.json
。.tfvars
檔案使用 HCL 語法,.tfvars.json
使用 JSON 語法。
以 .tfvars
為例,參數檔中以 HCL 程式碼對需要賦值的參數進行賦值,例如:
image_id = "ami-abc123"
availability_zone_names = [
"us-east-1a",
"us-west-1c",
]
後綴名為 .tfvars.json
的檔案用一個 JSON 物件來對輸入變數賦值,例如:
{
"image_id": "ami-abc123",
"availability_zone_names": ["us-west-1a", "us-west-1c"]
}
呼叫 terraform 指令時,透過 -var-file
參數指定要使用的參數文件,例如:
terraform apply -var-file="testing.tfvars"
terraform apply -var-file="testing.tfvars.json"
有兩種情況,你無需指定參數檔:
terraform.tfvars
或是 terraform.tfvars.json
的文件.auto.tfvars
或是 .auto.tfvars.json
的文件可以透過設定名為 TF_VAR_<NAME>
的環境變數為輸入變數賦值,例如:
$ export TF_VAR_image_id=ami-abc123
$ terraform plan
...
在環境變數名稱大小寫敏感的作業系統上,Terraform 要求環境變數中的 \ 與 Terraform 程式碼中定義的輸入變數名稱大小寫完全一致。
環境變數傳值非常適合在自動化管線中使用,尤其適合用來傳遞敏感數據,類似密碼、存取金鑰等。
在前面介紹斷言的例子中我們看到過,當我們從命令列介面執行 terraform 操作,Terraform 無法透過其他途徑取得一個輸入變數的值,而該變數也沒有定義預設值時,Terraform 會進行最後的嘗試,在互動介面上要求我們給出變數值。
當上述的賦值方式同時存在時,同一個變數可能會被賦值多次。Terraform 會使用新值覆蓋舊值。
Terraform 載入變數值的順序是:
terraform.tfvars
文件(如果存在的話)terraform.tfvars.json
文件(如果存在的話).auto.tfvars
或 .auto.tfvars.json
文件,以字母順序排序處理-var
或是 -var-file
命令列參數傳遞的輸入變量,按照命令列參數中定義的順序加載假如以上方式皆未能成功對變數賦值,那麼 Terraform 會嘗試使用預設值;對於沒有定義預設值的變量,Terraform 會採用互動介面方式要求使用者輸入一個。對於某些 Terraform 指令,如果執行時帶有 -input=false
參數停用了互動介面傳值方式,那麼就會報錯。
透過參數檔傳值時,可以直接使用 HCL 或 JSON 語法對複雜型別傳值,例如 list 或 map。
對於某些場景下必須使用 -var
命令列參數,或是環境變數傳值時,可以用單引號引用 HCL 語法的字面量來定義複雜類型,例如:
export TF_VAR_availability_zone_names='["us-west-1b","us-west-1d"]'
由於採用這種方法需要手動處理引號的轉義,所以這種方法比較容易出錯,複雜類型的傳值建議盡量通過參數檔。
原簡體中文教程連結: Introduction.《Terraform入門教程》