Terraform 狀態檔案是管理基礎設施即程式碼的關鍵,它記錄了基礎設施的目前狀態,並協助 Terraform 追蹤變更和避免組態漂移。當執行 Terraform 命令時,它會載入程式碼和狀態檔案,並重新整理狀態以確保與實際基礎設施同步,進而精確管理基礎設施。善用狀態檔案能提升管理效率和準確性,並有效解決組態漂移問題。本文將逐步示範如何使用 Terraform 在 Azure 上建立和管理資源群組、容器登入函式庫和 Kubernetes 叢集,並涵蓋佈署微服務應用程式到 Kubernetes 叢集的完整流程,包含取得憑證、構建和推播 Docker 映像、更新佈署組態等步驟,最後也提醒讀者在非必要情況下及時銷毀基礎設施以避免產生額外成本。

Terraform狀態檔案的必要性

Terraform狀態檔案是必要的,因為它允許Terraform跟蹤基礎設施的變化和組態漂移。當我們修改Terraform程式碼時,基礎設施可能會出現組態漂移,這意味著實際的基礎設施與我們宣告的基礎設施不匹配。Terraform狀態檔案可以幫助我們解決這個問題。

Terraform狀態檔案的工作原理

當我們執行Terraform時,它會載入我們的程式碼和狀態檔案。然後,它會重新整理狀態檔案以確保它與實際的基礎設施同步。這樣,Terraform就可以跟蹤基礎設施的變化和組態漂移。

Terraform狀態檔案的優點

使用Terraform狀態檔案有幾個優點:

  • 它允許Terraform跟蹤基礎設施的變化和組態漂移。
  • 它可以幫助我們解決基礎設施組態漂移的問題。
  • 它可以提高基礎設施管理的效率和準確性。

Destroy和Recreate基礎設施

在本章中,我們還將探討如何使用Terraform Destroy和Recreate基礎設施。這是一個重要的步驟,因為它可以幫助我們測試和驗證基礎設施的組態和變化。

  flowchart TD
    A[開始] --> B[載入程式碼和狀態檔案]
    B --> C[重新整理狀態檔案]
    C --> D[跟蹤基礎設施變化]
    D --> E[Destroy和Recreate基礎設施]

圖表翻譯:

上述Mermaid圖表展示了Terraform狀態檔案的工作流程。首先,Terraform載入我們的程式碼和狀態檔案。然後,它重新整理狀態檔案以確保它與實際的基礎設施同步。接下來,Terraform跟蹤基礎設施的變化和組態漂移。最後,Terraform可以使用Destroy和Recreate基礎設施來測試和驗證基礎設施的組態和變化。

使用Terraform進行基礎設施管理

在本文中,我們將探討如何使用Terraform進行基礎設施管理。Terraform是一種基礎設施即程式碼(Infrastructure as Code, IaC)工具,允許我們使用程式碼定義和管理基礎設施。

安裝Terraform

首先,我們需要安裝Terraform。在Azure中,我們可以使用Azure CLI來安裝Terraform。

初始化Terraform專案

接下來,我們需要初始化Terraform專案。這可以使用terraform init命令來完成。

建立Azure資源群組

然後,我們可以使用Terraform來建立Azure資源群組。這可以使用azurerm_resource_group資源來完成。

resource "azurerm_resource_group" "example" {
  name     = "example-resource-group"
  location = "eastus"
}

刪除資源群組

如果我們想要刪除資源群組,可以使用terraform destroy命令來完成。

terraform destroy

建立容器登記函式庫

接下來,我們需要建立容器登記函式庫。這可以使用azurerm_container_registry資源來完成。

resource "azurerm_container_registry" "example" {
  name                     = "example-container-registry"
  resource_group_name      = azurerm_resource_group.example.name
  location                 = azurerm_resource_group.example.location
  sku                      = "Basic"
  admin_enabled            = true
}

引數化Terraform程式碼

最後,我們可以引數化Terraform程式碼,以便建立多個例項。這可以使用variable資源來完成。

variable "environment" {
  type = string
}

resource "azurerm_resource_group" "example" {
  name     = "${var.environment}-resource-group"
  location = "eastus"
}

建立私有容器登入函式庫

在 Azure 中,建立私有容器登入函式庫是一個簡單的過程。首先,我們需要定義資源群組和位置。然後,我們可以建立容器登入函式庫資源,並設定其名稱、SKU 和其他屬性。

