身為一位在台灣鑽研雲端架構多年的技術工作者,我發現精通 Terraform 的進階技巧對於有效管理基礎設施至關重要。以下我將分享我多年累積的經驗,包含網路組態自動化、與本地檔案系統互動、以及範本渲染技術的應用,並示範如何驗證輸入變數,確保組態的正確性。

子網自動化組態:告別手動計算

在規劃雲端架構時,子網的組態往往是複雜與容易出錯的環節。我發現使用 cidrsubnet 函式可以有效簡化這個過程,自動產生所需的子網,避免手動計算的風險。

locals {
  base_cidr = "10.0.0.0/16"
  subnet_count = 4
  subnets = [for i in range(local.subnet_count): cidrsubnet(local.base_cidr, 8, i)]
}

這段程式碼定義了一個 /16 的基礎 CIDR 區塊,並使用 cidrsubnet 函式自動產生四個 /24 的子網。8 代表新增 8 個位元來劃分子網,i 則為子網索引。透過調整 subnet_count 變數,可以輕鬆控制子網數量,大幅提升網路組態的彈性。

  graph LR
    B[B]
    A[定義基礎 CIDR] --> B{迴圈產生子網};
    B --> C[輸出子網列表];

上圖展示了使用 cidrsubnet 函式產生子網的流程。

與本地檔案系統互動:外部資料的整合

Terraform 提供了 filefileexists 函式,方便與本地檔案系統互動。這對於整合外部設定檔或資料相當實用。

variable "config_file_path" {
  type = string
  default = "config.txt"
}

locals {
  config = fileexists(var.config_file_path) ? file(var.config_file_path) : "預設組態"
}

output "config_content" {
  value = local.config
}

這段程式碼首先檢查 config.txt 是否存在。若存在,則讀取檔案內容;若不存在,則使用預設值「預設組態」。這個技巧可以讓 Terraform 組態更具彈性,例如根據不同環境載入不同的設定檔。

範本渲染技術:動態生成組態

範本渲染技術是提升 IaC 效率的利器,可以根據變數動態生成組態檔或指令碼。

variable "user_name" {
  type = string
  default = "使用者名稱"
}

data "template_file" "user_script" {
  template = <<-EOF
#!/bin/bash
echo "歡迎,${var.user_name}"
EOF

  vars = {
    user_name = var.user_name
  }
}

output "rendered_script" {
  value = data.template_file.user_script.rendered
}

這段程式碼使用 template_file 資料來源定義了一個 bash 指令碼範本,並將 user_name 變數的值嵌入其中。執行 terraform apply 後,rendered_script 輸出將包含渲染後的指令碼內容。

  graph LR
    C[C]
    A[定義變數] --> B[定義範本];
    B --> C{渲染範本};
    C --> D[輸出結果];

上圖展示了使用範本渲染技術生成組態的流程。

驗證輸入變數:確保組態正確性

我認為變數驗證是 Terraform 組態中不可或缺的一環。它可以確保輸入值符合預期格式,避免佈署錯誤。

variable "environment" {
  type = string
  validation {
    condition = contains(["開發", "測試", "正式"], var.environment)
    error_message = "環境變數必須是『開發』、『測試』或『正式』"
  }
}

這段程式碼限制 environment 變數的值必須是「開發」、「測試」或「正式」其中之一,確保環境設定的正確性。

透過以上技巧,我們可以更有效地利用 Terraform 管理基礎設施,提升自動化程度和程式碼品質。善用這些技巧,能讓你的 IaC 實踐更上一層樓。

在雲端時代,基礎設施即程式碼(IaC)已成為不可或缺的技術。Terraform 作為 IaC 的佼佼者,其強大的功能和靈活性深受開發者喜愛。然而,要真正駕馭 Terraform 並建構穩健、可維護的基礎設施,需要掌握一些進階技巧。本文將探討 Terraform 的模組化設計、錯誤訊息最佳化和跨狀態資料存取,並結合 EKS 叢集建立的實際案例,帶您領略 Terraform 的精妙之處。

