返回文章列表

TerraformCLI進階應用與狀態管理

本文探討 Terraform CLI 的進階應用,涵蓋程式碼格式化、資源汙染標記、現有基礎設施匯入及工作空間管理等導向。文章將詳細說明`terraform fmt`、`terraform taint`、`terraform import` 和 `terraform workspace`

DevOps 雲端運算

Terraform 的核心工作流程固然重要,但其 CLI 提供的進階功能更能提升效率與彈性。本篇將著重探討程式碼格式化、資源汙染與修復、現有基礎設施匯入 Terraform 管理,以及工作空間的應用。這些技巧能幫助工程師更有效率地維護程式碼品質、處理異常資源、整合既有環境以及管理多個佈署狀態。透過 terraform fmt 確保程式碼風格一致性,簡化團隊協作;使用 terraform taint 精準標記需重建的資源,避免不必要的變更;terraform import 則能將外部資源納入 Terraform 管理,實作單一平台控管;最後,善用工作空間區分不同環境的狀態,降低佈署風險。

Terraform CLI 的進階應用

在前面的章節中,我們已經介紹了 Terraform 的基本用法和核心工作流程。本章節將重點介紹如何在核心工作流程之外使用 Terraform CLI,包括程式碼格式化、資源汙染(taint)、以及匯入現有基礎設施到 Terraform 狀態等進階主題。

使用 terraform fmt 進行程式碼格式化

Terraform 提供了一個非常有用的命令 terraform fmt,用於將 Terraform 組態檔案格式化為規範的格式。這有助於保持程式碼的一致性和可讀性,尤其是在團隊協作的專案中。

程式碼格式化範例

假設我們有以下 Terraform 組態檔案:

1 provider "azurerm" {
2 environment = "public"
3 }
4
5 module "vnet" {
6 source = "Azure/vnet/azurerm"
7 resource_group_name = "tacos"
8 location = "westus"
9 address_space = "10.0.0.0/16"
10 subnet_prefixes = ["10.0.1.0/24", "10.0.2.0/24"]
11 subnet_names = ["cheese", "beans"]
12 }

執行 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"]
}

使用 -recursive 選項

如果你有多個 Terraform 組態檔案分散在不同的子目錄中,可以使用 -recursive 選項來對所有組態檔案進行格式化:

terraform fmt -recursive

這將對當前目錄及其所有子目錄中的 Terraform 組態檔案進行格式化。

使用 terraform taint 汙染資源

terraform taint 命令用於將一個資源標記為汙染,表示該資源需要被銷毀並重新建立。這在某些情況下非常有用,例如當資源的內部狀態變得不正確或需要重新組態時。

使用 terraform taint 的範例

假設我們有一個 aws_instance 資源,名稱為 nginx

resource "aws_instance" "nginx" {
  # 組態內容
}

執行以下命令將該資源標記為汙染:

terraform taint aws_instance.nginx

輸出結果將顯示資源已被標記為汙染:

Resource instance aws_instance.nginx has been marked as tainted.

檢視汙染資源

執行 terraform show 命令可以檢視資源的當前狀態,包括汙染標記:

terraform show

輸出結果將顯示 aws_instance.nginx 資源已被標記為汙染:

# aws_instance.nginx: (tainted)
resource "aws_instance" "nginx" {
  # 組態內容
}

解除汙染標記

如果需要解除汙染標記,可以使用 terraform untaint 命令:

terraform untaint aws_instance.nginx

使用 terraform import 匯入現有基礎設施

terraform import 命令允許你將現有的基礎設施資源匯入到 Terraform 的狀態中,從而實作對這些資源的管理。

使用 terraform import 的範例

假設我們有一個現有的 AWS EC2 例項,需要將其匯入到 Terraform 中。首先,需要在 Terraform 組態檔案中定義該資源:

resource "aws_instance" "example" {
  # 組態內容(可以先留空,匯入後再完善)
}

然後,執行以下命令匯入該資源:

terraform import aws_instance.example i-1234567890abcdef0

這將把 ID 為 i-1234567890abcdef0 的 EC2 例項匯入到 Terraform 狀態中,並與組態檔案中的 aws_instance.example 資源對應起來。

