《Terraform 101 從入門到實踐》 第五章 HCL語法

来源:https://www.cnblogs.com/larrydpk/archive/2023/02/11/17111017.html
-Advertisement-
Play Games

《Terraform 101 從入門到實踐》這本小冊在南瓜慢說官方網站和GitHub兩個地方同步更新,書中的示例代碼也是放在GitHub上,方便大家參考查看。 介紹了Terraform一些比較基礎的概念後,我們可以先瞭解一下Terraform的語法,也就是HCL的語法。 變數Variables 變數 ...


《Terraform 101 從入門到實踐》這本小冊在南瓜慢說官方網站GitHub兩個地方同步更新,書中的示例代碼也是放在GitHub上,方便大家參考查看。


介紹了Terraform一些比較基礎的概念後,我們可以先瞭解一下Terraform的語法,也就是HCL的語法。

變數Variables

變數是實現代碼復用的一種方式,同樣的代碼不同的變數往往會有不同的效果。而在Terraform里,有一個概念非常重要,就是變數都是從屬於模塊的。變數無法跨模塊引用。即在模塊A定義的變數X,無法在模塊B中直接引用。但父模塊的變數,可以作為子模塊的入參;而子模塊的輸出變數可以被父模塊獲取。

變數類型

從語言角度

跟任何編程語言一樣,變數都是有類型的,Terraform的變數類型從語言的角度可分為兩大類:基本類型和組合類型,具體如下:

基本類型:

  • 字元串string,如"pkslow.com"
  • 數字number,如3195.11
  • 布爾值bool,如true

組合類型:

  • 列表list(),如["dev", "uat", "prod"]
  • 集合set(),如set(...)
  • 映射map(),如{name="Larry", age="18"}
  • 對象object({name1=T1, name2=T2})
  • 元組tuple([T1,T2,T3...])

如果不想指定某個類型,可以用any來表示任意類型;或者不指定,預設為任意類型。

從功能角度

從功能角度來看,變數可以分為輸入變數、輸出變數和本地變數。

輸入變數是模塊接收外部變數的方式,它定義在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"
    }
  ]
}

輸出變數定義了一個模塊對外返回的變數,通過output塊來定義,如下:

output "instance_ip_addr" {
  value = aws_instance.server.private_ip
}

本地變數是模塊內定義且可引用的臨時變數,在locals塊中定義,如下:

locals {
  service_name = "forum"
  owner        = "Community Team"
}

輸入變數Input Variable

輸入變數是定義在variable塊中的,它就像是函數的入參。

定義輸入變數

定義variable有很多可選屬性:

  • 類型type:指定變數是什麼類型;如果沒有指定,則可以是任意類型;
  • 預設值default:變數的預設值,定義後可以不用提供變數的值,註意它的值的類型要與type對應上;
  • 說明description:說明這個變數的作用和用途;
  • 校驗validation:提供校驗邏輯來判斷輸入的變數是否合法;
  • 敏感性sensitive:定義變數是否敏感,如果是則不會顯示;預設為false
  • 可空nullable:如果為true則可以為空,否則不能。預設為true

所有屬性都顯性指定如下麵例子所示:

variable "env" {
  type        = string
  default     = "dev"
  description = "environment name"
  sensitive   = false
  nullable    = false
  validation {
    condition     = contains(["dev", "uat", "prod"], var.env)
    error_message = "The env must be one of dev/uat/prod."
  }
}

這個變數名為env,表示環境名,預設值為dev,這個值必須為devuatprod中的其中一個。如果輸出一個非法的值,會報錯:

$ terraform plan -var="env=sit"
╷
│ Error: Invalid value for variable
│ 
│   on input.tf line 1:
│    1: variable "env" {
│ 
│ The env must be one of dev/uat/prod.

使用輸入變數

只有定義了變數才可以使用,使用的方式是var.name。比如這裡定義了兩個變數envrandom_string_length

variable "env" {
  type        = string
  default     = "dev"
}

variable "random_string_length" {
  type    = number
  default = 10
}

則使用如下:

resource "random_string" "random" {
  length  = var.random_string_length
  lower   = true
  special = false
}

locals {
  instance_name = "${var.env}-${random_string.random.result}"
}

output "instance_name" {
  value = local.instance_name
}

傳入變數到根模塊

要從外部傳入變數到根模塊,有多種方式,常見的有以下幾種,按優先順序從低到高:

  • 環境變數export TF_VAR_image_id=ami-abc123

  • terraform.tfvars文件;

  • terraform.tfvars.json文件;

  • *.auto.tfvars*.auto.tfvars.json文件;

  • 命令行參數-var傳入一個變數;命令行參數-var-file傳入一個變數的集合文件;

在實踐中,最常用的還是通過命令行來傳入參數,因為一般需要指定不同環境的特定變數,所以會把變數放到文件中,然後通過命令行指定特定環境的主文件:

$ terraform apply -var="env=uat"
$ terraform apply -var-file="prod.tfvars"

prod.tfvars的內容如下:

env                  = "prod"
random_string_length = 12

我們可以定義dev.tfvarsuat.tfvarsprod.tfvars等,要使用不同環境的變數就直接改變文件名即可。

輸出變數Output Variable

有輸入就有輸出,輸出變數就像是模塊的返回值,比如我們調用一個模塊去創建一臺服務,那就要獲取服務的IP,這個IP事先是不知道,它是伺服器創建完後的結果之一。輸出變數有以下作用:

  • 子模塊的輸出變數可以暴露一些資源的屬性;
  • 根模塊的輸出變數可以在apply後輸出到控制台;
  • 根模塊的輸出變數可以通過remote state的方式共用給其它Terraform配置,作為數據源。

定義輸出變數

輸出變數需要定義在output塊中,如下:

output "instance_ip_addr" {
  value = aws_instance.server.private_ip
}

這個value可以是reource的屬性,也可以是各種變數計算後的結果。只要在執行apply的時候才會去計算輸出變數,像plan是不會執行計算的。

還可以定義輸出變數的一些屬性:

  • description:輸出變數的描述,說明清楚這個變數是幹嘛的;
  • sensitive:如果是true,就不會在控制台列印出來;
  • depends_on:顯性地定義依賴關係。

完整的定義如下:

output "instance_ip_addr" {
  value       = aws_instance.server.private_ip
  description = "The private IP address of the main server instance."
  sensitive   = false
  depends_on = [
    # Security group rule must be created before this IP address could
    # actually be used, otherwise the services will be unreachable.
    aws_security_group_rule.local_access,
  ]
}

引用輸出變數

引用輸出變數很容易,表達式為module.<module name>.<output name>,如果前面的輸出變數定義在模塊pkslow_server中,則引用為:module.pkslow_server.instance_ip_addr

本地變數Local Variable

本地變數有點類似於其它語言代碼中的局部變數,在Terraform模塊中,它的一個重要作用是避免重覆計算一個值。

locals {
  instance_name = "${var.env}-${random_string.random.result}-${var.suffix}"
}

這裡定義了一個本地變數instance_name,它的值是一個複雜的表達式。這時我們可以通過local.xxx的形式引用,而不用再寫複雜的表達式了。如下:

output "instance_name" {
  value = local.instance_name
}

這裡要特別註意:定義本地變數的關鍵字是locals塊,裡面可以有多個變數;而引用的關鍵字是local,並沒有s

一般我們是建議需要重覆引用的複雜的表達式才使用本地變數,不然太多本地變數就會影響可讀性。

對變數的引用

定義了變數就需要對其進行引用,前面的講解其實已經講過了部分變數的引用,這些把所有列出來。

類型 引用方式
資源Resources <Resource Type>.<Name>
輸入變數Input Variables var.<NAME>
本地變數Local Values local.<NAME>
子模塊的輸出 module.<Module Name>.<output Name>
數據源Data Sources data.<Data Type>.<Name>
路徑和Terraform相關 path.module:模塊所在路徑
path.root:根模塊的路徑
path.cwd:一般與根模塊相同,其它高級用法除外
terraform.workspace:工作區名字
塊中的本地變數 count.index:count迴圈的下標;
each.key/each.value:for each迴圈的鍵值;
self:在provisioner的引用;

上面都是單值的引用,如果是List或Map這種複雜類型,就要使用中括弧[]來引用。

aws_instance.example[0].id:引用其中一個元素;

aws_instance.example[*].id:引用列表的所有id值;

aws_instance.example["a"].id:引用key為a的元素;

[for value in aws_instance.example: value.id]:返回所有id為列表;

運算符

與其它語言一樣,Terraform也有運算符可以用,主要是用於數值計算和邏輯計算。以下運算符按優先順序從高到低如下:

  1. !取反,-取負
  2. *乘號,/除號,%取餘
  3. +加號,-減號
  4. >>=<<=:比較符號
  5. ==等於,!=不等於
  6. &&與門
  7. ||或門

當然,用小括弧可以改變這些優秀級,如(1 + 2) * 3

註意:對於結構化的數據比較需要註意類型是否一致。比如var.list == []按理說應該返回true,而list為空時。當[]實際表示是元組tuple([]),所以它們不匹配。可以使用length(var.list) == 0的方式。

條件表達式

條件表達式的作用是在兩個值之間選一個,條件為真則選第一個,條件為假則選第二個。形式如下:

condition ? true_value : false_value

示例如下:

env = var.env !="" ? var.env : "dev"

意思是給env賦值,如果var.env不為空就把輸入變數var.env的值賦給它,如果為空則賦預設值dev

for表達式

使用for表達式可以創建一些複雜的值,而且可以使用一些轉換和計算對值計算再返回。如將字元串列表轉化成大寫:

> [for s in ["larry", "Nanhua", "Deng"] : upper(s)]
[
  "LARRY",
  "NANHUA",
  "DENG",
]

可以獲取下標和值:

> [for i,v in ["larry", "Nanhua", "Deng"] : "${i}.${v}"]
[
  "0.larry",
  "1.Nanhua",
  "2.Deng",
]

對於Map的for表達式:

> [for k,v in {name: "Larry Deng", age: 18, webSite: "www.pkslow.com"} : "${k}: ${v}"]
[
  "age: 18",
  "name: Larry Deng",
  "webSite: www.pkslow.com",
]

通過條件過濾數據:

> [for i in range(1, 10) : i*3 if i%2==0]
[
  6,
  12,
  18,
  24,
]

動態塊Dynamic Block

動態塊的作用是根據變數重覆某一塊配置。這在Terraform是會遇見的。

resource "aws_elastic_beanstalk_environment" "tfenvtest" {
  name                = "tf-test-name"
  application         = "${aws_elastic_beanstalk_application.tftest.name}"
  solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"

  dynamic "setting" {
    for_each = var.settings
    content {
      namespace = setting.value["namespace"]
      name = setting.value["name"]
      value = setting.value["value"]
    }
  }
}

比如這裡的例子,就會重覆setting塊。重覆的次數取決於for_each後面跟的變數。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Java線程里:“中斷”就是指“終止”,與操作系統里的"中斷"、“異常”是完全不同的概念; 由於stop()方法過於暴力,可能導致資源回收無法風險、開銷過大等問題,此方法已過期,故Java中沒有強制中斷線程的手段;但可以調用interupt()、interupted()方法來向進程提出中斷請求,待進 ...
  • 聲明:文章來源於網路,如有侵權,請聯繫刪除 網頁即將載入 --網頁即將載入 if(網頁鏈接:find"url/.")then 停止載入() 進入子頁面("游覽",{鏈接=網頁鏈接}) end 載入本地網頁 載入本地網頁("file:///android_asset/drawable/index.ht ...
  • 這篇文章主要介紹分散式系統中的集中式結構,以及我們經常使用的三種基於集中式結構的解決方案:Google Borg、Kubernetes和Mesos。 ...
  • Java 平臺的基礎 I/O 類。它首先關註 I/O Streams,這是一個強大的概念, 可以大大簡化 I/O 操作。該課程還可以看到序列化,這使得程式可以將整個對象寫入流並再次讀取它們。 然後,該課程將查看 文件 I/O 和文件系統操作,包括隨機訪問文件。 I/O Streams 大多數都是講... ...
  • 對於Python新手來說,寫代碼很少考慮代碼的效率和簡潔性,因此容易造成代碼冗長、執行慢,這些都是需要改進的地方。本文是想通過幾個案列給新手一點啟發,怎樣寫python代碼更優雅。 大坑一:不喜歡使用高級數據結構 1.sets(集合) 很多新手忽視sets(集合)和tuple(元組)的強大之處 例如 ...
  • Spring Cloud Gateway 是 Spring Cloud 的一個全新項目,該項目是基於 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等響應式編程和事件流技術開發的網關,它旨在為微服務架構提供一種簡單有效的統一的 API 路由管理方式。① 身... ...
  • 1.gensim的安裝 可以使用如下命令安裝gensim conda install -i https://pypi.tuna.tsinghua.edu.cn/simple gensim==3.8.2 2.生成分詞列表 這一步已經有生成好的分詞列表可以忽略 項目列表: 點擊查看代碼 # coding ...
  • 各位技術大佬,大家好,我是練習時長兩年半的代碼練習生,Max,喜歡技術,後端和架構。 問題介紹 項目配置了多個功能變數名稱,如下,php 代碼中有獲取 $_SERVER['SERVER_NAME'] 的值。 server { server_name a.demo.com b.demo.com; ... } ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...