Terraform 模組化設計:擁抱宣告式資源管理

我認為,Terraform 的核心優勢在於其宣告式資源管理。我們應該盡可能設計順序無關的組態,充分發揮 Terraform 的平行執行能力,而非受限於資源的處理順序。這不僅能提升效率,更能簡化程式碼邏輯,提高可讀性。

友善的 Terraform 錯誤訊息:引導使用者快速解決問題

當使用者提供無效輸入時,清晰、具體的錯誤訊息至關重要。我習慣利用 Terraform 的變數區塊和自定義驗證規則來達成此目標。

variable "instance_type" {
  type = string
  description = "EC2 執行個體型別"
  validation {
    condition     = can(regex("^t[23]\\..*", var.instance_type))
    error_message = "執行個體型別無效。必須是 t2 或 t3 執行個體型別 (例如:t2.micro、t3.small)。"
  }
}

variable "environment" {
  type = string
  description = "佈署環境"
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "環境無效。必須是下列其中之一:dev、staging、prod。"
  }
}

上述程式碼使用 regexcontains 函式驗證輸入變數。regex 確保 instance_type 符合 t2 或 t3 執行個體的命名規則,contains 則限制 environment 的值。這些客製化錯誤訊息能有效引導使用者提供正確輸入。

設計友善錯誤訊息的關鍵原則:

  • 明確指出錯誤原因和無效輸入。
  • 提供修正步驟或有效輸入範例。
  • 解釋驗證規則背後的邏輯。
  • 保持錯誤訊息風格一致性。
  • 使用簡潔明瞭的語言,避免專業術語。

此外,錯誤訊息應以正面、簡潔的方式呈現,並使用正確的技術術語。國際化和訊息測試也應納入考量。

Terraform 跨狀態資料存取:實作資訊分享

在複雜架構中,參照其他 Terraform 狀態的資源或輸出變數是常見的需求。以下圖表説明跨狀態資料存取方式:

  graph LR
    subgraph State A
        A[Resource 1] --> OutputA(Output Variable)
    end
    subgraph State B
        DataB[Data Source] --> B[Resource 2]
    end
    OutputA --> DataB

State A 的輸出變數被 State B 的資料源參照,實作了不同 Terraform 狀態之間的資料分享。

以下程式碼示範如何使用 AWS 資料源和 terraform_remote_state 跨狀態存取資料:

data "aws_vpc" "existing" {
  tags = {
    Environment = "production"
  }
}

output "vpc_id" {
  value = data.aws_vpc.existing.id
}

data "terraform_remote_state" "network" {
  backend = "s3"
  config = {
    bucket = "my-terraform-state"
    key    = "network/terraform.tfstate"
    region = "us-west-2"
  }
}

resource "aws_subnet" "example" {
  vpc_id     = data.terraform_remote_state.network.outputs.vpc_id
  cidr_block = "10.0.1.0/24"
}

程式碼優先嘗試使用 aws_vpc 資料源取得 VPC 資訊。若無法取得,則使用 terraform_remote_state 從其他狀態讀取 vpc_id

跨狀態存取資料的注意事項:

  • 優先使用雲端原生資料源,避免暴露敏感資訊。
  • 謹慎使用 terraform_remote_state
  • 確保後端組態正確與安全。
  • 注意透過狀態輸出暴露的資訊。
  • 確保後端支援狀態鎖定。
  • 注意版本相容性。
  • 使用 try 函式處理遠端狀態輸出可能不存在的情況。

實戰演練:使用公開模組建立 EKS 叢集

在 AWS 上建立 EKS 叢集,使用 Terraform Registry 的公開 AWS EKS 模組能有效簡化流程。以下程式碼片段示範如何使用該模組,並整合先前建立的 VPC 和 KMS 金鑰:

# ... (variables.tf and kms.tf configurations as shown previously)

data "aws_eks_cluster" "cluster" {
  name = module.eks.cluster_id
}

data "aws_eks_cluster_auth" "cluster" {
  name = module.eks.cluster_id
}