resource "azurerm_container_registry" "flixtube" {
  name                     = "flixtube"
  resource_group_name      = azurerm_resource_group.flixtube.name
  location                 = azurerm_resource_group.flixtube.location
  admin_enabled            = true
  sku                      = "Basic"
}

容器登入函式庫屬性解釋

  • name: 容器登入函式庫的名稱,必須唯一。
  • resource_group_name: 資源群組的名稱,與 Terraform 中定義的資源群組名稱相對應。
  • location: 容器登入函式庫的位置,必須與資源群組的位置相同。
  • admin_enabled: 啟用或停用管理員帳戶,以便遠端驗證登入函式庫。
  • sku: 容器登入函式庫的 SKU,決定了登入函式庫的功能和成本。在本例中,我們使用的是基本 SKU,它提供了基本功能,並且由 Azure 自動管理儲存。

Terraform 執行命令

建立完容器登入函式庫資源後,我們可以使用 Terraform 的 apply 命令來建立實際的資源。

terraform apply -auto-approve

這個命令會自動批准變更,不需要手動確認。這在自動化佈署管道中非常有用,因為不需要人工介入。

Terraform 輸出

執行完 apply 命令後,Terraform 會顯示變更的資源和輸出值。在本例中,輸出值包括了容器登入函式庫的詳細訊息。

Outputs:

registry_pw = <sensitive>

這些輸出值可以用於後續的指令碼或組態中,例如在佈署應用程式時使用容器登入函式庫的憑證。

使用 Terraform 輸出敏感值

Terraform 可以用於從基礎設施中提取生成的組態詳細訊息。以下是如何宣告輸出以顯示新容器登入的 URL、使用者名稱和密碼。

output "registry_hostname" {
  value = azurerm_container_registry.container_registry.login_server
}

output "registry_un" {
  value = azurerm_container_registry.container_registry.admin_username
}

output "registry_pw" {
  value     = azurerm_container_registry.container_registry.admin_password
  sensitive = true
}

在上述範例中,sensitive = true 用於標記密碼為敏感值。這意味著 Terraform 不會在終端顯示實際值,而是顯示 <sensitive>

取得敏感值

若要檢視實際的密碼值,您可以使用以下命令:

terraform output -raw registry_pw

這將顯示密碼的實際值。

敏感值的重要性

Terraform 會將敏感值從輸出中隱藏,以確保佈署過程的安全性。在自動化佈署管道中,所有輸出都會被記錄,因此敏感值不應該以明文形式儲存。

雖然可以使用 terraform output -raw 取得敏感值,但這些值仍然會儲存在本地 Terraform 狀態檔中。您可以使用 cat terraform.tfstate 命令檢視狀態檔的內容,包括密碼。

圖表翻譯:

  flowchart TD
    A[宣告輸出] --> B[設定值]
    B --> C[標記敏感值]
    C --> D[執行 Terraform]
    D --> E[顯示輸出]
    E --> F[取得敏感值]
    F --> G[檢視狀態檔]

內容解密:

在上述範例中,我們宣告了三個輸出:registry_hostnameregistry_unregistry_pw。其中,registry_pw 被標記為敏感值。當我們執行 Terraform 時,輸出將顯示 <sensitive> 而不是實際的密碼值。然而,我們可以使用 terraform output -raw 命令取得實際的密碼值。這些值儲存在本地 Terraform 狀態檔中,可以使用 cat terraform.tfstate 命令檢視。

使用 Terraform 管理基礎設施的最佳實踐

在上一節中,我們學習瞭如何使用 Terraform 建立和管理基礎設施。然而,在實際應用中,我們需要考慮到基礎設施的安全性和敏感性資料的保護。在本文中,我們將探討如何使用 Terraform 管理基礎設施的最佳實踐,包括如何處理敏感性資料和如何分享組態資料。

7.9 不要輸出敏感值

當我們使用 Terraform 建立基礎設施時,可能會需要輸出一些敏感性資料,例如密碼或 API 金鑰。然而,這些資料可能會被未經授權的使用者存取,從而導致安全性風險。因此,最佳實踐是不要輸出敏感性資料。

7.10 重構以分享組態資料

當我們建立多個 Terraform 組態檔案時,可能會需要重複使用一些組態資料,例如應用程式名稱或資料中心位置。為了避免重複工作和提高維護性,我們可以使用 Terraform 變數來分享組態資料。

7.10.1 繼續演化基礎設施