使用 Terraform CLI(核心工作流程以外)

目標 4:使用 Terraform CLI(核心工作流程以外)

在許多情況下,管理員可能會手動在 Terraform 管理範圍以外建立資源,而這些資源需要被納入 Terraform 的管理。理想情況下,一旦採用 Terraform,所有新的資源都應該透過 Terraform 建立和管理。

截至目前為止,Terraform 的最新版本不會為匯入的資源自動生成組態,它只是將資源新增到狀態中。因此,在執行匯入命令之前,您需要手動編寫與現有資源相比對的組態。雖然這個過程效率不高,但也有其好處。為現有資源編寫組態可能會讓您更深入地瞭解這些資源是如何被建立的,並突出任何與最佳實踐的偏差。HashiCorp 表示,未來的 Terraform 版本將能夠生成組態。

情境

直到最近,DevOps 才開始在 IT 維運領域流行起來。在此之前,大多數使用雲端的組織都是透過手動(透過 GUI)或指令碼(例如 PowerShell、Bash 等)來佈署資源。雖然有些組織可能使用了 API 或範本(這與 Terraform 的做法類別似),但這些方法通常是一次性的。

透過 Terraform 的狀態檔案(在目標 2B:解釋狀態的好處和目標 7:實施和維護狀態中有詳細介紹),我們有了一種持續管理資源的方法。

當一個組織開始使用 Terraform 時,他們很可能已經在雲端佈署了一些資源。在這種情況下,假設您的組織有多個虛擬機器,也許是為了高用性而進行了負載平衡。您希望使用 Terraform 來管理它們,以便您可以透過簡單的程式碼更改(例如 nodeCount = 3)快速擴充套件或縮減叢集。

此時,您有三個選項:

  1. 刪除現有的基礎架構,並使用 Terraform 組態重新佈署(如果是在生產環境中,這不是一個可行的選項)。
  2. 使用 Terraform 組態建立一套新的基礎架構,並將資料/內容遷移到新的環境(這將導致費用增加,因為需要臨時維持雙倍的基礎架構)。
  3. 編寫一個 Terraform 組態(就好像您正在佈署一套新的相同的基礎架構),並使用 terraform import 將現有的佈署納入 Terraform 的管理之下。

使用 terraform import 的好處

透過使用 terraform import,您不需要重新建立任何基礎架構(因此避免了停機的問題),並且可以使用基礎架構即程式碼(IaC)來管理整個雲端環境。

如果您想嘗試使用 import 命令,可以使用 terraform state rm 命令從狀態檔案中刪除一個資源。物理資源將繼續存在。然後,使用 terraform import 命令將其重新匯入狀態檔案。

補充資訊

重點

  • terraform import 可以將現有的資源納入 Terraform 的管理。
  • 單純的匯入並不會為資源建立必要的組態,這需要手動完成。

工作空間(Workspace)

在 Terraform 開源版本中,工作空間是用於管理具有共同組態的不同狀態檔案的機制。許多組織有多個環境,包括開發、測試、預釋出和生產環境。每個 Terraform 工作空間代表了一個組態在不同工作環境中的佈署。這使得您可以使用單一組態來管理所有環境中的相同佈署,從而在應用程式滾動到生產環境時提高一致性。

工作空間的管理

工作空間由 terraform workspace 命令集管理。以下是可用的子命令:

  • new:建立一個新的工作空間並選擇它
  • select:選擇一個現有的工作空間
  • list:列出現有的工作空間
  • show:顯示當前工作空間的名稱
  • delete:刪除一個空的工作空間

工作流程

要建立一個新的工作空間,只需執行 terraform workspace new development。這樣就會建立一個新的工作空間並切換到它。


#### 內容解密:
這段程式碼展示瞭如何使用 `terraform workspace new` 命令建立一個新的工作空間
- `terraform workspace new` 是建立新工作空間的命令
- `development` 是新工作空間的名稱
這個命令會建立一個新的工作空間並自動切換到該工作空間允許您在不同的環境中管理您的基礎架構組態

Terraform 工作區與狀態管理

