## HashiCorp Terraform Associate 認證準備

在現代雲端環境中,基礎設施即程式碼 (IaC) 已成為不可或缺的技能。Terraform 作為領先的 IaC 工具,其 Associate 認證也越來越受到重視。這篇文章將作為您的 Terraform Associate 認證準備,帶您瞭解考試重點,並提供實務操作的技巧與訣竅。

## 瞭解 IaC 的核心概念

IaC 的核心概念是將基礎設施的組態和管理,如同軟體開發一樣,透過程式碼來定義和自動化。這相較於傳統的手動操作,有著顯著的優勢:

* **一致性:** 透過程式碼,確保每次佈署的基礎設施都完全相同,避免人為錯誤。
* **可重複性:** 基礎設施的佈署過程可以被輕鬆地重複執行,提高效率。
* **版本控制:** 程式碼可以被版本控制系統管理,方便追蹤變更和回復。
* **可擴充套件性:** IaC 可以輕鬆地擴充套件基礎設施的規模,滿足業務需求。

```mermaid
graph LR
    C[C]
A[定義基礎設施程式碼] --> B(版本控制)
B --> C{佈署基礎設施}
C --成功--> D[一致與可重複的環境]
C --失敗--> E[回復至先前版本]

上面的 Mermaid 流程圖展示了 IaC 的基本流程,從定義程式碼、版本控制到佈署和回復,清晰地呈現了 IaC 的優勢。

Terraform 的獨特優勢

Terraform 作為一個跨平台、多雲端的 IaC 工具,擁有許多獨特的優勢:

  • 多雲端支援: Terraform 可以管理不同雲端供應商的資源,例如 AWS、Azure 和 GCP,實作真正的多雲端管理。
  • 狀態管理: Terraform 使用狀態檔案追蹤基礎設施的狀態,方便管理和更新。
  • 模組化設計: Terraform 使用模組來封裝可重複使用的程式碼,提高程式碼的可維護性和重用性。

Terraform CLI 的使用

Terraform CLI 提供了豐富的命令,方便管理基礎設施:

  • terraform init: 初始化工作目錄,下載必要的外掛。
  • terraform plan: 預覽將要執行的變更。
  • terraform apply: 執行變更,佈署基礎設施。
  • terraform destroy: 銷毀基礎設施。
terraform init
terraform plan -out=tfplan
terraform apply tfplan

以上程式碼片段展示了 Terraform 的基本工作流程,包含初始化、規劃和應用變更。-out=tfplan 引數將規劃的變更儲存到檔案中,方便後續應用。

Terraform 模組的應用

Terraform 模組可以將可重複使用的程式碼封裝起來,方便在不同的專案中重複使用。

module "example" {
  source = "./modules/example"
  input_variable = "example_value"
}

這個程式碼片段展示瞭如何使用本地模組。source 引數指定模組的來源,input_variable 引數則傳遞輸入變數給模組。

狀態管理的重要性

Terraform 使用狀態檔案追蹤基礎設施的狀態,這對於管理和更新基礎設施至關重要。建議將狀態檔案儲存在遠端,例如雲端儲存服務中,以便團隊協作和狀態分享。

這篇文章涵蓋了 Terraform Associate 認證的關鍵概念和實務操作技巧,希望能幫助您順利透過認證考試。記住,熟練掌握 Terraform CLI 和模組的使用,以及理解狀態管理的重要性,是成為 Terraform 工作者的關鍵。持續練習和探索,您將在 IaC 領域取得更大的成功。

HashiCorp Terraform Associate 認證

這篇文章將引導你準備 HashiCorp Terraform Associate 認證考試。無論你是 Terraform 的愛好者、開發人員,或是想提升技能並獲得認證的 IT 專業人士,這篇文章都將提供你所需的知識和實踐指導。

關於玄貓(BlackCat)

玄貓(BlackCat)是一位擁有國際技術經驗的台灣技術工作者與作者,專注於雲端運算、自動化技術和軟體開發等領域。玄貓擅長以深入淺出的方式解釋複雜技術,並結合個人經驗提供獨到見解。

關於 Terraform Associate 認證

Terraform Associate 認證旨在評估 IT、DevOps 和維運人員在基礎設施即程式碼(IaC)和 HashiCorp Terraform 方面的基礎知識。本認證並不要求你成為 Terraform 工作者,而是著重於測試你對核心概念和實踐的理解。

考試準備

除了研讀這篇文章,動手實踐至關重要。我們鼓勵你開啟程式碼編輯器,嘗試不同的組態,並探索 Terraform 的狀態檔案。親自動手操作能加深你對 Terraform 的理解,並提升你的實務技能。

前置技能

在開始學習 Terraform 之前,建議你具備以下基礎技能:

  • 終端環境的基本操作
  • 對於本地和雲端基礎設施元件的基本理解
  • 熟悉一種指令碼語言
  • 熟悉基本的開發概念
  • 存取雲端供應商

產品版本

這篇文章中的範例和指令碼根據 Terraform 0.13 版本。 我們已將 0.13 版本引入的新功能納入其中,例如模組功能的擴充套件、變數驗證和自動下載第三方供應商。

考試目標

HashiCorp 公佈了一系列考試目標,涵蓋了 Terraform Associate 認證所需的知識和技能。以下列出主要目標,最新版本請參考官方考試目標頁面。

  1. 理解 IaC 概念:IaC 包含核心佈署模式,相較於傳統方法,它提供了許多優勢。
  2. 理解 Terraform 的用途:Terraform 可用於管理多雲環境,並利用其供應商模型和狀態儲存來維護基礎設施。
  3. 理解 Terraform 基礎知識:Terraform 建立於一些基本概念之上,例如安裝、外掛、供應商和組態器。
  4. 使用 Terraform CLI:Terraform 主要由 CLI 驅動,我們將探討一些在 initplanapply 工作流程之外的命令。
  5. 與 Terraform 模組互動:模組將常見的佈署模式抽象成可重複使用的程式碼塊。
  6. 瀏覽 Terraform 工作流程:基礎設施的佈署遵循 write->plan->create 的核心工作流程來管理生命週期。
  7. 實作和維護狀態:Terraform 管理的狀態資料使應用程式能夠管理已佈署基礎設施的生命週期。
  8. 讀取、生成和修改組態:Terraform 佈署的組態由變數、資源、資料源和機密訊息等組成。
  graph LR
    C[C]
A[撰寫組態] --> B(plan)
B --> C{apply}
C --> D[基礎設施]

上圖展示了 Terraform 的核心工作流程:首先撰寫組態檔案,然後使用 terraform plan 預覽變更,最後使用 terraform apply 佈署基礎設施。

在接下來的文章中,我們將探討每個目標,並提供實踐範例和玄貓的專業見解,幫助你充分準備 Terraform Associate 認證考試。

深入淺出 IaC:基礎概念與 Terraform 的優勢

身為一個在各個領域都有涉略的技術工作者,我發現 Infrastructure as Code (IaC) 的概念越來越重要。IaC 是一種透過機器可讀的格式來定義和組態基礎設施資源的實踐方式。這些資源可以包含實體伺服器、虛擬機器、網路資源、儲存空間,甚至是資料函式庫服務。雖然 IaC 常用於雲端環境,但它並非雲端專屬。只要你的基礎設施管理系統具備程式設計介面,就可以參與 IaC。

  graph LR
    B[B]
    A[基礎設施資源] --> B{IaC}
    B --> C[機器可讀格式]
    C --> D[自動化組態]

上圖展示了 IaC 的基本概念:透過機器可讀的格式描述基礎設施資源,並實作自動化組態。

IaC 的格式可以是宣告式(定義預期結果)或指令式(定義組態過程)。像 Terraform 這樣的宣告式組態方案,專注於佈署的最終狀態,並依賴解釋引擎來建立和組態實際資源。而指令式組態方案,例如批次指令碼,則專注於實際的組態過程,並可能參考包含設定和組態值的檔案。

我認為 IaC 的核心精神在於透過機器可讀的程式碼來定義和組態基礎設施,而不是透過入口網站、命令列或 API 手動組態。如果命令或過程是由人員手動執行,那就不是 IaC。

IaC 的優勢:一致性、可重複性和效率

使用 IaC 的優勢可以歸納為幾個關鍵類別:一致性、可重複性和效率。

透過將基礎設施定義為程式碼,可以確保在不同環境中佈署的一致性。當使用相同的程式碼來建立測試和正式環境的基礎設施時,維運團隊就不必再擔心兩個環境是否一致。在雲端環境中,使用相同的程式碼在多個區域佈署基礎設施,可以確保每個區域的設定一致。

基礎設施中有許多常見的元件和佈署模式。使用 IaC 可以將這些模式定義一次,並多次使用。例如,為新的應用程式佈署 Web 伺服器可能是一種常見模式。透過在程式碼中定義 Web 伺服器佈署,每個需要一組 Web 伺服器的新佈署都可以重複使用它。此外,如果需要更改這些 Web 伺服器的組態,可以更新 Web 伺服器佈署程式碼,並將其推播至每個應用程式環境。

  graph LR
    A[程式碼定義] --> B(Web 伺服器佈署)
    B --> C[測試環境]
    B --> D[正式環境]

此圖說明如何使用 IaC 中的程式碼定義來佈署 Web 伺服器到不同環境,確保一致性。

將基礎設施定義為程式碼,可以讓維運團隊與開發團隊更緊密地整合。基礎設施的組態過程可以整合到現有的應用程式開發流程中,建立一個貫穿開發、測試、預發和正式環境的一致與可重複的流程。透過自動化並且開發團隊整合,可以提高效率。

IaC 提升了一致性、可重複性和效率,同時降低了風險和成本。這對於現代軟體開發和維運至關重要,尤其是在快速迭代和頻繁佈署的環境中。

Terraform 的狀態管理:深入解析其優勢

Terraform 使用狀態檔案來追蹤管理的資源,這對於基礎設施即程式碼至關重要。當您建立資源(例如 AWS 中的 EC2 執行個體)時,Terraform 會在狀態檔案中建立一個條目,將資源的後設資料(例如 instance-id)對映到條目中的鍵/值對。追蹤資源後設資料有多種功能:

冪等性(Idempotence)

每次執行 terraform planterraform apply 時,Terraform 會檢查實際環境是否與設定檔比對。只有需要更改的資源才會更新,其他資源保持不變。如果設定沒有更改,Terraform 不會對環境進行任何更改。狀態檔案讓 Terraform 能夠將設定檔中定義的資源對映到實際存在的資源,確保操作的冪等性。

依賴關係(Dependencies)

假設您從設定檔中移除了一個子網路和一個 EC2 執行個體。Terraform 會在下次執行 terraform apply 時嘗試銷毀這些資源。直覺上,您知道必須先移除 EC2 執行個體,然後再移除子網路,因為執行個體依賴於子網路。Terraform 如何判斷這一點?在建立資源時,EC2 執行個體參考了子網路,因此 Terraform 在構建圖形時發現了依賴關係。當兩個資源都從設定檔中移除後,Terraform 無法透過構建圖形來推斷依賴關係。答案是:狀態檔案! Terraform 在狀態檔案中維護一個依賴關係列表,以便正確處理設定檔中不再存在的依賴關係。

效能(Performance)

狀態檔案代表 Terraform 所理解的目前世界狀態。在規劃更改時,Terraform 需要檢視資源及其屬性以確定是否需要更改。例如,EC2 執行個體是否需要新的後設資料標籤?Terraform 可以檢查狀態檔案中 EC2 執行個體的 tags 屬性並快速做出決策。雖然 Terraform 可以在每次規劃執行時直接查詢資源,但隨著基礎設施規模的增長,規劃的效能會迅速下降。

預設情況下,Terraform 會在每次規劃執行前重新整理狀態,但為了提高效能,可以使用 --refresh=false 引數讓 Terraform 跳過重新整理。 -target 引數可用於指定要重新整理的特定資源,而不會觸發完整狀態重新整理。可以根據需要定期從實際環境重新整理狀態,以跟上更改,而無需在每次規劃期間進行完整掃描。

需要注意的是,選擇不重新整理狀態意味著您的基礎設施佈署的實際情況可能與狀態檔案中的內容不符。這可能會導致應用規劃時出現不一致的結果,或完全失敗。不重新整理狀態的風險應與任何效能改進相平衡。

協作(Collaboration)

狀態檔案會追蹤已應用設定的版本,並支援在更新期間鎖定狀態。結合將狀態儲存在遠端共用位置的功能,團隊能夠協作進行佈署而不會覆寫彼此的工作。

Terraform 基礎:安裝、Provider 和 Provisioner

在開始使用 Terraform 之前,您需要將其安裝到某個位置。如果沒有使用各種 Provider,您也無法做很多事情,這些 Provider 讓 Terraform 能夠與雲端供應商、平台服務、資料中心應用程式等進行通訊。我們還將介紹 Provisioner 以及何時使用它們。您可能會發現答案與您的直覺相反!

Terraform 和 Provider 的安裝和版本控制

Terraform

Terraform 使用 Golang 編寫,並編譯為適用於多個作業系統的單一二進位制檔案。沒有複雜的安裝指令碼或動態連結程式函式庫列表。您不需要使用 MSI、rpm 或 dpm 安裝它。可執行二進位制檔案位於 zip 檔案中。Terraform 支援 Windows、macOS、Linux、FreeBSD、OpenBSD 和 Solaris。

要在任何支援的作業系統上安裝 Terraform:

  1. 找到適用於您的作業系統型別的 Terraform 套件並下載。Terraform 以單個 zip 檔案分發。
  2. 下載 Terraform 後,將套件解壓縮到您選擇的目錄。Terraform 以名為 terraform 的單一二進位制檔案執行。套件中的任何其他檔案都可以安全移除,Terraform 仍然可以正常運作。
  3. 要從任何路徑執行 Terraform,您可以修改 PATH 環境變數以包含 Terraform 二進位制檔案所在的目錄。
    1. 如何在 Linux 和 Mac 上設定 $PATH
    2. 如何在 Windows 上設定 PATH

Providers

Terraform 使用的資源和資料來源都是透過 Provider 系統啟用的。Provider 是一個可執行的外掛程式,其中包含與其編寫的服務的 API 互動所需的程式碼。通常,這包括驗證服務、管理資源和存取資料來源的方法。

Provider 可以在設定檔中明確定義,也可以由使用 Provider 的資源或資料來源隱式定義。Provider 區塊中的實際引數因 Provider 而異,但所有 Provider 都支援 versionalias 後設引數。稍後會詳細介紹這些內容。

Azure Provider 區塊範例如下:

provider azurerm {
  version     = "=1.41.0"
  tenant_id   = var.tenant_id
  subscription = var.subscription_id
}

對於 Azure Provider,驗證資訊可以透過環境變數或 Azure CLI 的快取憑證提供。一般最佳實務是避免將機密資訊(例如憑證)硬編碼到 Terraform 設定檔中。

version 引數用於將 Provider 限制為特定版本或版本範圍,以防止下載可能包含重大更改的新 Provider。如果未指定版本,Terraform 將在初始化期間自動下載最新的 Provider。雖然您可以在 Provider 區塊中指定 Provider 的版本,但 HashiCorp 建議您為 Terraform 設定建立 required_providers 區塊,如下所示:

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=1.41.0"
    }
  }
}

required_providers 區塊是在 Terraform 0.12 中引入的,語法從 Terraform 0.13 版開始更新。上面的範例使用包含 source 引數的較新語法。您可能會看到較舊的語法,它只是 Provider 名稱和版本。

(圖表)

  graph LR
    C[C]
A[Terraform] --> B(Provider)
B --> C{Cloud Providers}
C --> D[AWS]
C --> E[Azure]
C --> F[GCP]

上面的 圖表展示了 Terraform 與不同雲端供應商之間的關係。Terraform 透過 Provider 與 AWS、Azure 和 GCP 等雲端供應商互動。

玄貓解說 Terraform 的 Provider 設定與外掛架構

在 Terraform 的世界裡,Provider 就像是一座橋樑,連線著你的設定檔與各個雲端平台或服務供應商。這一篇,玄貓要帶你深入瞭解如何設定 Provider 的版本,以及 Terraform 外掛式架構的精妙之處。

設定 Provider 版本:告別單獨設定的煩惱

以往往,我們需要為每個 Provider 的例項設定版本,這在複雜的組態中簡直是場噩夢。現在,required_providers 區塊橫空出世,它能一次設定所有 Provider 例項的版本,包括子模組,更新版本也變得輕而易舉。

設定版本號的方法也很多樣,以下是一些常見的用法:

  • >= 1.41.0:大於或等於指定版本。
  • <= 1.41.0:小於或等於指定版本。
  • ~> 1.41.0:這個比較特別,表示 1.41.X 範圍內的任何版本。
  • >= 1.20, <= 1.41:1.20 到 1.41 之間的任何版本(含)。

~> 這個用法最常見,它能讓你保持在同一個主要版本,同時允許次要版本更新。例如,假設 Azure Provider 在 2.0 版本有重大更新,設定版本為 ~> 1.0 就能讓你使用所有 1.X 版本的更新,同時避免升級到 2.0。

外掛式架構:小巧、安全又好除錯

Terraform 的核心是一個單一執行檔,包含解析和佈署設定檔所需的元件。但與各個供應商互動的程式碼則是由外掛提供的。每個外掛都是一個獨立的程式,透過 RPC 介面與 Terraform 核心通訊。

早期的 Terraform 將許多 Provider 的程式碼直接封裝進核心執行檔,導致檔案過大,每次 Provider 更新都得重新發布 Terraform。後來,HashiCorp 改用外掛式架構,讓 Provider 可以獨立更新,同時也讓 Terraform 核心更精簡、更安全,除錯也更容易。

外掛式架構明確區分了 Terraform 的核心功能和外掛的功能,讓開發和維護更加清晰。

多個 Provider 的使用:不同 Provider 與多例項

在實際應用中,我們經常需要使用多個 Provider,甚至同一個 Provider 的多個例項。

不同 Provider 的使用

即使是最基本的設定,也可能用到多個不同的 Provider。例如,使用 random Provider 產生隨機數來命名 S3 Bucket,同時使用 aws Provider 建立 S3 Bucket 資源。

同一 Provider 的多例項

有時,你需要同一個 Provider 的多個例項。例如,AWS Provider 是區分割槽域的,如果你想在多個區域建立資源,就需要多個 aws Provider 例項。

所有 Provider 都支援 alias 引數,讓你為 Provider 指定別名。在建立資源時,你可以指定要使用的 Provider 別名。

provider "aws" {
  region = "us-east-1"
}

provider "aws" {
  region = "us-west-2"
  alias  = "west"
}

resource "aws_instance" "example" {
  provider = aws.west
  # ... other configurations
}

在這個例子中,EC2 例項會建立在 us-west-2 區域,因為我們在資源區塊中指定了 aws.west 這個 Provider。

如果沒有指定 Provider 別名,Terraform 會尋找沒有別名的 Provider 並使用它。

在模組中使用 Provider 別名,語法如下:

module "vpc" {
  source    = "terraform-aws-modules/vpc/aws"
  providers = {
    aws = aws.west
  }
}

這是因為模組可能包含多個 Provider,所以我們需要提供一個對映,以 Provider 名稱為鍵,完整別名為值。

Terraform 如何尋找和取得 Provider:0.13 版本的革新

在 0.13 版本之前,Terraform Provider 分為 HashiCorp 發布的和第三方發布的。HashiCorp 發布的 Provider 會在初始化時自動下載,而第三方 Provider 需要放在指定的外掛目錄中。

0.13 版本之後,Terraform 可以從公共或私有倉函式庫自動下載 Provider。官方公共倉函式庫位於 registry.terraform.io,包含官方、驗證和社群三種型別的 Provider。

透過在 terraform 區塊中使用 required_providers 區塊,可以增加 Provider:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

每個 Provider 都有一個本地名稱,可以在設定檔中使用。source 可以是任何公共或私有倉函式庫,格式為 hostname/organization/provider。如果省略 hostname,Terraform 預設使用 registry.terraform.io

總之,瞭解 Provider 的設定和外掛式架構,能讓你更有效率地使用 Terraform,輕鬆管理複雜的基礎設施。記住玄貓的這些技巧,讓你的 Terraform 之旅更加順暢!

在建構基礎設施即程式碼 (IaC) 的過程中,Terraform Provisioner 看似提供了便捷的途徑,讓我們能在資源建立後執行特定指令碼或操作。然而,根據個人經驗,我發現 Provisioner 實際上潛藏著許多陷阱,可能破壞 Terraform 的宣告式和冪等性模型。

Provisioner 的使用場景與問題

Provisioner 主要應用於以下三種場景:

  1. 載入資料到虛擬機器: 例如,將設定檔或應用程式佈署到新建立的伺服器。
  2. 引導虛擬機器使用設定管理工具: 例如,安裝 Chef、Puppet 或 Salt 等工具。
  3. 在本機系統儲存資料: 例如,將產生的金鑰或憑證儲存到本地檔案系統。

然而,Provisioner 的執行並非原子性或冪等性的。Terraform 無法像追蹤其他資源一樣追蹤 Provisioner 的結果和狀態,這可能導致難以預測的行為和錯誤。

  graph LR
    B[B]
    No[No]
    Yes[Yes]
A[資源建立] --> B{Provisioner 執行成功?}
B -- Yes --> C[資源建立完成]
B -- No --> D[資源 tainted]

remote-execlocal-exec 的迷思

remote-exec 允許透過 WinRM 或 SSH 連線到遠端機器執行指令碼。然而,這種方式需要機器接受遠端連線,存在安全風險。更有效率的做法是利用雲端供應商提供的工具,例如 AWS 的 user_data 或 Azure 的 custom_data,在建立資源時直接傳遞資料。

local-exec 則是在本機執行指令碼。雖然在某些情況下,本地指令碼是唯一的選擇,但通常可以找到更符合 Terraform 精神的替代方案。例如,使用 Local Provider 可以與本地檔案系統互動,避免使用 local-exec

remote-exec 的替代方案

以下程式碼片段展示瞭如何在 AWS 中使用 user_data 傳遞資料,避免使用 remote-exec

resource "aws_instance" "example" {
  # ... other configurations ...

  user_data = <<EOF
#!/bin/bash
echo "Hello from user_data!" > /tmp/message.txt
EOF
}

這段程式碼定義了一個 AWS EC2 執行個體,並使用 user_data 屬性傳遞一個 Bash 指令碼。當執行個體啟動時,該指令碼會在 /tmp/message.txt 檔案中寫入 “Hello from user_data!"。

最佳實務:避免使用 Provisioner

HashiCorp 官方強烈建議盡可能避免使用 Provisioner,除非絕對必要。我個人也認同這個觀點。以下是一些替代方案:

  • 使用組態管理工具: Chef、Puppet、Ansible 等工具更適合管理伺服器組態。
  • 建立自定義映像: 預先安裝所需軟體和設定的自定義映像可以簡化佈署流程。
  • 利用雲端供應商提供的工具: 使用 user_datacustom_data 等功能傳遞資料。
  • 使用 Null Resource Provisioner: 如果真的需要在 Terraform 中執行一些操作,可以考慮使用 Null Resource Provisioner,並搭配 local-execremote-exec。這樣可以更精確地控制 Provisioner 的執行時機,並避免汙染資源。

Terraform Provisioner 雖然看似方便,但實際上存在許多問題。在設計 IaC 架構時,應優先考慮其他更穩定、更符合 Terraform 精神的方案。善用組態管理工具、自定義映像和雲端供應商提供的工具,可以避免 Provisioner 帶來的陷阱,開發更健壯、更高效的 IaC 流程。

Terraform CLI 的進階應用:格式化程式碼及其他

在探討 Terraform 核心工作流程之前,我們先來瞭解 Terraform 命令列介面(CLI)的一些進階應用,特別是那些在核心工作流程之外的功能。雖然 HashiCorp 官方檔案將 CLI 的介紹放在核心工作流程之前,但我個人建議先熟悉核心工作流程後再來理解這些進階應用,這樣更能體會它們的實用性。

透過 terraform fmt 格式化程式碼

terraform fmt 命令用於將 Terraform 設定檔重寫為符合 Terraform 語言風格規範的標準格式。由於標準格式會隨著 HashiCorp 設定語言和 Terraform 的功能和語法更新而演變,因此建議在更新 Terraform 版本後執行 terraform fmt

fmt 命令的語法為 terraform fmt [options] [DIR]。它會掃描目前目錄中以 .tf.tfvars 結尾的設定檔,除非指定了 DIR 引數。fmt 命令有幾個可選引數,包括:listwritediffcheckrecursive。您可以透過執行 terraform fmt -help 瞭解更多資訊。

以下案例說明 terraform fmt 的作用:

假設您正在團隊中工作,您編寫了一個 Terraform 範本,如下所示:

provider "azurerm" {
environment = "public"
}

module "vnet" {
source = "Azure/vnet/azurerm"
resource_group_name = "tacos"
location = "westus"
address_space = "10.0.0.0/16"
subnet_prefixes = ["10.0.1.0/24", "10.0.2.0/24"]
subnet_names = ["cheese","beans"]
}

程式碼可讀性良好,組織結構也算清晰。但是,執行 terraform fmt 後,程式碼會變成:

provider "azurerm" {
  environment = "public"
}

module "vnet" {
  source = "Azure/vnet/azurerm"
  resource_group_name = "tacos"
  location = "westus"
  address_space = "10.0.0.0/16"
  subnet_prefixes = ["10.0.1.0/24", "10.0.2.0/24"]
  subnet_names = ["cheese", "beans"]
}

注意縮排、等號等都對齊了。雖然兩個程式碼範例都可讀與可以成功執行,但格式化後的版本更具一致性。尤其在團隊合作中,最好將 terraform fmt 作為程式碼提交的一部分,以便所有人的程式碼格式都相同。

terraform fmt 的選項之一是 -recursive。如果您想要更新多個設定檔,只需在父目錄上執行 fmt 命令,它就會遞迴處理所有子目錄中的設定檔。

terraform help 命令

如同許多命令列介面一樣,Terraform 也內建了幫助系統。剛開始使用 Terraform 時,您會學習 initplanapplydestroy 等主要命令。

如果您遇到不熟悉的命令,或想了解更多資訊,當然可以上網搜尋,通常會找到 Terraform 官方命令檔案頁面。但我們也可以使用命令列完成同樣的事情。

執行 terraformterraform help 可以列出所有可用命令。

使用幫助系統查詢任何命令的更多資訊,只需輸入 terraform <commandName> -help。例如,如果要檢視 terraform plan 命令的幫助(使用 terraform plan -help),它會輸出命令的描述和選項。

這有助於發現特定命令的更多選項,從而提供更大的靈活性和自動化選項。

  graph LR
    C[C]
    No[No]
    Yes[Yes]
    A[terraform help] --> B(列出所有命令)
    A --> C{特定命令?};
    C -- Yes --> D[terraform <command> -help];
    D --> E(顯示命令說明);
    C -- No --> F(結束);

此流程圖展示瞭如何使用 terraform help 命令。首先執行 terraform help 會列出所有可用命令。如果您有特定想了解的命令,則可以執行 terraform <command> -help 來顯示該命令的詳細說明。

透過善用 terraform fmtterraform help,您可以編寫更規範、更易維護的程式碼,並更有效率地探索 Terraform 的各種功能。

將現有基礎設施匯入Terraform狀態

在真實世界中,多數環境並非全新佈署,而是已存在基礎設施。Terraform的import命令允許將這些現有資源納入Terraform管理,無需修改底層資源。這對於希望使用Terraform管理現有雲端資源的團隊尤其重要。

import命令的機制是將現有資源增加到Terraform狀態檔案中。截至目前,Terraform並不會自動生成匯入資源的組態,您需要自行編寫與現有資源比對的組態。雖然這需要額外的工作,但也能幫助您更深入地瞭解資源的建立方式,並發現任何偏離最佳實踐的地方。

何時使用import

以下場景適合使用import

  1. 遷移現有基礎設施到Terraform管理: 當團隊開始採用Terraform時,通常已經有一些雲端資源在執行。使用import可以避免刪除和重建這些資源,從而減少停機時間和成本。

  2. 手動建立資源後的補救: 有時,管理員可能會在Terraform之外手動建立資源。import可以將這些資源納入Terraform管理,確保所有基礎設施都以程式碼的形式進行管理。

如何使用import

import命令的使用步驟如下:

  1. 編寫Terraform組態: 首先,您需要編寫一個Terraform組態,描述要匯入的資源。這個組態應該與現有資源的屬性比對。

  2. 執行import命令: 接著,使用import命令將資源匯入到Terraform狀態。import命令的語法如下:

    terraform import <ADDRESS> <ID>
    

    其中,<ADDRESS>是資源的地址,<ID>是資源的唯一識別符號。

  3. 驗證狀態: 匯入資源後,使用terraform show命令驗證資源是否已成功增加到狀態檔案中。

import的優勢

  • 避免停機: 無需刪除和重建現有資源,從而避免服務中斷。
  • 簡化管理: 將所有基礎設施納入Terraform管理,方便日後維護和修改。
  • 提升一致性: 確保所有資源都遵循相同的組態規範。

import的限制

  • 需要手動編寫組態: 目前,Terraform不會自動生成匯入資源的組態,需要手動編寫。
  • 可能需要調整組態: 匯入資源後,可能需要調整組態以比對現有資源的實際狀態。

使用import的例項

假設您有一個現有的AWS EC2例項,ID為i-0abcdef1234567890。您想要將其匯入到Terraform管理。首先,您需要建立一個Terraform組態:

resource "aws_instance" "example" {
  ami           = "ami-0c94855ba95c574c8" # 替換為您的AMI ID
  instance_type = "t2.micro"
}

然後,執行import命令:

terraform import aws_instance.example i-0abcdef1234567890

最後,使用terraform show命令驗證匯入是否成功。

import的最佳實踐

  • 先備份狀態: 在執行import命令之前,最好備份現有的Terraform狀態檔案。
  • 逐步匯入: 避免一次性匯入大量資源,最好逐步匯入並驗證。
  • 使用版本控制: 將Terraform組態和狀態檔案納入版本控制系統,方便追蹤和回復。

藉由import,您可以將現有基礎設施無縫整合到Terraform的管理體系中,實作基礎設施即程式碼的目標。

  graph LR
    B[B]
    A[現有基礎設施] --> B{terraform import};
    B --> C[Terraform狀態];
    C --> D[基礎設施即程式碼];

上面的Mermaid圖表展示了使用terraform import將現有基礎設施匯入到Terraform狀態,最終實作基礎設施即程式碼的流程。

Terraform CLI:深入解析 Workspace 與 State 命令

在實際專案中,我們經常需要管理多個環境,例如開發、測試、預發布和生產環境。Terraform 提供了 workspacestate 命令來有效管理這些不同環境的基礎設施。本文將探討這兩個命令的使用場景、工作原理以及最佳實踐。

Workspace:隔離多環境狀態

Terraform 的 workspace 可以理解為獨立管理的狀態檔案,它們分享相同的組態,但狀態相互隔離。每個 workspace 代表一個特定環境中的佈署,允許我們使用單一組態管理所有環境中的相同佈署,確保高度一致性。

過去,Terraform 使用 terraform env 命令管理環境,但現在 env 命令實際上是 terraform workspace 的別名,未來可能會被棄用。

Workspace 命令詳解

  • new:建立一個新的 workspace 並切換到該 workspace。
  • select:切換到一個已存在的 workspace。
  • list:列出所有已存在的 workspace。
  • show:顯示當前 workspace 的名稱。
  • delete:刪除一個空的 workspace。

需要注意的是,刪除 workspace 時,該 workspace 不能是當前選定的 workspace,與狀態檔案必須為空。如果狀態檔案不為空,可以使用 -force 標誌強制刪除,但這會導致該 workspace 中的資源被遺棄。

Workspace 實踐案例

假設一個大型組織中包含網路團隊、治理團隊和應用程式團隊,以及生產、預發布和開發環境。為了實作角色和許可權分離,可以建立以下 workspace:

  • networking-dev
  • networking-stage
  • networking-prod
  • governance-dev
  • governance-stage
  • governance-prod
  • application-dev
  • application-stage
  • application-prod

這種方式允許每個團隊獨立管理各自的組態和環境,並在不同環境中獨立推進變更。

  graph LR
    application-dev[application-dev]
    application-stage[application-stage]
    governance-dev[governance-dev]
    governance-stage[governance-stage]
    networking-dev[networking-dev]
    networking-stage[networking-stage]
subgraph 網路團隊
    networking-dev --> networking-stage --> networking-prod
end
subgraph 治理團隊
    governance-dev --> governance-stage --> governance-prod
end
subgraph 應用程式團隊
    application-dev --> application-stage --> application-prod
end

State:檢視與操作 Terraform 狀態

Terraform 的狀態是一個 JSON 檔案,儲存了所有已佈署資源的訊息。強烈建議不要直接編輯狀態檔案,而是使用 terraform state 命令及其子命令進行操作。

State 命令詳解

  • list:列出狀態中的所有資源。
  • mv:移動狀態中的一個專案。
  • pull:提取當前狀態並輸出到標準輸出。
  • push:將本地狀態檔案更新到遠端狀態。
  • rm:從狀態中移除資源例項。
  • show:顯示狀態中的一個資源。

資源定址

使用 terraform state 命令時,通常需要與狀態中定義的特定資源例項進行互動。可以使用標準地址語法來存取這些資源,語法格式為 [module path][resource spec]

例如,Azure vnet 模組 my-vnet 中定義的一個子網路可以透過路徑 module.my-vnet.azurerm_subnet.example 來參照。

terraform state 命令提供了一種安全可靠的方式來管理 Terraform 狀態,避免直接編輯狀態檔案可能帶來的風險。terraform workspace 命令則提供了一種有效的方法來管理多個環境的基礎設施,確保不同環境之間的隔離性和一致性。

在大型專案中,結合使用 workspacestate 命令,可以更好地組織和管理 Terraform 狀態,提高團隊協作效率,並降低基礎設施管理的複雜性。

透過以上說明,我們深入瞭解了 terraform workspaceterraform state 命令的使用方法和應用場景。在實際操作中,應根據具體需求選擇合適的命令和子命令,並遵循最佳實踐,以確保 Terraform 狀態的正確性和一致性。

深入Terraform狀態操作:資源管理的利器

在Terraform的世界中,狀態管理是至關重要的環節。它記錄了基礎設施的當前狀態,並作為Terraform規劃和應用變更的依據。我將探討Terraform狀態操作的各個方面,包括資源定址、列表、移動、提取、推播和移除等關鍵操作,並結合實際案例說明如何有效地運用這些功能。

Terraform 資源定址:精準定位你的資源

Terraform 使用一種稱為「地址」的機制來精確地參照狀態中的資源。這種機制類別似於檔案系統的路徑,允許你定位到特定的資源例項或模組。資源地址的基本形式為 module.module_name.resource_type.resource_name。例如,module.web_servers.aws_instance.nginx 指的是名為 web_servers 的模組中,型別為 aws_instance 與名稱為 nginx 的資源例項。

對於巢狀的子模組,地址會進一步延伸,例如 module.parent_module.module.child_module.resource_type.resource_name。此外,你還可以透過索引來參照資源屬性中的特定元素,例如 module.web_servers.aws_instance.nginx.private_ip[0] 指的是 nginx 例項的第一個私有 IP 地址。

  graph LR
    subgraph 根模組
        subgraph web_servers 模組
            nginx[aws_instance.nginx] --> private_ip[private_ip[0]]
        end
    end

Terraform 狀態列表:一覽全域性

terraform state list 命令用於列出 Terraform 狀態中的所有資源。你可以使用 -state 選項指定狀態檔案,使用 -id 選項指定特定 ID,或者使用地址引數來過濾特定資源。如果不提供地址,則會傳回所有資源。

例如,假設我們佈署了一個 AWS EC2 例項,並希望檢視所有已建立的資源,執行 terraform state list 後,輸出如下:

data.aws_ami.aws-linux
aws_default_vpc.default
aws_instance.nginx
aws_security_group.allow_ssh

這個命令可以幫助你快速瞭解佈署中的所有資源,並選擇特定資源進行後續操作。

Terraform 狀態移動:資源重組的藝術

terraform state mv 命令用於在 Terraform 狀態中移動資源。你可以使用它來重新命名資源、將資源移動到不同的模組,或將資源移動到新的狀態檔案。

例如,我們想將 aws_instance.nginx 重新命名為 aws_instance.web。首先,我們需要更新組態檔案中的資源名稱。然後,執行以下命令:

terraform state mv aws_instance.nginx aws_instance.web

這樣,Terraform 就會將 aws_instance.nginx 在狀態中的記錄更新為 aws_instance.web,而無需銷毀並重新建立例項。

Terraform 狀態提取和推播:遠端狀態同步

terraform state pull 命令用於從遠端後端下載狀態檔案,而 terraform state push 命令則用於將本地狀態檔案上傳到遠端後端。這些命令主要用於與遠端狀態進行同步。

Terraform 狀態移除:告別不再管理的資源

terraform state rm 命令用於從 Terraform 狀態中移除資源。這並不會銷毀實際的資源,只是將其從 Terraform 的管理中移除。

例如,如果我們不再使用 Terraform 管理 aws_instance.web,可以執行以下命令:

terraform state rm aws_instance.web

移除資源後,也需要從組態檔案中刪除相應的資源定義和參照,以避免 Terraform 嘗試重新建立資源或出現錯誤。

總結:熟練掌握 Terraform 的狀態操作命令,可以讓你更有效地管理和維護你的基礎設施。理解資源定址、列表、移動、提取、推播和移除等操作,可以幫助你更好地控制 Terraform 狀態,並在實際應用中更加得心應手。

深入Terraform CLI:狀態管理、日誌與模組

在之前的討論中,我們已經涵蓋了Terraform的核心工作流程。現在,讓我們探討Terraform CLI的更多進階功能,包含狀態管理、日誌設定以及模組的使用。這些工具能幫助我們更有效率地管理基礎設施,並提升協作效率。

Terraform狀態管理:洞悉基礎設施現狀

Terraform的狀態管理功能是理解和操作基礎設施現狀的關鍵。透過terraform state指令,我們可以檢視、修改,甚至重新整理Terraform狀態,從而精確控制基礎設施的變更。

檢視資源屬性:terraform state show

terraform state show指令可以顯示特定資源的詳細屬性。例如,要檢視aws_instance.web資源的屬性,可以使用以下指令:

terraform state show aws_instance.web

這個指令的輸出結果會列出該資源的所有屬性及其值,方便我們快速檢查資源的組態情況。這在除錯或整合其他系統時非常有用,例如,可以將這些資訊提供給組態管理資料函式庫(CMDB)。

Terraform狀態指令的應用場景

terraform state子指令提供了多種功能,以下列出一些常見的應用場景:

  • terraform state list:列出所有受管理的資源。
  • terraform state mv:移動資源到不同的狀態路徑,例如在重構程式碼時調整資源的組織結構。
  • terraform state rm:從狀態中移除資源,這在移除不再需要的資源時非常有用。
  • terraform state push:將本地狀態更新到遠端儲存函式庫,方便團隊協作。
  • terraform state pull:從遠端儲存函式庫下載最新的狀態到本地。

這些指令讓我們能更精細地管理Terraform狀態,提升基礎設施管理的靈活性。

設定日誌級別:精確掌控除錯資訊

Terraform的日誌功能可以幫助我們診斷和解決問題。透過設定TF_LOG環境變數,我們可以控制日誌的詳細程度。日誌級別從最詳細到最簡潔依序為TRACEDEBUGINFOWARNERROR

例如,當terraform apply執行失敗與錯誤訊息不夠明確時,可以設定TF_LOGINFO或更詳細的級別來取得更多除錯資訊:

export TF_LOG=INFO
terraform apply

如果還需要將日誌寫入檔案,可以設定TF_LOG_PATH環境變數:

export TF_LOG_PATH=/var/logs/terraform/my-log.log

這樣,Terraform的日誌就會同時輸出到終端和指定的檔案中。

善用模組:提升程式碼重用性

模組是Terraform中程式碼重用的關鍵。一個模組就是一個包含輸入、資源和輸出的組態,這些元素都是可選的。當我們在一個目錄下建立一組.tf.tf.json檔案時,就構成了一個模組。

模組來源:靈活選擇

Terraform支援多種模組來源,包含:

  • 本地路徑
  • Terraform Registry
  • GitHub、Bitbucket等程式碼託管平台
  • HTTP URLs
  • AWS S3、Google Cloud Storage等雲端儲存服務

其中,Terraform Registry是一個重要的資源,它提供了許多由第三方廠商維護和驗證的模組,例如AWS VPC或Azure AKS叢集等常用雲端元件。使用這些驗證過的模組可以節省大量時間和精力。

模組呼叫:簡潔明瞭

使用module程式碼區塊可以呼叫模組:

module <模組名稱> {
  # 模組設定
}

透過模組,我們可以將複雜的基礎設施組態拆解成更小、更易於管理的單元,提升程式碼的可讀性和重用性。

Mermaid視覺化Terraform架構

Mermaid圖表可以幫助我們更清晰地展現Terraform的架構和流程。以下是一些Mermaid圖表的應用範例:

  graph LR
    C[C]
    A[Terraform] --> B(Provider)
    B --> C{Resource}

這個簡單的流程圖展示了Terraform、Provider和Resource之間的關係。

  sequenceDiagram
    participant Terraform
    participant Provider
    Terraform->>Provider: Provision Resources
    Provider->>Terraform: Return Resource Status

這個時序圖展示了Terraform和Provider之間的互動流程。

透過Mermaid圖表,我們可以更直觀地理解Terraform的運作方式,並更有效地溝通技術方案。

本文探討了Terraform CLI的進階功能,包含狀態管理、日誌設定和模組的使用。這些工具能幫助我們更有效率地管理基礎設施,並提升程式碼的重用性和可維護性。Mermaid圖表的應用則能進一步提升技術溝通的效率。掌握這些技巧,將使我們在使用Terraform時更加得心應手。

揭開 Terraform 模組的神秘面紗:邁向可重複使用基礎架構之路

在現代軟體開發中,基礎架構即程式碼 (Infrastructure as Code, IaC) 已成為不可或缺的實踐。Terraform 作為 IaC 的領先工具,其模組化設計更是建構可重複使用、高效率基礎架構的關鍵。本文將探討 Terraform 模組的精髓,帶您領略模組的強大功能。

模組來源:本地檔案 vs. 遠端儲存函式庫

Terraform 模組的來源可以是本地檔案系統或遠端儲存函式庫,包含經第三方廠商驗證的 Terraform Registry。我個人偏好使用私有儲存倉管理模組,這有助於版本控制和團隊協作。

module "vpc" {
  source = "terraform-aws-modules/vpc/aws" # 使用 Terraform Registry 上的模組
  # ...其他設定 ...
}

module "local_module" {
  source = "./modules/my_module" # 使用本地模組
  # ...其他設定 ...
}

以上程式碼片段展示瞭如何使用 source 引數指定模組來源。使用遠端儲存函式庫時,Terraform 會在執行 terraform init 時將檔案複製到本地 .terraform 目錄。

模組輸入與輸出:開發靈活的模組化介面

輸入變數:客製化模組行為

輸入變數如同函式的引數,允許在不修改模組原始碼的情況下客製化模組行為。在根模組中宣告變數時,可以使用 CLI 選項或環境變數設定其值。在子模組中宣告變數時,則由呼叫模組傳遞值。

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"
  name = var.prefix # 使用根模組的變數
  cidr = "10.0.0.0/16" # 直接設定值
  # ...其他設定 ...
}

以上程式碼片段展示瞭如何傳遞輸入變數給子模組。輸入變數可以是根模組的變數、硬編碼值或其他資源的屬性。

輸出變數:暴露資源屬性

輸出變數將資源屬性暴露給外部使用,例如子模組將資源屬性暴露給呼叫模組,或根模組將值輸出到 CLI。

output "vpc_id" {
  value = module.vpc.vpc_id
}

以上程式碼片段展示瞭如何使用輸出變數。未暴露為輸出的屬性將無法被其他模組使用。

模組變數範圍:理解變數的可見性

每個 Terraform 設定目錄都是一個模組。模組中的變數具有區域性作用域,僅在該模組內可見。子模組無法直接存取父模組的變數,除非透過輸入變數傳遞。

variable "vpc_name" {
  type = string
}

module "my_vpc" {
  # ...
  name = var.vpc_name # 使用父模組傳遞的變數
}

以上程式碼片段展示瞭如何在子模組中使用父模組傳遞的變數。

視覺化 Terraform 模組架構

  graph LR
    C[C]
    subgraph 根模組
        A[變數定義] --> B(模組呼叫)
        B --> C{輸出變數}
    end
    B --> D((子模組))
    D --> E[資源建立]

此圖表展示了 Terraform 模組的基本架構,根模組透過變數與子模組互動,子模組負責建立資源。

Terraform 模組化設計是建構可重複使用、高效率基礎架構的根本。透過理解模組來源、輸入輸出和變數範圍等核心概念,並善用 圖表視覺化模組架構,可以更好地運用 Terraform 構建複雜與可維護的基礎架構。

模組化設計:Terraform 中的程式碼重用與封裝

身為一位擁有多年雲端架構經驗的技術工作者,我深刻體會到程式碼重用和一致性對於提升效率和降低錯誤率的重要性。Terraform 的模組化設計正是解決這個問題的利器。它允許我們將基礎設施程式碼封裝成可重複使用的模組,就像搭建積木一樣,快速構建複雜的雲端環境。

模組範圍與變數可見性

在設計模組時,理解變數的作用域至關重要。每個模組都擁有自己的區域變數,這些變數僅在模組內部可見。呼叫模組時,我們需要明確地將值傳遞給模組的輸入變數。子模組無法直接存取父模組的變數,除非這些變數被明確地作為輸入傳遞。

舉例來說,假設根模組定義了一個名為 naming_prefix 的變數:

variable "naming_prefix" {
  type = string
  description = "用於資源命名的字首"
  default = "tfm"
}

然後,根模組呼叫一個子模組來建立一組虛擬機器:

module "virtual_machine_set" {
  source = "../modules/virtual_machine_set"

  name = "vms"
  num_vms = 3
}

子模組無法透過以下任何方式存取父模組的 naming_prefix 變數:

# 參照子模組自身的變數
var.naming_prefix

# 無效的物件參照
root.var.naming_prefix

# 同樣無效
parent.var.naming_prefix

同樣地,子模組的區域變數也無法被父模組直接存取。例如,子模組定義了一個區域變數:

locals {
  vm_name = "${var.prefix}-vms"
}

父模組無法透過以下方式參照 local.vm_name

# 參照父模組自身的區域變數
local.vm_name

# 無效的物件參照
module.virtual_machine_set.local.vm_name

# 同樣無效
module.virtual_machine_set.vm_name

要讓父模組存取子模組的區域變數,唯一的方法是在子模組中建立一個輸出變數。

模組間的資料傳遞

更進一步,我們可以利用一個子模組的輸出作為另一個子模組的輸入。以下是一個建立網路安全群組 (NSG) 的例子。NSG 模組需要一些輸入變數,例如標籤值、資源群組名稱和 NSG 名稱。我們可以將先前呼叫的另一個模組 (VNets-Core) 的輸出值傳遞給 NSG 模組:

module "nsgs-Core" {
  source = "../../nsgs/core"

  ResourceID = var.ResourceID
  CostCenter = var.CostCenter

  CoreNetworking-ResourceGroup-Name = azurerm_resource_group.CoreNetworking.name

  CoreProduction-NSG-Name = module.vnets-Core.CoreProduction-NSG-Name
}

公開模組登入函式庫

Terraform 的公開模組登入函式庫 (https://registry.terraform.io/) 提供了大量由社群維護的模組,涵蓋了主流雲端供應商和各種常見應用場景。這些模組都是開源的,程式碼託管在 GitHub 上,供所有人檢閱和使用。

在使用公開模組時,建議指定版本號,以避免意外的更新影響現有基礎設施:

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "2.20.0"
}

版本約束可以使用多種運算元,例如:

  • >= 2.20.0:版本 2.20.0 或更新版本
  • <= 2.20.0:版本 2.20.0 或更舊版本
  • ~> 2.20.0:2.20.x 系列的任何版本,2.21.x 版本不符合
  • >= 2.0.0, <= 2.20.0:2.0.0 到 2.20.0 之間的任何版本(包含 2.0.0 和 2.20.0)

~> 運算元尤其適用於保持主版本號不變,同時允許次要版本號更新。

透過模組化設計,我們可以有效地管理和重用基礎設施程式碼,提高佈署效率,並確保基礎設施的一致性。善用公開模組登入函式庫和版本約束,更能簡化開發流程,降低維護成本。

模組間資料流向

以下使用 Mermaid 流程圖展示模組間的資料流向:

  graph LR
    D[D]
    subgraph 根模組
        A[變數: naming_prefix] --> B(模組: virtual_machine_set)
    end
    B --> C[模組: VNets-Core]
    C --> D{模組: nsgs-Core}
    D --> E[輸出]

此圖表展示了變數如何在模組間傳遞。根模組的 naming_prefix 變數傳遞給 virtual_machine_set 模組。VNets-Core 模組的輸出作為 nsgs-Core 模組的輸入。最終,nsgs-Core 模組產生輸出。這個流程圖清晰地展現了 Terraform 模組化設計的資料流向。

藉由以上說明和圖表,相信各位讀者對於 Terraform 模組的使用有了更深入的理解。在實際應用中,靈活運用模組化設計,將能大幅提升您的基礎設施管理效率。

Terraform 工作流程與核心指令解析

身為一個擁有多年雲端架構經驗的技術工作者,我發現 Terraform 的出現簡化了基礎設施管理的複雜性。它以程式碼的形式定義基礎設施,讓管理和佈署變得更有效率與可預測。這篇文章將探討 Terraform 的核心工作流程和關鍵指令,並分享我在實際應用中的一些心得。

Terraform 的核心工作流程:撰寫、規劃、應用

Terraform 的工作流程主要分為三個階段:撰寫 (Write)、規劃 (Plan) 和應用 (Apply)。這個流程確保了基礎設施的變更在佈署前經過充分的驗證和預覽,降低了出錯的風險。

  1. 撰寫 (Write): 這個階段就像撰寫任何程式碼一樣,使用 HCL 或 JSON 定義所需的基礎設施資源。我個人偏好使用 HCL,因為它的語法更簡潔易懂。良好的程式碼風格和版本控制至關重要,這能幫助團隊協作和追蹤變更。在撰寫過程中,我會頻繁使用 terraform validate 檢查程式碼語法,並使用 terraform fmt 格式化程式碼,確保程式碼品質。

  2. 規劃 (Plan): 在這個階段,Terraform 會根據你的程式碼,預覽將在目標環境中進行的變更。這一步至關重要,它能讓你確認變更是否符合預期,避免意外的修改。我會在每次修改程式碼後執行 terraform plan,及早發現潛在問題。

  3. 應用 (Apply): 最後一步是將規劃好的變更應用到目標環境。Terraform 會再次顯示預覽的變更,並要求確認後才會執行。成功應用後,我會將程式碼提交到版本控制系統,確保變更得到妥善儲存。

  graph LR
    C[C]
A[撰寫 (Write)] --> B(規劃 (Plan))
B --> C{應用 (Apply)}
C -- 迴圈 --> A

刪除佈署

除了佈署新的基礎設施,Terraform 也支援刪除不再需要的資源。當專案結束或資源不再使用時,可以使用 terraform destroy 指令移除已佈署的基礎設施。

關鍵指令詳解

以下將詳細介紹 Terraform 工作流程中使用的關鍵指令:

terraform init:初始化工作目錄

terraform init 是在新的 Terraform 工作目錄中必須執行的第一個指令。它會初始化後端狀態儲存、下載所需的模組和外掛。

這個指令的功能包括:

  • 準備狀態儲存: 無論使用本地或遠端後端,terraform init 都會準備好狀態儲存的後端。
  • 下載模組: terraform init 會檢查程式碼中使用的模組,並從指定的來源下載。
  • 下載外掛: terraform init 會下載程式碼中使用的 provider 和 provisioner 外掛。

terraform init 可以多次安全執行,如果組態沒有變更,Terraform 不會進行任何操作。以下是一些需要重新執行 terraform init 的場景:

  • 新增了新的模組、provider 或 provisioner。
  • 更新了模組、provider 或 provisioner 的版本。
  • 變更了後端組態。

常用的 terraform init 引數:

  • -backend-config:用於組態後端狀態儲存。
  • -input=false:禁止 init 過程中提示使用者輸入,適用於自動化場景。
  • -plugin-dir:指定外掛目錄,避免自動下載外掛,適用於安全受限的環境。
  • -upgrade:強制更新外掛和模組到最新版本。

terraform plan:規劃變更

terraform plan 指令用於預覽將要執行的變更。它會比較目前的狀態和組態,顯示新增、修改或刪除的資源。

在開發過程中,我會頻繁使用 terraform plan,確保每次變更都符合預期。terraform plan 的輸出可以儲存到檔案中,以便後續應用。

terraform apply:應用變更

terraform apply 指令用於應用規劃好的變更。它會再次顯示預覽的變更,並要求確認後才會執行。

terraform destroy:銷毀基礎設施

terraform destroy 指令用於銷毀已佈署的基礎設施。它會移除所有由 Terraform 管理的資源。

模組的使用

模組是可重複使用的程式碼塊,可以簡化 Terraform 組態的管理。使用模組可以提高程式碼的可讀性和可維護性。

在使用模組時,最好指定版本號,避免意外的更新造成問題。HashiCorp 提供了一個公開的模組倉函式庫,其中包含許多由雲端供應商提供的官方模組。

Terraform 的核心工作流程和指令設計簡潔而有效,能幫助開發者高效管理基礎設施。透過理解和熟練運用這些指令,可以更好地利用 Terraform 的強大功能,構建和管理可靠的雲端基礎設施。我建議在實踐中多使用 terraform plan 預覽變更,並善用模組來提高程式碼的可重用性。

玄貓解說 Terraform 工作流程:初始化與驗證組態

在實際操作 Terraform 之前,我們必須先了解其工作流程中的兩個關鍵步驟:初始化和驗證。這兩個步驟確保你的組態正確無誤,為順利佈署基礎設施奠定基礎。

初始化 Terraform 組態 (terraform init)

terraform init 命令是 Terraform 工作流程的第一步。它主要完成以下任務:

  1. 初始化後端: 確認狀態檔案的儲存位置。狀態檔案記錄了 Terraform 管理的資源,是後續更新和銷燬資源的關鍵。terraform init 會驗證是否可以存取指定的後端,例如本地檔案系統、雲端儲存服務等。

  2. 下載模組: 如果組態中使用了模組,terraform init 會下載並安裝所需的模組。模組是可複用的組態單元,能簡化複雜基礎設施的管理。

  3. 下載外掛: Terraform 使用外掛與不同的雲端平台和服務供應商互動。terraform init 會根據組態中指定的供應商,下載並安裝對應的外掛。在 Terraform 0.13 及之後的版本中,required_providers 區塊用於指定外掛來源,可以是公開或私有的外掛倉函式庫。

以下是一個使用 AWS 供應商和 VPC 模組的組態示例:

provider "aws" {
  region = "us-east-1"
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "2.24.0"
}

執行 terraform init 後,Terraform 會在工作目錄下建立 .terraform 目錄,其中包含下載的模組和外掛。

.
├── .terraform
│   ├── modules
│   │   ├── modules.json
│   │   └── vpc
│   └── plugins
│       └── windows_amd64
└── terraform_aws_vpc_init.tf

關於狀態檔案: terraform init 雖然會初始化後端,但並不會立即建立狀態檔案。狀態檔案只在有實際狀態需要記錄時才會建立,例如在第一次執行 terraform apply 之後。

驗證 Terraform 組態 (terraform validate)

terraform validate 命令用於檢查 Terraform 設定檔的語法是否正確。它會掃描目錄下的所有 Terraform 檔案,並標示出語法錯誤和警告。

驗證時機: 除了手動執行 terraform validate 外,terraform planterraform apply 命令也會自動執行驗證。

驗證的重要性: 語法驗證能及早發現組態錯誤,避免在佈署過程中出現問題。但需要注意的是,即使組態透過驗證,也並不保證佈署一定會成功。例如,組態中可能存在邏輯錯誤或引數值錯誤,這些錯誤 terraform validate 無法檢測出來。

驗證示例:

以下是一個包含錯誤的組態示例:

provider "azurerm" {
  version = "~> 1.0"
}

resource "azurerm_resource_group" "main" {
  name     = "test"
  location = "eastus"
  colors   = ["blue"] // 錯誤:azurerm_resource_group 資源型別不支援 colors 引數
}

module "network" {
  source              = "Azure/network/azurerm"
  version             = "~> 1.1.1"
  location            = "eastus"
  allow_rdp_traffic  = "true"
  allow_ssh_traffic  = "maybe" // 錯誤:"maybe" 不是有效的布林值
  resource_group_name = azurerm_resource_group.main.group_name // 錯誤:azurerm_resource_group 沒有 group_name 屬性
}

執行 terraform validate 後,Terraform 會指出以上錯誤。修正錯誤後再次執行驗證,才能確保組態語法正確。

以上程式碼示範瞭如何使用 Terraform 定義 Azure 資源組和網路模組。其中,azurerm_resource_group 資源用於建立 Azure 資源組,network 模組則用於組態網路設定。程式碼中故意加入了一些錯誤,用於演示 terraform validate 如何檢測組態錯誤。

總結:

terraform initterraform validate 是 Terraform 工作流程中不可或缺的兩個步驟。terraform init 負責初始化後端、下載模組和外掛,而 terraform validate 負責檢查組態語法。透過這兩個步驟,我們可以確保 Terraform 組態正確無誤,為後續的佈署工作做好準備。

  graph LR
    C[C]
A[撰寫 Terraform 組態] --> B(terraform init)
B --> C{驗證透過?}
C --是--> D[terraform plan]
C --否--> A

圖表說明: 此流程圖展示了 Terraform 初始化和驗證的流程。首先,我們撰寫 Terraform 設定檔。接著,執行 terraform init 初始化後端和下載依賴項。然後,執行驗證。如果驗證透過,則可以繼續執行 terraform plan;如果驗證失敗,則需要傳回修改組態,直到驗證透過為止。

玄貓帶你理解 Terraform 的執行計畫:terraform plan

terraform plan 命令是 Terraform 建立執行計畫的關鍵。它會執行三項主要任務:

  1. 語法驗證: 檢查當前設定檔的語法是否正確。
  2. 狀態更新: 根據實際環境更新狀態資訊。這一步驟至關重要,能讓 Terraform 掌握最新的基礎設施狀況。我曾經遇到過因為跳過這一步驟而導致佈署錯誤的情況,所以務必重視!
  3. 狀態比較: 比較更新後的狀態與設定檔內容,找出差異。

執行 plan 命令並不會修改實際環境,它只會產生一個執行計畫,告訴你為了讓實際環境與設定檔一致,需要進行哪些變更。這就像在蓋房子之前先畫藍圖一樣,可以預先檢查設計是否有問題。

產生的執行計畫可以透過 -out 引數儲存到檔案中,方便之後使用 terraform apply 執行。要注意的是,執行計畫與當前狀態版本繫結,如果狀態發生變化,Terraform 就會拒絕執行該計畫。

我通常會在以下情況使用 plan

  • 程式碼合併前檢查: 確保程式碼合併後不會造成意外的基礎設施變更。
  • 驗證設定檔: 確認設定檔內容的正確性。
  • 準備執行變更: 預覽變更內容,並將執行計畫儲存下來,以便在自動化流程中使用。

terraform plan 常用引數:

  • -input:是否提示輸入,在自動化流程中應設為 false
  • -out:指定儲存執行計畫的檔案路徑。
  • -refresh:是否更新狀態,預設為 true
  • -var:設定變數值,可以多次使用。
  • -var-file:指定包含變數值的檔案。

varvar-file 引數非常常用,它們是提交變數值的主要方式之一。

plan 命令還可以接受一個包含 Terraform 設定檔的目錄作為輸入。如果未指定目錄,Terraform 將使用當前工作目錄中的設定檔。

-destroy 引數則會產生一個銷毀所有受管資源的計畫,我們會在稍後討論 terraform destroy 時詳細說明。

Terraform 基礎設施變更執行:terraform apply

terraform apply 命令會根據設定檔或 terraform plan 產生的執行計畫,對實際環境進行變更。

預設情況下,apply 會在當前工作目錄中尋找 Terraform 設定檔,並根據目標狀態和實際環境建立執行計畫。執行計畫會呈現給使用者批准,批准後才會套用到實際環境,並更新狀態資料。

如果提交已儲存的執行計畫給 terraform apply,它會跳過計畫產生和批准步驟,直接修改實際環境和狀態資料。

雖然可以直接執行 terraform apply 而不用先執行 terraform plan,但我不建議這樣做。尤其在團隊合作或自動化環境中,最好先執行 plan 並儲存執行計畫。

terraform apply 常用引數:

  • -auto-approve:跳過批准步驟,自動執行變更。
  • -input:是否提示輸入,在自動化流程中應設為 false
  • -refresh:是否更新狀態,預設為 true
  • -var:設定變數值,可以多次使用。
  • -var-file:指定包含變數值的檔案。

如果已將執行計畫儲存到 terraform.tfplan 檔案中,則可以執行以下命令:

terraform apply terraform.tfplan

這樣就不需要再次指定變數,並且會自動批准執行計畫。

即使有執行計畫,也不能保證變更一定會成功套用。Terraform 會盡力套用所有變更,但偶爾還是會出現問題,例如雲端供應商的問題或設定檔的錯誤。當遇到錯誤時,Terraform 不會回復到先前的設定,而是保留目前的狀態,以便你進行除錯。組態失敗的資源會被標記為 tainted,Terraform 會在下一次執行時嘗試重新建立它們。

銷毀 Terraform 管理的基礎設施:terraform destroy

terraform destroy 命令用於銷毀 Terraform 管理的基礎設施。

銷毀已佈署的資源在基礎設施生命週期中可能不是一個顯而易見的步驟,但在許多情況下都非常有用,例如在專案結束後清理開發環境,或在 CI/CD 流程中拆除測試環境。

destroy 命令功能強大,它會刪除 Terraform 管理的所有資源,而與這個動作是不可逆的。因此,Terraform 會先顯示將要銷毀的所有資源的執行計畫,並要求確認後才會執行銷毀操作。

destroy 命令在許多方面與 apply 命令類別似,但它不能接受執行計畫檔案。它接受 apply 命令的所有引數和標誌,但沒有 plan 檔案引數。你可以透過執行 terraform plan -destroy 來預覽 destroy 命令的執行結果。

destroy 命令的兩個常用引數:

  • -auto-approve:不提示確認,直接執行銷毀操作(過去的 -force 引數已被棄用)。
  • -target:指定要銷毀的目標及其依賴項,可以多次使用。

使用 圖表說明 terraform 工作流程

  graph LR
    C[C]
    E[E]
A[撰寫設定檔] --> B(terraform init)
B --> C{terraform validate}
C -- 有錯誤 --> A
C -- 無錯誤 --> D(terraform plan)
D --> E{terraform apply}
E -- 執行成功 --> F[基礎設施已佈署]
E -- 執行失敗 --> G[除錯與修正]
F --> H(terraform destroy)
G --> D
H --> A

此流程圖展示了使用 Terraform 管理基礎設施的典型工作流程。從撰寫設定檔開始,接著初始化、驗證、規劃、套用和銷毀。圖中也展示了錯誤處理和迴圈流程,例如驗證失敗則傳回修改設定檔,套用失敗則進行除錯和修正。

terraform planterraform applyterraform destroy 是 Terraform 工作流程中的三個核心命令。plan 用於建立執行計畫,apply 用於套用變更,destroy 用於銷毀資源。理解這些命令的用法和引數,對於有效管理基礎設施至關重要。善用這些命令和引數,可以提高效率,減少錯誤,並更好地控制基礎設施的變更。

Terraform 的狀態管理:深入解析

在 Terraform 的世界中,狀態管理至關重要。它就像一座橋樑,連線著你所描述的理想環境和你實際佈署的真實環境。Terraform 使用一種稱為「狀態」的 JSON 格式資料結構來追蹤這種對映關係。本文將探討狀態的儲存位置(後端)、組態方式、存取方法,以及協作和機密管理方面的一些注意事項。

預設本地後端

如果沒有指定其他組態,Terraform 會將狀態資料儲存在組態所在的本地檔案系統中。一個典型的資料夾結構如下:

.
├── .terraform
├── main.tf
└── terraform.tfstate

.terraform 目錄存放組態使用的外掛,terraform.tfstate 檔案則存放關於組態的狀態資料。可以使用命令列標誌 -state=statefile 來更改本地狀態檔案的位置,例如在 planapply 命令中使用。

如果你使用 Terraform 工作區,目錄結構會略有不同。每個工作區都維護一個單獨的狀態,允許多個環境使用相同的 Terraform 組態。假設我們在組態中建立了一個名為 development 的工作區,則目錄結構如下:

.
├── .terraform
├── main.tf
├── terraform.tfstate
└── terraform.tfstate.d
    └── development
        └── terraform.tfstate

Terraform 建立了一個 terraform.state.d 目錄和每個工作區的子目錄。每個工作區目錄中都包含該工作區的 terraform.tfstate 檔案。預設工作區繼續使用根目錄中的 terraform.tfstate 檔案。

狀態鎖定

狀態資料非常重要,涉及狀態的事務應該是原子性的。為了防止多個程式同時編輯狀態,Terraform 會鎖定狀態。任何可能編輯狀態的操作都會首先檢查狀態是否被鎖定。如果狀態未被鎖定,Terraform 將在進行更改之前嘗試建立狀態鎖定。如果無法獲得鎖定,Terraform 將不會繼續執行。

可以使用 -lock=false 標誌覆寫多個命令的鎖定行為。這應該是一個例外事件,應謹慎使用。狀態損壞的後果不堪設想。大多數狀態後端都支援鎖定,但也有一些不支援。您應該檢視任何給定後端的檔案,以確定它支援哪些功能。

後端驗證方法

某些後端需要驗證和授權才能存取儲存在後端中的狀態資料。例如,Azure 儲存體需要存取金鑰,MySQL 後端需要資料函式庫憑證。每個後端型別的檔案都將列出所需的準確格式和驗證型別。

以 Azure 儲存體後端為例:

terraform {
  backend "azurerm" {
    storage_account_name = "arthurdent42"
    container_name       = "tfstate"
    key                  = "terraform.tfstate"
    access_key           = "qwertyuiop12345678..."
  }
}

Azure 儲存體帳戶有一個允許完全存取儲存體帳戶內容的存取金鑰。在上面的程式碼片段中,存取金鑰值直接儲存在組態中。一般來說,不建議這種做法。

將憑證靜態定義在組態中有幾個問題。您可能希望定期更新憑證,這意味著每次都需要更新組態。將重要憑證以明文形式儲存在本地工作站或原始碼控制中也不是一個好主意。這是一個主要的潛在安全漏洞。

解決方案是在根模組中使用部分後端組態,並在執行時提供其餘資訊。當我們深入研究後端組態塊時,將在本章後面更詳細地討論部分組態。

以上程式碼片段展示瞭如何在 Terraform 中組態 Azure 儲存體作為狀態後端。storage_account_namecontainer_namekey 分別指定了儲存體帳戶名稱、容器名稱和狀態檔案的金鑰。access_key 則提供了存取儲存體帳戶的憑證。然而,直接將 access_key 硬編碼在組態中存在安全風險,更好的做法是使用環境變數或其他安全機制來管理敏感資訊。

(圖表)

  graph LR
    Authentication[Authentication]
    B[B]
    Local[Local]
    Remote[Remote]
    A[Terraform Configuration] --> B{Backend Initialization}
    B -- Local --> C[Local State File]
    B -- Remote --> D[Remote State Backend]
    D -- Authentication --> E[Credential Management]

圖表說明: 此流程圖展示了 Terraform 狀態管理的流程。Terraform 組態初始化後端,可以選擇本地狀態檔案或遠端狀態後端。遠端後端通常需要身份驗證,因此需要安全的憑證管理機制。

在小型專案中,使用 Terraform 預設的本地檔案後端或許足夠,但它缺乏資料保護與不利於團隊協作。解決方案是使用遠端狀態後端,將狀態資料儲存在遠端共用位置。

遠端後端根據您在組態中定義的後端設定,將狀態資料儲存在遠端位置。並非所有後端都相同,HashiCorp 定義了兩種型別的後端:

  • 標準後端: 包括狀態管理和可能的鎖定機制。
  • 增強後端: 在標準功能之上,還包括遠端操作。

增強型遠端後端是 Terraform Cloud 或 Terraform Enterprise,它們允許您在遠端服務上執行 Terraform 操作(例如 planapply),而不是在本地執行。

目前有十四種標準後端,本文將不一一贅述。建議您查閱每個後端的說明檔案,以瞭解支援的功能和所需的值。

當狀態資料儲存在遠端後端時,它不會寫入本地系統的磁碟。狀態資料在 Terraform 操作期間載入到記憶體中,然後在不再使用時清除。狀態檔案中的敏感資料永遠不會儲存在本地磁碟上,如果您的本地系統遺失或遭到入侵,這將提供額外的安全性。

除了將狀態儲存在安全位置之外,使用遠端狀態還可以讓其他團隊成員存取、修改狀態或將其用作資料來源。假設您正在與網路管理員 Joan 合作進行網路組態。你們兩個都可以更新本地組態副本,然後將其推播到版本控制。當需要更新實際環境時,您執行 planapply 階段。更新期間遠端狀態會被鎖定,因此 Joan 無法進行任何更改。當 Joan 執行她的下一個 plan 時,它將使用您最近一次 apply 更新後的遠端狀態資料。

組態中定義的任何輸出都可以使用狀態檔案作為資料來源來存取。例如,假設應用程式團隊需要查詢有關網路組態的資訊。您可以授予他們對網路狀態的唯讀存取許可權,並確保他們需要的資訊透過輸出公開。然後,應用程式團隊將在他們的組態中將網路狀態定義為資料來源,並直接參照輸出。

  graph LR
    C[C]
    F[F]
    A[本地組態] --> B(版本控制)
    B --> C{執行 plan}
    C -- 鎖定遠端狀態 --> D[更新環境]
    D --> E[遠端狀態]
    E --> F{Joan 執行 plan}

上圖展示了團隊協作使用遠端狀態的流程。本地組態更改推播到版本控制後,執行 plan 時會鎖定遠端狀態,確保更新環境的一致性。Joan 在執行 plan 時會使用更新後的遠端狀態資料。

Terraform refresh 對狀態資料的影響

儲存在狀態中的資料需要反映 Terraform 管理的基礎設施的實際狀態。refresh 操作會檢查目標環境中資源的屬性,並將它們與儲存在狀態中的值進行比較。Terraform 在 refresh 操作中不會更改目標基礎設施,但它會更新狀態以準確反映目標環境。

refresh 操作可以透過執行 terraform refresh 並指定任何選項來手動觸發。refresh 操作也會在 plan 階段自動執行,無論是從顯式 terraform plan 還是隱式地在沒有執行計劃檔案的情況下執行 terraform apply。重新整理狀態對於 Terraform 確定需要哪些更改才能使組態中表達的期望狀態與受管基礎設施相比對至關重要。

Terraform 不會發現和匯入在組態之外建立的新資源。例如,如果您手動將新資源新增到 Azure 資源群組或將 EC2 執行個體新增到 VPC,Terraform 不會找到這些資源並將它們置於管理之下。您需要更新組態並使用 import 命令才能實作此目的。

組態中的後端區塊和部分組態的最佳實務

Terraform 後端的組態定義在根模組的 terraform 區塊內。巢狀的 backend 區塊定義了正在使用的後端型別以及該後端的必要和可選屬性。每個組態只能指定一個後端。您不能同時將狀態儲存在兩個不同的後端中,也不能將狀態拆分到兩個不同的後端中。這種情況可以透過將組態本身拆分為兩個相互依賴的組態來解決。

如本章前面所見,使用 Azure 儲存體的基本後端組態區塊可能如下所示:

terraform {
  backend "azurerm" {
    storage_account_name = "arthurdent42"
    container_name       = "tfstate"
    key                  = "terraform.tfstate"
    access_key           = "qwertyuiop12345678..."
  }
}

以上程式碼片段展示了 Terraform 使用 Azure 儲存體作為後端的組態。其中,storage_account_namecontainer_namekeyaccess_key 分別指定了儲存帳戶名稱、容器名稱、狀態檔案名稱和存取金鑰。

直接在組態中儲儲存存帳戶名稱和存取金鑰可能不是一個好主意。但 Terraform 不允許在後端組態區塊中使用變數或任何其他插值。另一種方法是省略您想要動態組態的設定,而是在執行時提供它們。產生的區塊稱為部分組態。

我們上面的例子看起來像這樣:

terraform {
  backend "azurerm" {
    container_name = "tfstate"
    key            = "terraform.tfstate"
  }
}

這個程式碼片段展示了 Terraform 的部分後端組態。省略了敏感資訊 storage_account_nameaccess_key,這些資訊將在執行時提供。

storage_account_nameaccess_key 的值可以透過以下三種方式之一提供:

  1. 在執行 terraform init 時以互動方式在命令列中提供。
  2. 透過 -backend-config 旗標提供一組鍵/值對。
  3. 透過 -backend-config 旗標提供包含鍵/值對的檔案路徑。

後端中的某些引數也可以來自環境變數。例如,可以透過將 ARM_USE_MSI 設定為 true 來組態 Azure 儲存體的 Managed Security Identity (MSI)。檢查後端說明檔案以檢視環境變數支援哪些設定。

第一次使用後端值執行 terraform init 後,您無需再次為其他命令提供這些值。後端資訊和其他初始化資料儲存在組態的 .terraform 子目錄中的本地檔案中。由於您的後端組態中可能包含敏感資料(例如身份驗證憑據),因此應將此目錄從原始碼控制中排除。

在 GitHub 上建立新的儲存函式庫並建立 .gitignore 檔案時,您可以選擇 Terraform 作為選項之一。它將自動排除 .terraform 目錄,以及 terraform.tfvarsterraform.tfstate 等檔案。我們建議在任何新專案中使用 .gitignore 並排除這些檔案。

狀態檔案中的機密管理

狀態資料包含有關您組態的所有資訊,包括任何敏感資料,例如密碼、API 金鑰和存取憑據。狀態資料未由 Terraform 加密,但它可以位於加密的儲存平台上。透過使用提供資料加密的後端,您可以新增…

總結來說,選擇合適的遠端狀態儲存機制對於團隊協作和狀態資料安全至關重要。透過理解不同後端型別及其特性,並遵循最佳實務,可以有效管理 Terraform 狀態,確保基礎設施組態的安全性和可靠性。

敏感資料的處理:保護你的Terraform狀態

在使用 Terraform 管理基礎設施時,保護敏感資料至關重要。當 Terraform 使用遠端狀態後端時,狀態內容僅複製到記憶體中,除非明確指示,否則不會持久化到磁碟。

處理敏感資料的最佳實務是根本不將其儲存在狀態中。如果有 secrets 管理平台(例如 HashiCorp Vault),則讓應用程式從那裡擷取敏感資料。如果你的設定中必須包含敏感資料,則應將其儲存在提供靜態和傳輸中資料加密的遠端後端。

  graph LR
    C[C]
    A[應用程式] --> B(Secrets 管理平台)
    B --> C{敏感資料}

上圖展示了應用程式如何從 secrets 管理平台取得敏感資料,而不是直接從 Terraform 狀態中取得。

深入Terraform狀態管理

讓我們快速回顧本章節的學習目標和每個目標的重點:

  • 預設本地後端: 如果未指定替代方案,Terraform 將使用根模組目錄來儲存狀態資料。
  • 狀態鎖定: Terraform 可以在支援的後端鎖定狀態檔,以防止同時寫入狀態資料的操作。
  • 後端驗證方法: 遠端後端通常需要驗證。你需要在後端設定或執行時提供該資訊。
  • 遠端狀態儲存機制和支援的標準後端: Terraform 可以將狀態資料儲存在支援協作和狀態作為資料來源的遠端位置。
  • Terraform refresh 對狀態的影響: Terraform 可以從受管基礎設施的實際狀態重新整理狀態檔的內容。
  • 設定中的後端區塊和部分設定的最佳實務: Terraform 後端使用後端設定區塊定義。部分設定應用於省略敏感和動態值,這些值將在執行時提交。
  • 狀態檔中的 Secret 管理: 使用遠端狀態後端將敏感資料保留在你的機器之外。

讀取、生成和修改 Terraform 設定檔

現在,讓我們深入瞭解 Terraform 設定的細節。Terraform 中的典型設定將由變數、本地值、資源、資料來源、模組和輸出組成。

輸入變數

變數在 Terraform 設定中定義。你可以在執行時提供這些變數的值,或設定變數要使用的預設值。如果沒有設定變數的預設值,Terraform 將要求你在執行時提供一個值。未能提供值將導致相關命令出錯。

最基本的變數可以只用名稱標籤定義,不帶任何引數:

variable "aws_region" {}

讓我們定義更多關於 aws_region 的資訊:

variable "aws_region" {
  type = string
  default = "us-east-1"
  description = "此設定使用的 AWS 區域"
}

這樣更好。我們定義了預期的資料型別 (string)、預設值,並為自己和可能使用此設定的其他人提供了描述。我們稍後會在本章中介紹資料型別。提供變數的資料型別意味著 Terraform 可以執行一些驗證,以確保提供正確的資料型別。它不是完整的資料驗證,但總比沒有好!

Terraform 0.13 引入了變數驗證作為一項新功能!使用變數驗證時,你可以在變數區塊中新增一個驗證區塊,該區塊必須評估為 true 或 false。完整理解變數驗證超出了本的範圍,但瞭解此功能的存在是件好事。

這些變數的值如何提交?好問題!這些值在執行時透過幾種可能的方式提交。以下是一個方便的選項列表:

  1. 使用字首 TF_VAR_ 後跟變數名稱設定環境變數
  2. terraform.tfvarsterraform.tfvars.json 檔放在與設定相同的目錄中
  3. 將以 .auto.tfvars.auto.tfvars.json 結尾的檔放在與設定相同的目錄中
  4. -var-file 旗標與包含鍵/值對的檔案路徑一起使用
  5. -var 旗標與鍵/值對一起使用(aws_region=us-west-1
  6. 在命令列提示時輸入它們

有很多選項。而與你可以將所有這些選項組合在一起,讓事情更加複雜。Terraform 確實有一個評估提交值的優先順序,恰好與上面的列表相符。後面的選項優先於前面的選項,因此,如果你在環境變數中定義了一個變數值,並使用 -var 旗標為同一個變數提交了不同的值,則使用 -var 旗標提交的值將勝出。在命令列層級,最後提交的值將勝出。

將值應用於變數後,我們現在可以透過在設定的其餘部分中參照這些變數來使用它們。當我們討論資源定址時,我們將更深入地研究這個過程。

輸出值

Terraform 可以在設定檔成功佈署後提供輸出。根模組(即你的主要設定)建立的輸出將作為控制檯輸出的一部分列印,並且可以使用 terraform output 命令查詢它們。這看起來可能不是特別有用,但在子模組和 Terraform 狀態資料來源中,輸出變得非常有用,主要有兩種方式。

當你在 Terraform 中呼叫子模組時,你可以存取該模組建立的一些屬性或資源。子模組中的輸出決定了呼叫模組可以使用哪些資訊。這意味著子模組可以根據自己的需要建立變數和資源,只要它產生一組一致的輸出供呼叫模組使用即可。

在 Terraform 0.12 之前,輸出僅限於字串。你無法將複雜的資料型別作為輸出傳遞回去。這通常意味著使用內建函式將該字串輸出轉換為列表或對應等資料型別。現在支援複雜的資料型別,這意味著你可以將整個資源及其所有屬性作為輸出傳遞回去。

Terraform 狀態可以作為資料來源被另一個設定使用。該資料來源可用的屬性僅限於透過輸出公開的內容。假設你的網路團隊使用 Terraform 為你的應用程式團隊建立了網路環境。應用程式團隊可以在其設定中使用網路狀態檔作為資料來源,並查詢目標網路環境的資訊。網路團隊可以透過在其設定中建立適當的輸出來決定哪些資訊可用。

在設定中建立輸出遵循一個簡單的格式。輸出需要一個名稱和一個值。

output "vpc_id" {
  value = module.vpc.vpc_id
  description = "你的應用程式的 vpc id"
}

輸出區塊可以有兩個額外的引數:sensitivedepends_on。如果輸出的 sensitive 設定為 true,Terraform 將不會在 CLI 列印輸出的值。depends_on 引數接受輸出所依賴的資源列表,然後再進行渲染。通常 Terraform 可以自行確定依賴關係,但在某些特殊情況下,依賴關係鏈需要明確指定。

  graph LR
    C[C]
    A[輸入變數] --> B(Terraform設定)
    B --> C{輸出值}
    C --> D[子模組]
    C --> E[Terraform狀態資料來源]

上圖展示了 Terraform 設定如何使用輸入變數,並產生輸出值,這些輸出值可以被子模組或 Terraform 狀態資料來源使用。

Terraform 變數、輸出與機密資訊管理

在 Terraform 中,變數是向組態提交值的機制。提交值的方法有很多種,Terraform 會按照特定順序評估這些值,最後提交的值會覆寫先前的值。輸出主要用於將資訊從子模組公開到呼叫模組,或透過遠端狀態公開資訊。輸出在 terraform apply 過程中呈現,可以是複雜的資料型別。如果您更改現有輸出或增加新輸出,即使組態中沒有其他更改,也需要再次執行 apply

在處理 Terraform 的組態時,我們經常需要處理一些敏感資訊,例如應用程式密碼、API 令牌或用於向供應商驗證的使用者名稱和密碼。這些敏感資料需要謹慎處理。以下是一些關於處理機密資料的建議:

  • 避免將敏感資料儲存在 .tfvars 檔案中。 Terraform 不提供任何加密或保護變數檔案的機制,而與這些檔案很可能被簽入到版本控制系統中,這會導致敏感資訊洩露。
  • 避免在命令列中使用 -var 標誌提交敏感資料。 即使您在命令列中提交變數值,這些敏感資料也會以明文形式儲存在命令歷史記錄中。
  • 將敏感資料載入到環境變數中。 使用 TF_VAR_ 命名慣例加上變數名稱,可以將敏感資料儲存在環境變數中。您可以組態這些環境變數來提取敏感資料,而無需將其暴露在命令列中,Terraform 也將不會在其輸出中顯示敏感資料。
  • 使用機密生命週期管理器。 HashiCorp Vault、AWS Key Management Service 或 Azure Key Vault 等工具都是儲存敏感資料的安全選擇。Terraform 可以透過資料來源使用儲存在這些位置的敏感資訊,從而避免在本地儲存這些值。

需要注意的是,作為資源組態一部分提交的敏感資料會儲存在 Terraform 狀態中。理想情況下,您的狀態資料應該儲存在支援靜態加密的安全後端。如果您使用本地檔案後端來儲存狀態,請確保將其從版本控制中排除。

Terraform 集合與結構型別

Terraform 0.12 版本引入了定義完善的資料結構。Terraform 中有三種基本資料型別:

  • **string:**Unicode 字元序列。
  • **number:**數值,包括整數和小數。
  • **boolean:**真或假值。

在指定變數型別時,可以使用任何這些基本資料型別。基本型別只有一個值。複雜型別有多個值,可以分為兩類別:集合和結構。

集合型別是您可能最常遇到的多值型別,尤其是在 Associate 級別。有三種集合型別:

  • **list:**按列表中位置標識的順序值列表,從 0 開始。
  • **map:**由唯一字串鍵標識的值集合。
  • **set:**沒有識別符號或排序的唯一值集合。

list 和 map 集合型別比 set 型別更常見。集合中的所有值必須是相同的原始型別。您可以在一組括號中定義該原始型別。

variable "my_list" {
  type = list(string) # 字串列表
}

variable "my_map" {
  type = map(number) # 數字值的對映
}

有一種特殊的原始型別叫做 any,它允許在集合中使用任何型別。Terraform 會根據提交的值嘗試找出預期的型別。通常,在宣告輸入變數時,最好是規定性地使用型別,以確保獲得所需的結構。

結構型別允許您建立更複雜的物件,其中的值可以是多種型別。這與集合型別截然不同,在集合型別中,集合中的每個值必須是同一型別。有兩種結構型別:

  • **object:**與 map 類別似,它是一組鍵/值對,但每個值可以是不同的型別。
  • **tuple:**與 list 類別似,它是一組索引值,其中每個值可以是不同的型別。

map 可以輕鬆轉換為物件,但反過來並不總是如此。tuple 和 list 也是如此。在決定使用哪種型別時,請問自己是否需要在變數中定義多種型別。如果需要,則使用結構型別。

基本型別、集合型別和結構型別之間的區別一開始可能會有些混淆。建議多複習幾次,並嘗試建立自己的變數來測試各種型別。在大多數情況下,Terraform 將 map/object 和 list/tuple 視為相同的資料結構。雖然在為 Terraform 編寫模組和供應商時,實際差異可能很重要,但通常您也可以將它們視為等效的。

Terraform 資源與資料來源

大多數 Terraform 供應商都由資源和資料來源組成。資料來源是現有… (此處內容中斷,需要後續切片)

  graph LR
    A[基本型別] --> B(string)
    A --> C(number)
    A --> D(boolean)
    E[集合型別] --> F(list)
    E --> G(map)
    E --> H(set)
    I[結構型別] --> J(object)
    I --> K(tuple)

上面的 圖表展示了 Terraform 中不同資料型別的分類別,清晰地呈現了基本型別、集合型別和結構型別之間的關係。

  graph TD
    A[變數定義] --> B{敏感資料?}
    B -- 是 --> C[使用環境變數或機密管理工具]
    B -- 否 --> D[直接在組態中定義]

該流程圖展示了在 Terraform 中定義變數時,根據資料的敏感性選擇不同處理方式的決策流程。

(後續內容待補充)

玄貓帶你串聯 Terraform 資源:地址與引數應用

在 Terraform 的世界裡,資源之間的關係就像一張錯綜複雜的網路,彼此相互依存、相互影響。例如,建構一個執行於虛擬機器的 Web 應用程式,可能需要虛擬網路、虛擬機器、網路介面、防火牆規則以及負載平衡器等多種資源。這些資源的組態往往互相參照:負載平衡器需要參照虛擬機器上的網路介面,而網路介面則需要參照虛擬網路上的子網路。資源定址就是如何在 Terraform 組態中參照其他資源屬性的方法,它如同網路的經緯線,將各個資源緊密地聯絡在一起。

資料來源:資訊的入口

資料來源就像資訊的入口,讓你可以從供應商那裡取得所需資訊。例如,你可能需要取得特定 Ubuntu 版本在 AWS us-east-1 區域的 AMI ID,或者取得佈署 Azure 虛擬機器的 vnet ID。這些都是資料來源的應用場景。大多數資料來源需要你提供一些組態資料才能取得相關資訊,並且假設你已經正確組態了供應商,就像我們先前討論 Terraform 基礎時提到的那樣。以下是一個 AWS AMI 的例子:

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

這段程式碼定義了一個名為 ubuntuaws_ami 資料來源。most_recent = true 表示取得最新的 AMI。兩個 filter 區塊用於篩選 AMI,分別根據名稱和虛擬化型別進行比對。owners 指定了 AMI 的所有者,這裡是 Canonical。這個資料來源會傳回最新的 Ubuntu 16.04 HVM AMI 的相關資訊,其中包含 image_id 屬性,可用於建立 EC2 執行個體。

資源:Terraform 的核心

資源是 Terraform 存在的核心,用於組態和管理基礎設施。每個資源都代表供應商提供的特定基礎設施元件,例如虛擬機器、網路或資料函式庫。資源接受引數來定義物理資源的組態,這些引數可以是必需的或可選的,可以包含簡單的鍵值對或巢狀區塊。以下是一個 Azure 虛擬網路資源的例子:

resource "azurerm_virtual_network" "vnet" {
  name                = "prod-vnet"
  location            = var.location
  resource_group_name = azurerm_resource_group.net_group.name
  address_space       = ["10.0.0.0/16"]

  subnet {
    name           = "subnet1"
    address_prefix = "10.0.1.0/24"
  }
}

這段程式碼定義了一個名為 vnetazurerm_virtual_network 資源,用於建立一個 Azure 虛擬網路。namelocationresource_group_name 分別指定了虛擬網路的名稱、位置和資源群組。address_space 定義了虛擬網路的地址空間。巢狀的 subnet 區塊定義了一個名為 subnet1 的子網路,其地址字首為 10.0.1.0/24

迴圈與多個執行個體:簡化組態的利器

當你需要建立多個相似資源時,手動指定每個執行個體既繁瑣又容易出錯。Terraform 提供了 countfor_each 兩個元引數來簡化這個過程。它們支援資料來源、資源和模組,讓你能夠以迴圈方式建立多個執行個體。

Count:適用於簡單的重複

count 元引數接受一個非負整數值,Terraform 會建立與該整數相等數量的物件執行個體。例如,以下組態將建立四個 AWS EC2 執行個體:

resource "aws_instance" "web_servers" {
  count = 4

  name = "web-${count.index}"
}

count = 4 表示建立四個 EC2 執行個體。在迴圈過程中,可以使用 count.index 屬性來參照當前迴圈的索引,從 0 開始。這裡使用它來構建執行個體的名稱,例如 web-0web-1 等。

For_each:適用於複雜的場景

for_each 元引數接受一個集合或字串對映作為值。Terraform 會為集合中的每個元素或對映中的每個鍵建立一個物件執行個體。以下是一個使用集合的例子:

resource "aws_bucket" "mah_buckets" {
  for_each = toset(["Red", "Green", "Blue"])

  name = "this-is-my-${each.key}-bucket"
}

for_each = toset(["Red", "Green", "Blue"]) 表示建立三個 S3 儲存桶,分別對應集合中的三個元素。在迴圈過程中,可以使用 each.keyeach.value 來參照當前元素。這裡使用 each.key 來構建儲存桶的名稱,例如 this-is-my-Red-bucketthis-is-my-Green-bucket 等。

for_each 也支援使用對映:

resource "aws_bucket" "mah_buckets" {
  for_each = {
    Red   = "Sand"
    Green = "Rocks"
    Blue  = "Dirt"
  }

  name = "this-is-my-${each.key}-bucket"
  tags = {
    Contents = each.value
  }
}

這裡使用對映作為 for_each 的值,同樣會建立三個 S3 儲存桶。each.key 仍然用於構建儲存桶的名稱,而 each.value 則用於設定儲存桶的標籤。

串聯資源:構建完整架構

透過資源定址和引數應用,你可以將不同的資源串聯起來,構建完整的基礎架構。例如,你可以使用 azurerm_virtual_network.vnet.id 來參照前面建立的虛擬網路的 ID,並將其作為其他資源的引數,例如子網路或虛擬機器的組態。

resource "azurerm_subnet" "subnet" {
  # ... other configurations
  virtual_network_name = azurerm_virtual_network.vnet.name
  # ...
}

這段程式碼展示瞭如何使用資源定址將子網路與虛擬網路關聯起來。virtual_network_name 引數使用了 azurerm_virtual_network.vnet.name 來參照前面定義的虛擬網路的名稱。

藉由靈活運用資源定址和引數,你可以將 Terraform 的各個資源像拼圖一樣組合起來,開發出滿足你需求的基礎架構。

(圖表)

  graph LR
    subgraph 資料來源
        A[aws_ami] --> B(AMI ID)
    end
    subgraph 資源
        C[azurerm_virtual_network] --> D(Virtual Network)
        D --> E(Subnet)
        F[aws_instance] --> G(EC2 Instance)
    end
    B --> G
    D --> G

藉由理解和運用這些技巧,你將能夠更有效地使用 Terraform 管理和組態你的基礎設施。

深入解析 Terraform 設定:資源、函式與動態區塊

在 Terraform 的世界中,設定資源如同搭建基礎建設的藍圖,精確與靈活的設定至關重要。本文將探討如何在 Terraform 設定中參照資源、使用內建函式以及運用動態區塊,提升您的基礎設施即程式碼(IaC)技能。

資源參照與屬性取值

我們已經瞭解如何參照命名值和索引。資源的參照格式通常為 resource_type.<NAME>.<ATTRIBUTE>,例如 azurerm_resource_group.net_group.name。如果您使用 for_eachcount 引數建立多個資源例項,則傳回值將分別為對映或列表。

以下是一個 Azure 虛擬網路設定的範例,其中 resource_group_name 引數參照了我們建立的 net_group 資源群組的名稱屬性:

resource "azurerm_resource_group" "net_group" {
  name     = "net-group"
  location = "eastus"
}

resource "azurerm_virtual_network" "vnet" {
  name                = "prod-vnet"
  location            = var.location
  resource_group_name = azurerm_resource_group.net_group.name
  address_space       = ["10.0.0.0/16"]

  subnet {
    name           = "subnet1"
    address_prefix = "10.0.1.0/24"
  }

  subnet {
    name           = "subnet2"
    address_prefix = "10.0.2.0/24"
  }
}

azurerm_resource_group 資源也匯出了 id 屬性,可以透過 azurerm_resource_group.net_group.id 表示式存取。

某些引數和屬性可能是複雜值型別,這表示您可能需要使用特殊語法來提取所需的值。在上面的虛擬網路引數中,我們定義了兩個子網路。虛擬網路資源會為每個定義的子網路匯出帶有 id 屬性的子網路區塊。以下表達式將檢索子網路的不同方面:

  • azurerm_virtual_network.vnet.subnet:檢索一組子網路,每個子網路都帶有定義子網路的屬性對映。
  • azurerm_virtual_network.vnet.subnet[*].id:使用 splat 運算元 * 檢索每個子網路的 id 屬性列表。

由於 subnet 屬性傳回的是集合而不是列表或對映,因此您無法透過索引或鍵參照特定子網路。您可以使用 for 表示式迭代集合並從每個子網路中選擇名稱鍵 [for subnet in azurerm_virtual_network.vnet.subnet : subnet["name"]]。該表示式將傳回子網路名稱的列表。

理解屬性或引數傳回的資料型別至關重要。

Terraform 內建函式的應用

資料來源和資源傳回的資料格式可能與您需要傳遞給另一個資源的格式不同。您可能還想轉換模組的輸出、組合變數或讀取檔案資料。Terraform 提供了內建函式來執行許多這類別任務。函式的基本格式為 function(arguments,...)

以下是一些例子:

  • max(number,number,...):傳回給定集合中的最大值。
  • lower(string):將字串轉換為小寫。
  • keys(map):傳回給定對映中的鍵列表。

您可以使用 terraform console 命令測試函式的輸出。如果您位於包含 Terraform 設定的目錄中,它將載入目前的狀態,以便您可以存取狀態資料來測試函式和其他插值。

動態區塊的組態與使用

在上一節中,我們看到了虛擬網路的示例,其中單個子網路定義為巢狀區塊。您很可能在虛擬網路中擁有多個子網路。您可以為每個子網路定義一個單獨的巢狀區塊,但這不是可擴充套件或動態的方法。更有意義的做法是根據變數中的值動態生成巢狀區塊。建立巢狀區塊的機制稱為動態區塊。

動態區塊可以在資源、資料來源、提供者和供應器內使用。它的工作方式類別似於 for 表示式。for 表示式產生列表或對映型別的集合。動態區塊表示式產生一個或多個巢狀區塊。

resource "azurerm_virtual_network" "vnet" {
  # ... other configurations

  dynamic "subnet" {
    for_each = var.subnets
    content {
      name           = subnet.value.name
      address_prefix = subnet.value.address_prefix
    }
  }
}

variable "subnets" {
  type = list(object({
    name           = string
    address_prefix = string
  }))
  default = [
    {
      name           = "subnet1"
      address_prefix = "10.0.1.0/24"
    },
    {
      name           = "subnet2"
      address_prefix = "10.0.2.0/24"
    }
  ]
}

以上程式碼片段展示瞭如何使用 dynamic 區塊來動態建立子網路。for_each 引數迭代 var.subnets 變數中定義的子網路列表,content 區塊則定義了每個子網路的設定。

透過動態區塊,您可以根據變數值靈活地建立多個巢狀區塊,從而實作更具彈性和可維護性的 Terraform 設定。

總結:本文探討了 Terraform 設定中的資源參照、內建函式和動態區塊。這些技術能幫助您更有效地管理基礎設施,並編寫更具彈性和可維護性的程式碼。熟練掌握這些技巧,將使您在 IaC 領域更上一層樓。

駕馭Terraform動態區塊:靈活組態資源

在Terraform中,dynamic區塊提供了一種強大的機制,能根據變數動態生成多個巢狀區塊,大幅提升組態效率。以下是一個使用dynamic區塊組態Azure虛擬網路子網路的例子:

resource "azurerm_virtual_network" "vnet" {
  name                = "prod-vnet"
  location            = "eastus"
  resource_group_name = azurerm_resource_group.net_group.name
  address_space       = var.address_space

  dynamic "subnet" {
    for_each = var.subnet_data
    content {
      name           = subnet.value["name"]
      address_prefix = subnet.value["address_prefix"]
    }
  }
}

這段程式碼定義了一個Azure虛擬網路,並使用dynamic區塊動態生成多個子網路。dynamic "subnet"宣告了一個名為subnet的動態區塊,for_each引數指定了迭代的資料來源var.subnet_data,它應該是一個map或set,每個元素包含一個子網路的組態資訊。content區塊定義了每個子網路的組態,其中subnet.value["name"]subnet.value["address_prefix"]分別代表子網路的名稱和地址字首。

subnet_data變數可以像這樣定義:

variable "subnet_data" {
  default = {
    subnet1 = {
      name           = "subnet1"
      address_prefix = "10.0.1.0/24"
    }
    subnet2 = {
      name           = "subnet2"
      address_prefix = "10.0.2.0/24"
    }
  }
}

此處subnet_data是一個map,鍵值分別為subnet1subnet2,對應的值是包含子網路名稱和地址字首的map。在每次迭代中,迭代器subnet會載入map中的一個元素,並用於生成對應的子網路。

雖然dynamic區塊功能強大,但也會降低程式碼可讀性。因此,應謹慎使用,在提升效率的同時兼顧程式碼的可維護性。

Terraform內建依賴管理:自動化資源佈署順序

Terraform會自動建立資源圖譜,分析資源間的依賴關係,確保資源以正確的順序建立。例如,建立虛擬機器、虛擬網路介面卡和DNS記錄時,Terraform會自動判斷虛擬網路介面卡依賴於虛擬網路,虛擬機器依賴於虛擬網路介面卡,DNS記錄依賴於虛擬機器的公有IP地址。

  graph LR
    C[C]
    A[虛擬網路] --> B(虛擬網路介面卡)
    B --> C{虛擬機器}
    C --> D[DNS記錄]

上圖展示了資源的建立順序,箭頭方向表示依賴關係。Terraform會先建立虛擬網路,然後是虛擬網路介面卡,接著是虛擬機器,最後是DNS記錄。

如果資源間的依賴關係無法自動推斷,可以使用depends_on引數顯式指定。但應盡量避免使用depends_on,因為它可能會增加程式碼的複雜性,並降低Terraform的自動化程度。

設定最佳化:提升Terraform效能

以下是一些Terraform設定的最佳化技巧:

  • 善用變數和輸出:變數用於向Terraform組態提交值,輸出主要用於在模組間傳遞資訊。
  • 安全地注入敏感資訊:避免將敏感資訊儲存在.tfvars檔案或命令列引數中,應使用環境變數。
  • 理解集合和結構型別:熟悉string、number、boolean、map、list、set、object和tuple等資料型別。
  • 區分資源和資料來源:資料來源用於取得現有資源的資訊,資源用於建立新的資源。
  • 使用資源定址和引數連線資源:正確使用資源的屬性和引數,確保資源之間的正確連線。
  • 使用內建函式:Terraform提供豐富的內建函式,可用於資料處理和轉換。

透過這些最佳化技巧,可以提升Terraform的效能和程式碼品質,讓你的基礎架構管理更加高效和可靠。

總結:本文探討了Terraform的動態區塊、依賴管理和設定最佳化等進階技巧。透過理解這些概念,並結合實踐經驗,可以更好地運用Terraform管理你的基礎架構。

玄貓解說 Terraform Enterprise 的強大功能

Terraform Enterprise 是 Terraform Cloud 的內部佈署版本,提供企業一個私有的 Terraform Cloud 應用程式例項,沒有資源限制,並具備額外的企業級架構功能,例如稽核日誌和 SAML 單一登入。Terraform Cloud 是 Terraform Enterprise 的雲端託管版本,具有許多相同的企業級架構功能。在大多數情況下,Terraform Enterprise 和 Terraform Cloud 可以視為同一產品。雖然終端目標特別提到了 Terraform Enterprise,但 Terraform Cloud 也是這個目標的一部分。

Sentinel、Registry 和 Workspace 的優勢解析

Sentinel:策略守護者

Sentinel 是一種策略語言和框架,旨在嵌入現有軟體中,實作根據邏輯的細粒度策略決策。策略描述了在何種情況下允許某些行為。Sentinel 是 HashiCorp Consul、Nomad、Terraform 和 Vault 的企業專屬功能。

Terraform Enterprise 使用 Sentinel 對 Terraform 組態、狀態和計劃實施策略。與 Terraform 整合的 Sentinel 在 terraform plan 之後和 terraform apply 之前在 Terraform Cloud 中執行。這些策略可以存取已建立的計劃、計劃時的狀態以及計劃時的組態。

Sentinel 策略是在 Terraform 執行時強制執行的規則,用於驗證計劃和相應的資源是否遵循公司策略。將策略新增至組織後,它將在所有執行時強制執行。

策略檢查將在計劃在執行中成功執行後立即進行。如果計劃失敗,則不會執行策略檢查。策略檢查使用生成的 tfplan 檔案、模擬的應用程式物件、狀態和組態來驗證每個策略中的規則。

簡而言之,Sentinel 策略可以驗證 terraform 計劃結果是否符合公司要求(在 Sentinel 策略中定義),如果不符合,則會阻止建立這些資源(透過 terraform apply)。

以下是一個簡單的 Sentinel 策略範例,用於限制 AWS EC2 instance 的型別:

import "tfplan"

main = rule {
  all tfplan.resources.aws_instance as _, instance {
    instance.applied.instance_type in ["t2.micro", "t3.micro"]
  }
}

這個策略會檢查所有 aws_instance 資源,確保它們的 instance_type 屬性值是 t2.microt3.micro。如果不是,策略檢查將會失敗,阻止 terraform apply 執行。

Registry:模組與提供者分享中心

Terraform 有一個公開的 Registry,用於 Terraform 模組和提供者,網址為 https://registry.terraform.io。有些組織可能不想將公開的 Registry 用於他們的模組和外掛。Terraform Cloud 提供了一個私有 Registry 功能,允許組織中的團隊私下分享模組和提供者外掛,包括支援版本控制、組態設計和搜尋功能。

組織可以透過選擇 Terraform Enterprise(Terraform Cloud 的本地託管版本)來進一步私有化他們的 Registry。在這種情況下,私有 Registry 託管在公司擁有的硬體上,並且不暴露於網際網路。

Workspace:基礎架構組態中心

Terraform Cloud 中的 Workspace 與 Terraform CLI 中的 Workspace 稍有不同。Workspace 是 Terraform Cloud 組織基礎架構組態的方式,包括組態、變數、狀態和日誌。

Terraform Cloud Workspace 包含:

  • Terraform 組態(通常從 VCS 儲存函式庫中擷取,但有時會直接上傳)
  • 組態使用的變數值
  • 作為敏感變數儲存的憑證和機密
  • 受管資源的持續儲存狀態
  • 歷史狀態和執行日誌

您仍然可以像在 Terraform OSS 中對多個 Workspace 使用相同的目錄一樣,對多個 Workspace 使用相同的儲存函式庫。最大的改進實際上是在管理變數、憑證和機密的值方面。使用指向您正在使用的 VCS 的 Webhook 自動化更新也更簡單。

OSS 和 TFE Workspace 的比較

在探討 Terraform Cloud 和 Terraform CLI 中 Workspace 的差異之前,讓我們先來看看 Terraform Cloud 和 OSS 之間的差異。Terraform 開源軟體 (OSS) 是免費的開源 CLI,您可以在本地系統上下載和執行它。

在 2019 年 Terraform Cloud 發布之前,HashiCorp 有一個名為 Terraform Enterprise 的託管產品。它建立在 Terraform OSS 之上,同時新增了多項增強功能和額外功能。Terraform Enterprise 也可以在內部佈署的伺服器上執行,這稱為私有 Terraform Enterprise。

Terraform Enterprise 的託管版本已重新命名為 Terraform Cloud,同時進行了多項授權更新,並為五人或五人以下的團隊提供免費層級。私有 Terraform Enterprise 已重新命名為 Terraform Enterprise,並繼續在內部佈署執行。自然,當人們提到 Terraform Enterprise 時,這會導致相當多的混淆,因此這裡有一個有用的提醒:

  • Terraform OSS - 免費和開源的 CLI
  • Terraform Cloud - 團隊託管的 Terraform(以前的 Terraform Enterprise)
  • Terraform Enterprise - 企業內部佈署的 Terraform(以前的私有 Terraform Enterprise)

好了,說完這些,我們可以討論 Terraform OSS 和 Terraform Cloud 中的 Workspace 了。

開源軟體 (OSS)

在目標 4:使用 Terraform CLI 中,我們討論了 Workspace;如何建立它們以及何時使用它們。Terraform OSS 中 Workspace 的核心概念是對多個環境使用相同的組態,但 Terraform 管理的每個環境都有單獨的狀態檔案。

有趣的是,Workspace 以前稱為環境,如果您檢視 terraform 的可用子命令,其中一個是 env - 環境的縮寫。該子命令仍然存在是為了向後相容,但它本質上是 Workspace 子命令的別名。

Terraform OSS 中的 Workspace 僅處理狀態管理,而不處理組態的其他方面,例如提交的變數值或先前操作的日誌。如果您想為每個 Workspace 提交不同的值,則需要將其納入您的指令碼或管道的邏輯中。

Terraform Cloud

Terraform Cloud 採用不同的方法來使用 Workspace。狀態管理元件仍然存在,但上面新增了一些額外功能。Terraform Cloud 產品與 GitHub 和 GitLab 等版本控制系統 (VCS) 整合。Terraform Cloud 中的 Workspace 建構指向其組態的 VCS 儲存函式庫。變數值、狀態、機密和憑證也儲存在 Workspace 設定中。

Terraform Cloud Workspace 的優勢在於簡化了變數、憑證和機密的管理,並透過與 VCS 的 Webhook 整合,更容易實作自動化更新。

總而言之,Terraform Enterprise 提供了 Sentinel、Registry 和 Workspace 等強大功能,協助企業更好地管理和控制基礎架構。透過瞭解這些功能的優勢和差異,您可以更有效地利用 Terraform Enterprise 來構建和管理您的基礎架構。

Terraform Cloud:協同基礎設施的利器

身為一個在不同環境下管理過大量基礎設施的技術工作者,我深刻體會到協同工作和自動化流程的重要性。Terraform Cloud 正是為瞭解決這些痛點而生的強大工具。它不僅僅是 Terraform 的雲端託管版本,更是一個功能豐富的平台,能簡化團隊合作、提升基礎設施管理效率。

本文將探討 Terraform Cloud 的核心功能,並分享我個人的使用心得和最佳實踐。

工作空間:版本控制與狀態管理的完美結合

Terraform Cloud 的工作空間(Workspace)功能巧妙地將版本控制系統(VCS)與狀態管理整合在一起。每個工作空間都與一個 VCS 倉函式庫連結,並包含了 Terraform 組態、變數值、持久狀態和歷史記錄。這種設計讓團隊成員可以輕鬆分享和管理基礎設施組態,同時確保狀態的一致性和可追溯性。

我曾在一個大型專案中使用 Terraform Cloud 的工作空間功能,有效地避免了團隊成員之間的組態衝突和狀態不一致問題。透過將工作空間與 Git 倉函式庫連結,我們可以追蹤每次變更,並輕鬆回復到之前的狀態。

模組登入檔:構建可重複使用基礎設施的根本

Terraform Cloud 的私有模組登入檔(Private Module Registry)功能讓團隊可以安全地分享和管理內部模組。這對於構建可重複使用的基礎設施至關重要。透過將常用的基礎設施元件封裝成模組,並將其釋出到私有登入檔,團隊成員可以輕鬆地複用這些模組,避免重複工作,並確保基礎設施的一致性。

我個人強烈建議將模組化設計作為 Terraform 專案的標準實踐。透過使用模組,我們可以將複雜的基礎設施分解成更小、更易於管理的單元,並提高程式碼的可讀性和可維護性。

遠端執行:安全可靠的自動化流程

Terraform Cloud 的遠端執行功能利用託管的、一次性的虛擬機器來執行 Terraform 命令。這種設計提供了更高的安全性和可靠性,同時也簡化了執行環境的管理。此外,Terraform Cloud 還支援 Sentinel 策略執行和成本估算等進階功能,進一步提升了基礎設施管理的效率。

我曾在一個安全性要求極高的專案中使用 Terraform Cloud 的遠端執行功能,有效地控制了對基礎設施的存取許可權,並確保了操作的合規性。

VCS 整合:自動化流程的關鍵

Terraform Cloud 與主流 VCS 系統的無縫整合,例如 Git,是實作自動化流程的關鍵。透過將 Terraform Cloud 與 VCS 連結,我們可以根據程式碼變更自動觸發 Terraform 執行,例如在提交程式碼或建立 Pull Request 時自動執行 terraform planterraform apply

這種自動化流程可以大幅提升團隊效率,並減少人為錯誤。我個人建議在所有 Terraform 專案中都使用 VCS 整合,並建立自動化的 CI/CD 流程。

  graph LR
    B[B]
    D[D]
    A[程式碼變更] --> B{Terraform Cloud};
    B --> C[Plan];
    C --> D{批准};
    D --> E[Apply];

上圖展示了 Terraform Cloud 與 VCS 整合後的自動化流程。當程式碼發生變更時,Terraform Cloud 會自動觸發 Plan 階段,生成執行計劃。經過批准後,Terraform Cloud 會執行 Apply 階段,將變更應用到基礎設施。

Sentinel:精細化策略控制的利器

Sentinel 是一種策略即程式碼的框架,可以實作精細化的策略控制。透過使用 Sentinel,我們可以定義複雜的規則來限制對基礎設施的存取和操作,例如限制特定資源的建立或修改。

我曾在一個需要嚴格控制成本的專案中使用 Sentinel,有效地防止了意外的資源浪費。

Terraform Cloud 提供了豐富的功能,能有效提升團隊協作效率和基礎設施管理水平。從工作空間到模組登入檔,從遠端執行到 VCS 整合,Terraform Cloud 的每個功能都經過精心設計,旨在簡化複雜的基礎設施管理任務。我強烈建議所有使用 Terraform 的團隊都考慮使用 Terraform Cloud,它將為你的基礎設施管理帶來巨大的價值。