在這個例子中,我們將建立一個新的 Terraform 組態檔案,名為 example-3,並在其中定義一些變數。然後,我們將使用這些變數來建立基礎設施。

7.10.2 引入 Terraform 變數

example-3 中,我們定義了一些變數,例如 app_namelocationkubernetes_version。這些變數可以被用來建立基礎設施,並且可以被分享於多個 Terraform 組態檔案中。

variable app_name {
}

variable location {
  default = "eastus"
}

variable kubernetes_version {
}

7.10.3 使用變數

resource-group.tfcontainer-registry.tf 中,我們使用了這些變數來建立基礎設施。

resource "azurerm_resource_group" "example" {
  name     = var.app_name
  location = var.location
}

resource "azurerm_container_registry" "example" {
  name                     = var.app_name
  resource_group_name      = azurerm_resource_group.example.name
  location                 = azurerm_resource_group.example.location
  sku                      = "Basic"
  admin_enabled            = true
}

建立 Kubernetes 叢集

在 Azure 中建立一個 Kubernetes 叢集是佈署微服務的關鍵步驟。這裡,我們將使用 Terraform 來自動化這個過程。

使用 Terraform 變數

首先,我們需要定義一些變數來儲存叢集的組態訊息。這些變數包括叢集的名稱、位置和資源群組名稱等。透過使用變數,我們可以方便地在不同環境中切換組態。

variable "app_name" {
  type        = string
  description = "應用程式名稱"
}

variable "location" {
  type        = string
  description = "位置"
}

建立資源群組和容器登記冊

接下來,我們需要建立一個資源群組和一個容器登記冊。這些資源將用於儲存和管理我們的 Kubernetes 叢集。

resource "azurerm_resource_group" "flixtube" {
  name     = var.app_name
  location = var.location
}

resource "azurerm_container_registry" "container_registry" {
  name                     = var.app_name
  resource_group_name     = azurerm_resource_group.flixtube.name
  location                 = var.location
  admin_enabled            = true
  sku                      = "Basic"
}

建立 Kubernetes 叢集

現在,我們可以開始建立 Kubernetes 叢集了。這裡,我們需要定義叢集的名稱、位置、資源群組名稱等訊息。

resource "azurerm_kubernetes_cluster" "cluster" {
  name                = var.app_name
  location            = var.location
  resource_group_name = azurerm_resource_group.flixtube.name
  dns_prefix          = var.app_name

  default_node_pool {
    name       = "default"
    node_count = 1
    vm_size    = "Standard_DS2_v2"
  }

  identity {
    type = "SystemAssigned"
  }
}

圖表翻譯:Kubernetes 叢集架構

  graph LR
    A[資源群組] --> B[容器登記冊]
    B --> C[Kubernetes 叢集]
    C --> D[節點池]
    D --> E[虛擬機器]

圖表翻譯:

上述圖表展示了 Kubernetes 叢集的架構。資源群組是叢集的父資源,容器登記冊用於儲存和管理映象,Kubernetes 叢集是核心資源,節點池是叢集中的計算資源,虛擬機器是節點池中的計算單元。

使用 Terraform 進行基礎設施組態

在雲端計算中,基礎設施組態是一個非常重要的步驟。Terraform 是一個強大的工具,允許我們使用程式碼定義基礎設施組態。下面,我們將介紹如何使用 Terraform 進行基礎設施組態。

變數定義

首先,我們需要定義一些變數,以便在組態檔案中使用。這些變數包括應用名稱 (app_name)、位置 (location)、資源群組名稱 (resource_group_name) 等。

name = var.app_name
location = var.location
resource_group_name = azurerm_resource_group.flixtube.name

資源群組組態

接下來,我們需要組態資源群組。資源群組是 Azure 中的一個邏輯容器,用於管理相關的資源。

# Sets the name of the resource group from the app_name variable
# Sets the location from the location variable
resource "azurerm_resource_group" "flixtube" {
  name     = var.app_name
  location = var.location
}

容器登入組態

然後,我們需要組態容器登入。容器登入是用於儲存和管理 Docker 映像的倉函式庫。

# Sets the name of the container registry from the app_name variable
# Sets the location from the location variable
resource "azurerm_container_registry" "flixtube" {
  name                     = var.app_name
  location                 = var.location
  resource_group_name      = azurerm_resource_group.flixtube.name
}

Kubernetes 叢集組態

最後,我們需要組態 Kubernetes 叢集。Kubernetes 是一個容器協調系統,用於自動化佈署、擴充套件和管理容器化應用程式。