Terraform 提供了一個強大的工具來管理和隔離不同環境下的基礎架構設定。透過使用工作區(Workspaces),使用者可以在相同的 Terraform 組態下管理多個獨立的狀態檔案。

工作區的使用

當你使用 terraform workspace 命令建立新的工作區時,Terraform 會在 .terraform.tfstate.d 目錄下為每個工作區建立一個子目錄,用於儲存該工作區的狀態檔案。例如:

├───.terraform
│ └───plugins
│ └───windows_amd64
└───terraform.tfstate.d
    ├───development
    ├───staging
    └───production

每個工作區都有其獨立的狀態檔案,這使得不同團隊或環境下的資源管理變得更加靈活和安全。

工作區的應用場景

在大型組織中,不同團隊負責不同的 Terraform 組態,例如網路團隊、治理團隊和應用程式團隊。每個團隊可以使用不同的工作區來管理他們各自的環境,例如 networking-devnetworking-stagenetworking-prod 等。

這種做法的好處包括:

  1. 角色與許可權的分離:每個團隊可以獨立管理自己的工作區,無需擔心影響其他團隊的資源。
  2. 環境隔離:不同環境(如開發、測試、生產)下的資源可以被妥善隔離,避免意外修改或刪除。

Terraform 狀態管理

Terraform 的狀態檔案是一個 JSON 檔案,用於記錄目前基礎架構的狀態。雖然可以直接編輯狀態檔案,但強烈建議不要這樣做,因為這可能會導致 Terraform 的狀態與實際基礎架構不一致。

相反,應該使用 terraform state 命令來與狀態檔案互動。該命令提供了一系列子命令,例如:

  • list:列出狀態檔案中的資源
  • mv:移動狀態檔案中的資源
  • pull:將遠端狀態檔案提取到本地
  • push:將本地狀態檔案推播到遠端
  • rm:從狀態檔案中移除資源
  • show:顯示狀態檔案中的資源詳細資訊

資源定址

在使用 terraform state 命令時,需要使用資源定址(Resource Addressing)來指定特定的資源。資源定址的語法為 [module path][resource spec],例如 module.my-vnet.azurerm_subnets.subnet[0]

列出資源

使用 terraform state list 命令可以列出狀態檔案中的資源。該命令的語法為 terraform state list [options] [address...],例如:

terraform state list

該命令將列出目前狀態檔案中的所有資源。

使用 Terraform CLI(核心工作流程以外)

Terraform 提供了一系列強大的命令列工具,能夠在核心工作流程之外進行更精細的操作與管理。這些命令能夠幫助使用者更有效地管理其基礎設施狀態。

檢視 Terraform 狀態

使用 terraform state list 命令可以列出目前 Terraform 管理的所有資源。這對於瞭解目前的佈署狀態以及選擇特定資源進行進一步操作非常有幫助。

範例輸出

$> 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 狀態中移動資源或模組。此命令的語法為:terraform state mv [options] SOURCE DESTINATION

重要選項

  • dry-run:預覽將要執行的操作,而不實際進行變更。
  • state:指定來源狀態檔案的路徑。
  • state-out:指定目標狀態檔案的路徑。

此命令可用於重新命名資源、將資源移動到不同的模組或狀態檔案中。

範例:重新命名資源

假設我們要將 aws_instance.nginx 重新命名為 aws_instance.web,首先需要更新相關的 Terraform 組態:

# 原始組態
resource "aws_instance" "nginx" {
  # ...
}

# 更新後的組態
resource "aws_instance" "web" {
  # ...
}

執行 terraform plan 後會發現 Terraform 計畫銷毀舊資源並建立新資源:

# aws_instance.nginx will be destroyed
- resource "aws_instance" "nginx" {
  # ...

# aws_instance.web will be created
+ resource "aws_instance" "web" {
  # ...

Plan: 1 to add, 0 to change, 1 to destroy.

使用 terraform state mv 命令更新狀態:

$> terraform state mv aws_instance.nginx aws_instance.web
Move "aws_instance.nginx" to "aws_instance.web"
Successfully moved 1 object(s).

再次執行 terraform plan,會發現沒有需要執行的變更:

No changes. Infrastructure is up-to-date.

從遠端後端提取狀態

terraform state pull 命令用於手動下載並輸出遠端後端中的狀態。此命令的語法為:terraform state pull [options]

此命令輸出的狀態為 JSON 格式,可以進一步使用工具(如 jq)進行處理。

使用範例

$> terraform state pull | jq '.resources[] | select(.type == "aws_instance")'

上傳本地狀態到遠端後端

terraform state push 命令用於手動上傳本地狀態檔案到遠端後端。此命令的語法為:terraform state push [options] PATH

風險提示

此操作具有較高的風險,因為它會覆寫遠端後端的狀態。在執行此操作前,請務必確認本地狀態檔案的正確性和時效性。

安全檢查

Terraform 會檢查本地狀態和遠端狀態的 lineageserial 值,以防止意外覆寫。如果需要強制上傳,可以使用 -force 選項。

從 Terraform 狀態中移除資源

terraform state rm 命令用於從 Terraform 狀態中移除指定的資源或模組。此命令的語法為:terraform state rm [options] ADDRESS

使用範例

$> terraform state rm aws_instance.nginx

Terraform CLI 高階應用:狀態管理與除錯

Terraform 不僅能在核心工作流程中發揮強大功能,其命令列介面(CLI)還提供了多種進階功能,幫助使用者更好地管理基礎設施狀態和除錯。

狀態管理:terraform state rm 命令

在某些情況下,我們可能需要從 Terraform 的狀態檔案中移除特定的資源,而不實際刪除該資源。這時,可以使用 terraform state rm 命令。

使用場景

假設我們不再希望使用 Terraform 管理 aws_instance.web 例項。首先,可以執行以下命令:

$> terraform state rm aws_instance.web
Removed aws_instance.web
Successfully removed 1 resource instance(s).

內容解密:

  1. terraform state rm aws_instance.web:此命令將 aws_instance.web 從 Terraform 的狀態檔案中移除。
  2. 狀態檔案更新:執行該命令後,Terraform 將不再管理該資源,但資源本身在雲端環境中仍然存在。
  3. 組態檔案的處理:需要手動從組態檔案中移除相關資源定義,否則下次執行 terraform planterraform apply 時,Terraform 可能會嘗試重新建立該資源。

檢視資源屬性:terraform state show 命令

使用 terraform state show 命令,可以檢視特定資源的詳細屬性。

使用場景

若要檢視 aws_instance.web 的屬性,可以執行:

$> terraform state show aws_instance.web
# aws_instance.web:
resource "aws_instance" "web" {
  ami = "ami-00eb20669e0990cb4"
  arn = "arn:aws:ec2:us-east-1:123456789123:instance/i-078e3d0f003ac07bf"
  associate_public_ip_address = true
  availability_zone = "us-east-1d"
  cpu_core_count = 1
  cpu_threads_per_core = 1
  [...]
}

內容解密:

  1. terraform state show aws_instance.web:顯示 aws_instance.web 資源的詳細屬性。
  2. 屬性列表:輸出的屬性按字母順序排列,可用於進一步的自動化處理或匯入組態管理資料函式庫(CMDB)。

除錯與日誌記錄

當 Terraform 執行過程中出現問題時,可以透過啟用詳細日誌記錄來幫助排查錯誤。

設定日誌級別

Terraform 支援五種日誌級別:TRACE、DEBUG、INFO、WARN 和 ERROR。使用者可以透過設定 TF_LOG 環境變數來選擇所需的詳細程度。

export TF_LOG=DEBUG

此外,還可以將日誌輸出到指設定檔案:

export TF_LOG_PATH=/var/logs/terraform/my_log.log

使用場景

terraform apply 失敗且標準錯誤輸出資訊不足時,可以啟用詳細日誌來取得更多除錯資訊。

內容解密:

  1. TF_LOG 環境變數:控制 Terraform 的日誌詳細程度。
  2. TF_LOG_PATH 環境變數:指定日誌檔案的儲存路徑。
  3. 當機日誌:若 Terraform 發生當機,將自動生成 crash.log 檔案,包含除錯資訊和錯誤回溯,用於提交錯誤報告。