provider "kubernetes" {
  host                   = data.aws_eks_cluster.cluster.endpoint
  cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
  token                  = data.aws_eks_cluster_auth.cluster.token
}

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "20.24.0" # 建議使用最新版本

  cluster_name                = var.project_name
  cluster_version             = var.cluster_version
  subnets                     = module.vpc.private_subnets
  vpc_id                      = module.vpc.vpc_id
  cluster_enabled_log_types   = var.cluster_enabled_log_types
  write_kubeconfig            = var.cluster_write_kubeconfig

  cluster_encryption_config = [
    {
      provider_key_arn = aws_kms_key.eks.arn
      resources        = ["secrets"]
    },
  ]

  worker_groups = [
    {
      asg_desired_capacity = var.cluster_asg_desired_capacity
      asg_max_size         = var.cluster_asg_max_size
      instance_type        = var.cluster_instance_type
    },
  ]
}

此程式碼片段示範如何使用 EKS 模組,並設定相關引數,例如叢集名稱、版本、網路設定、日誌型別、加密設定以及工作節點組態。同時,也示範瞭如何使用 Kubernetes 提供者與 EKS 叢集互動。

透過上述技巧,我們能有效提升 Terraform 的運用效率和程式碼可維護性,建構更穩健、更靈活的基礎設施。


建構穩固與可擴充套件的雲端基礎架構,仰賴於完善的 Infrastructure as Code (IaC) 實務。我發現 Terraform 在這方面表現出色,它提供簡潔的語法和豐富的生態系統,能有效管理雲端資源。本文將探討 Terraform 的一些關鍵導向,從 EKS 叢集的建立到程式碼品質與安全驗證的最佳實務,並分享我在實務中的一些心得與技巧。

## 建立 EKS 叢集的 Terraform 設定

以下程式碼片段示範如何使用 Terraform 建立 EKS 叢集:

```terraform
# 設定所需的 Providers
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.0"
    }
  }
}

# 設定 AWS Provider
provider "aws" {
  region = "us-west-2" # 根據您的需求調整區域
}

# 設定 Kubernetes Provider
provider "kubernetes" {
  host                   = module.eks.cluster_endpoint
  cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
  token                  = data.aws_eks_cluster_auth.cluster.token
  exec {
    api_version = "client.authentication.k8s.io/v1beta1"
    command     = "aws"
    args        = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
  }
}

# 使用 EKS 模組
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 19.0"

  cluster_name    = "my-eks-cluster"
  cluster_version = "1.26"

  vpc_id = "vpc-xxxxxxxxxxxxxxxxx" # 替換為您的 VPC ID
  subnet_ids = [
    "subnet-xxxxxxxxxxxxxxxxx", # 替換為您的子網路 ID
    "subnet-yyyyyyyyyyyyyyyyy", # 替換為您的子網路 ID
  ]

  worker_groups = [
    {
      name          = "worker-group-1"
      instance_type = "t3.medium"
      desired_capacity = 2
      max_size         = 4
      min_size         = 2
    }
  ]

  # 使用 KMS 金鑰加密 Secrets
  cluster_encryption_config = {
    provider_key_arn = "arn:aws:kms:us-west-2:xxxxxxxxxxxx:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # 替換為您的 KMS 金鑰 ARN
  }
}


# 取得 EKS 叢集驗證資訊
data "aws_eks_cluster_auth" "cluster" {
  name = module.eks.cluster_name
}

此設定檔定義了建立 EKS 叢集所需的資源,包括 VPC、子網路、工作節點組態和 KMS 金鑰。它還設定了 Kubernetes 提供者,以便 Terraform 可以與叢集互動。worker_groups 區塊定義了工作節點的自動擴充套件組態。cluster_encryption_config 使用 KMS 金鑰來加密 Kubernetes secrets,提升安全性。我建議將 VPC 和子網路 ID 等引數外部化,以便更容易管理和調整。

使用 GitHub Actions 強化 Terraform 程式碼品質

程式碼品質對於 IaC 至關重要。我偏好使用 GitHub Actions 來自動化程式碼檢查流程,確保程式碼風格一致性並及早發現潛在問題。

以下是一個結合 Super-Linter 和 Terraform 特定檢查的工作流程範例:

name: Terraform CI

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  super-lint:
    name: Super-Linter
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: github/super-linter@v4
        env:
          VALIDATE_ALL_CODEBASE: false
          DEFAULT_BRANCH: main
          VALIDATE_TERRAFORM: true
          VALIDATE_YAML: true
          VALIDATE_JSON: true
          VALIDATE_MD: true

  terraform-checks:
    name: Terraform Checks
    runs-on: ubuntu-latest
    needs: super-lint # 確保 Super-Linter 先執行
    steps:
      - uses: actions/checkout@v3
      - uses: hashicorp/setup-terraform@v2
        with:
          terraform_version: 1.3.0 # 或您需要的版本
      - run: terraform fmt -check
      - run: terraform init
      - run: terraform validate

這個工作流程包含兩個作業:super-lint 使用 Super-Linter 檢查程式碼風格和語法,而 terraform-checks 執行 Terraform 特定的檢查,例如格式化、初始化和驗證。needs: super-lint 確保 terraform-checks 作業在 super-lint 完成後才執行,形成一個更完善的 CI 流程。

Terraform Providers 的安全驗證

安全驗證是 IaC 的根本。我強烈建議避免在程式碼中直接嵌入憑證。以下是一個使用 AWS IAM 角色進行驗證的範例,這是我在生產環境中的首選方法:

provider "aws" {
  region = "us-west-2" # 根據您的需求調整區域

  #  使用預設 AWS 憑證鏈,包含 IAM 角色
  #  避免直接在程式碼中儲存憑證
}

這個設定利用 AWS 憑證鏈,讓 Terraform 自動從執行環境中取得憑證。當在 AWS 環境中執行,例如 EC2 執行個體或 Lambda 函式時,Terraform 會自動使用與執行個體關聯的 IAM 角色。這消除了在程式碼或設定檔中管理憑證的需要,大幅提升安全性。

使用私有 Terraform 模組提升程式碼重用性

私有模組能有效提升程式碼重用性和 maintainability。以下是如何使用儲存在 Terraform Cloud 的私有模組:

module "vpc" {
  source  = "app.terraform.io/my-org/vpc/aws"
  version = "1.0.0"

  vpc_cidr = "10.0.0.0/16"
  azs       = ["us-west-2a", "us-west-2b"] # 根據您的需求調整可用區域
}

這段程式碼示範如何參照 Terraform Cloud 上的私有模組。source 引數指定模組的來源,version 引數鎖定模組版本,確保一致性。我建議使用版本控制來管理模組,並利用 Terraform Cloud 或其他私有模組登入檔來集中管理和分享模組。

EKS 叢集架構

  graph LR
    VPC[VPC]
subgraph VPC
    subnet1[Subnet 1] --> routeTable[Route Table]
    subnet2[Subnet 2] --> routeTable
    routeTable --> internetGateway[Internet Gateway]
end
    EKS[EKS Cluster] --> workerNodes[Worker Nodes]
    workerNodes --> VPC

圖表説明:此圖表簡要説明瞭 EKS 叢集與 VPC 的關係,其中工作節點位於 VPC 的子網路中,並透過路由表和網際網路閘道器連線到網際網路。

  sequenceDiagram
    participant Client
    participant EKS API Server
    participant Worker Node

    Client->>EKS API Server:  傳送請求
    EKS API Server->>Worker Node:  排程 Pod
    Worker Node->>Client:  傳回回應

圖表説明:此序列圖展示了客戶端、EKS API 伺服器和工作節點之間的互動流程,説明瞭 EKS 如何處理客戶端請求。

透過結合上述實務,您可以建構更安全、可靠與易於維護的雲端基礎架構。記住,安全性永遠是首要考量,程式碼品質和自動化流程能有效提升效率和降低錯誤率。持續學習和探索新的工具和技術,才能在不斷變化的雲端世界中保持競爭力。