# Declares the resource for our Kubernetes cluster
resource "azurerm_kubernetes_cluster" "flixtube" {
  name                = var.app_name
  location            = var.location
  resource_group_name = azurerm_resource_group.flixtube.name
  dns_prefix          = var.app_name
  kubernetes_version = var.kubernetes_version

  default_node_pool {
    name = "default"
  }
}

內容解密:

在上面的程式碼中,我們定義了一些變數,包括應用名稱 (app_name)、位置 (location)、資源群組名稱 (resource_group_name) 等。然後,我們組態了資源群組、容器登入和 Kubernetes 叢集。每個資源都使用了變數來設定其名稱和位置。

圖表翻譯:

以下是資源之間的關係圖:

  graph LR
    A[應用名稱] -->|設定|> B[資源群組]
    B -->|設定|> C[容器登入]
    C -->|設定|> D[Kubernetes 叢集]
    D -->|設定|> E[預設節點池]

在這個圖表中,我們可以看到應用名稱設定了資源群組,資源群組設定了容器登入,容器登入設定了 Kubernetes 叢集,Kubernetes 叢集設定了預設節點池。這個圖表幫助我們瞭解資源之間的關係和依賴性。

建立 Kubernetes 叢集

在建立 Kubernetes 叢集之前,我們需要定義叢集的設定,包括節點數量、VM 大小等。以下是定義節點和 VM 大小的程式碼:

node_count = 1
vm_size = "Standard_B2s"

這裡,我們定義了一個只有單一節點的叢集,VM 大小為 Standard_B2s

將容器登入附加到叢集

在建立叢集之前,我們需要將容器登入附加到叢集,以便叢集可以從登入中提取映像。以下是建立角色指派的程式碼:

resource "azurerm_role_assignment" "role_assignment" {
  principal_id = azurerm_kubernetes_cluster.cluster.kubelet_identity[0].object_id
  role_definition_name = "AcrPull"
  skip_service_principal_aad_check = true
}

這裡,我們建立了一個角色指派,授予叢集從容器登入中提取映像的許可權。

建立叢集

現在,我們可以建立叢集了。執行以下命令:

terraform apply -auto-approve

這將建立我們定義的 Kubernetes 叢集。

附加說明

  • 我們使用 azurerm_kubernetes_cluster 資源建立 Kubernetes 叢集。
  • 我們使用 azurerm_role_assignment 資源建立角色指派,授予叢集從容器登入中提取映像的許可權。
  • 我們使用 terraform apply 命令建立叢集,並使用 -auto-approve 選項自動批准變更。

圖表翻譯

以下是建立叢集的流程圖:

  flowchart TD
    A[定義節點和 VM 大小] --> B[建立角色指派]
    B --> C[建立叢集]
    C --> D[授予叢集從容器登入中提取映像的許可權]

這裡,我們定義了建立叢集的流程,包括定義節點和 VM 大小、建立角色指派、建立叢集和授予叢集從容器登入中提取映像的許可權。

Kubernetes叢集佈署與微服務測試

現在,我們已經使用Terraform建立了一個Kubernetes叢集。下一步是佈署一個微服務到叢集中,以確保一切運作正常。為了測試我們的新叢集,我們將佈署來自chapter-7程式碼倉函式庫中example-4子目錄的微服務。這個例子與第6章中的example-2相同,我們現在將其佈署到使用Terraform建立的叢集中。

步驟1:取得Kubernetes叢集憑據

首先,我們需要取得Kubernetes叢集的憑據。使用以下命令:

az aks get-credentials --resource-group <resource-group> --name <cluster>

請將<resource-group><cluster>替換為您之前輸入的app_name變數的值。例如,如果您的app_name是`flixtube%,則命令如下:

az aks get-credentials --resource-group flixtube --name flixtube

步驟2:構建Docker映像

接下來,切換到chapter-7/example-4目錄,並構建Docker映像:

cd chapter-7/example-4
docker build -t video-streaming:1 --file Dockerfile-prod

步驟3:標記並推播映像

在推播映像之前,我們需要知道容器登錄檔的詳細訊息。請參考第7.9.6節以查詢這些詳細訊息。然後,使用容器登錄檔的URL標記映像:

docker tag video-streaming:1 <registry-url>/video-streaming:1

接下來,登入容器登錄檔:

docker login <registry-url>

登入後,將映像釋出到登錄檔:

docker push <registry-url>/video-streaming:1

這個過程可能需要一些時間,因此您可以在等待的同時準備您喜歡的熱飲。

步驟4:更新佈署組態

在進行測試佈署之前,您需要更新deploy.yaml檔案,以便它指向正確的容器登錄檔。請在檔案中找到正確的位置並輸入容器登錄檔的URL:

spec:
  containers:
  - name: video-streaming
    image: <registry-url>/video-streaming:1
    imagePullPolicy: IfNotPresent
    env:
    - name: PORT
      value: "4000"

請在deploy.yaml檔案中使用您的容器登錄檔名稱。

內容解密:

上述步驟涉及取得Kubernetes叢集憑據、構建Docker映像、標記並推播映像、登入容器登錄檔、釋出映像以及更新佈署組態。這些步驟是將微服務佈署到Kubernetes叢集的必要過程。

圖表翻譯:

下面是使用Mermaid語法繪製的流程圖,展示了上述步驟之間的關係:

  flowchart TD
    A[取得Kubernetes叢集憑據] --> B[構建Docker映像]
    B --> C[標記並推播映像]
    C --> D[登入容器登錄檔]
    D --> E[釋出映像]
    E --> F[更新佈署組態]

這個流程圖顯示了每個步驟之間的邏輯順序,幫助您更好地理解微服務佈署過程。

2297.14 Terraform 實踐檢視

在釋出映像檔並更新 deploy.yaml 以指向正確的登入倉函式庫後,我們可以將微服務佈署到 Kubernetes 叢集:

kubectl apply -f scripts/deploy.yaml

接下來,我們可以檢查佈署是否成功:

kubectl get pods
kubectl get deployments
kubectl get services

kubectl get services 的輸出中,我們可以取得 EXTERNAL-IP 值並使用它來測試由玄貓提供的網頁。請注意,必須檢視網頁的影片路由,否則將無法看到任何內容。測試完成後,我們可以刪除佈署並清理叢集:

kubectl delete -f scripts/deploy.yaml

我們快速地檢視了叢集的測試。如需更多關於使用 Docker 建立和釋出映像檔的細節,請參考第 3 章。如需更多關於佈署到 Kubernetes 的細節,請參考第 6 章。

7.13 銷毀基礎設施

除非您真的正在建構生產應用程式,否則沒有必要讓基礎設施保持執行。最終,它將耗盡 Azure 的免費積分並開始產生實際成本。因此,在您完成實驗 Terraform 和 Kubernetes 後,使用以下命令銷毀基礎設施:

terraform destroy

不要害怕銷毀基礎設施。由於我們的基礎設施是透過程式碼建立的,我們可以輕易地銷毀它並根據需要多次重新建立。當然,如果我們有依賴基礎設施的人員(客戶或團隊成員),我們不能在他們使用時就銷毀它!但是在第 12 章中,我們將討論如何在升級或替換基礎設施時最小化風險。

7.14 Terraform 實踐檢視

似乎我們正在快速地完成一個又一個的大章節!請記住,您可以隨時傳回任何章節來練習所學到的內容。為了複習,Terraform 是一個用於建立和設定根據雲端的基礎設施的通用工具。我們使用它來建立整個微服務應用程式的基礎設施。在繼續之前,讓我們複習一下在本章中新增到工具箱中的 Terraform 命令,如表 7.2 所示。

Terraform 在自動化基礎設施管理領域扮演著日益重要的角色。本文深入探討了Terraform狀態檔案的工作機制、優點,以及如何運用Terraform 建立、組態和銷毀Azure上的基礎設施,包含資源群組、容器登入函式庫和Kubernetes叢集等關鍵元件。分析Terraform程式碼的實務案例,可以發現,變數的運用、敏感資料的保護以及程式碼的模組化設計,對於提升IaC效率至關重要。此外,將容器登入函式庫整合到Kubernetes叢集中,並透過佈署微服務進行測試,驗證了Terraform的實用性和可靠性。然而,Terraform的學習曲線較陡峭,需要投入時間和精力才能掌握。展望未來,隨著雲原生技術的普及,預計Terraform的應用將更加廣泛,其生態系統也將更加成熟。玄貓認為,對於追求基礎設施自動化管理和提升DevOps效率的企業而言,Terraform是一項值得投資的技術,尤其在多雲環境下更能展現其優勢。技術團隊應著重於最佳實踐的學習和應用,例如避免輸出敏感值、重構程式碼以分享組態資料,才能最大化Terraform的價值,並降低潛在風險。