跳至主要內容

Terraform 基礎設施即程式碼入門實戰

Terraform 基礎設施即程式碼入門實戰

基礎設施即程式碼(Infrastructure as Code,IaC)已經是現代 DevOps 的標配。過去我們用手動點選雲端介面來建立資源,這不僅容易出錯,也難以重現。Terraform 由 HashiCorp 開發,是目前最流行的 IaC 工具之一,支援 AWS、GCP、Azure 等主流雲端平台,甚至 Cloudflare、GitHub 等服務也都有對應的 Provider。

為什麼選擇 Terraform?

  • 多雲支援:同一套工具管理不同雲端服務
  • 宣告式語法:描述「要什麼」而不是「怎麼做」
  • 狀態管理:追蹤實際資源與程式碼的差異
  • 可重現性:相同的程式碼產出相同的環境
  • 社群豐富:大量公開 Module 可直接使用

安裝 Terraform

# macOS 使用 Homebrew
brew tap hashicorp/tap
brew install hashicorp/tap/terraform

# 確認安裝
terraform version

基本概念

Provider

Provider 是 Terraform 與各平台 API 溝通的橋樑。使用前需要先設定:

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

provider "aws" {
  region = "ap-northeast-1"
}

Resource

Resource 是 Terraform 管理的基本單位,代表雲端上的一個實際資源:

# 建立一個 S3 Bucket
resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-unique-bucket-name-2026"

  tags = {
    Environment = "production"
    Project     = "my-app"
  }
}

# 設定 Bucket 的存取控制
resource "aws_s3_bucket_acl" "my_bucket_acl" {
  bucket = aws_s3_bucket.my_bucket.id
  acl    = "private"
}

Variable

使用變數讓設定更靈活:

# variables.tf
variable "environment" {
  description = "部署環境(dev/staging/prod)"
  type        = string
  default     = "dev"
}

variable "instance_type" {
  description = "EC2 Instance 類型"
  type        = string
  default     = "t3.micro"
}

variable "allowed_cidr_blocks" {
  description = "允許連入的 CIDR 清單"
  type        = list(string)
  default     = ["10.0.0.0/8"]
}

在資源中引用變數:

resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = var.instance_type

  tags = {
    Name        = "web-server-${var.environment}"
    Environment = var.environment
  }
}

Output

Output 讓你可以取得資源建立後的資訊:

# outputs.tf
output "instance_public_ip" {
  description = "Web Server 的公開 IP"
  value       = aws_instance.web.public_ip
}

output "bucket_arn" {
  description = "S3 Bucket 的 ARN"
  value       = aws_s3_bucket.my_bucket.arn
  sensitive   = false
}

實際工作流程

初始化

terraform init

這個指令會下載需要的 Provider 插件,建立 .terraform 目錄。

規劃

terraform plan

Terraform 會比較現有狀態與程式碼的差異,顯示將要執行的操作(新增、修改、刪除)。這個步驟非常重要,讓你在實際執行前確認變更內容。

套用

terraform apply

執行實際的資源變更。Terraform 會再次顯示計畫並要求確認。使用 -auto-approve 可以跳過確認(適合 CI/CD 環境)。

銷毀

terraform destroy

刪除所有由這份設定管理的資源。

管理 Terraform State

State 檔案記錄了 Terraform 所管理的資源狀態。預設會存在本地的 terraform.tfstate,但在團隊合作時應該使用遠端 Backend:

terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "prod/terraform.tfstate"
    region         = "ap-northeast-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}

使用 DynamoDB 作為鎖定機制,防止多人同時執行 terraform apply 造成衝突。

使用 Module

Module 讓你可以將重複使用的設定抽象化:

# 使用公開的 VPC Module
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.0.0"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["ap-northeast-1a", "ap-northeast-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]

  enable_nat_gateway = true
  single_nat_gateway = true

  tags = {
    Project     = "my-app"
    Environment = var.environment
  }
}

實用的 Terraform 指令

# 格式化程式碼
terraform fmt

# 驗證語法
terraform validate

# 顯示目前狀態
terraform show

# 列出所有資源
terraform state list

# 匯入既有資源
terraform import aws_s3_bucket.existing my-existing-bucket

# 針對特定資源執行
terraform apply -target=aws_instance.web

最佳實踐

目錄結構

infrastructure/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── terraform.tfvars
│   └── prod/
│       ├── main.tf
│       ├── variables.tf
│       └── terraform.tfvars
└── modules/
    ├── vpc/
    ├── ec2/
    └── rds/

版本鎖定

terraform {
  required_version = ">= 1.6.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "= 5.31.0"  # 鎖定精確版本避免意外升級
    }
  }
}

不要提交 State 檔案

.gitignore 中加入:

*.tfstate
*.tfstate.backup
.terraform/
*.tfvars  # 如果包含敏感資訊

總結

Terraform 提供了一個宣告式、可重現的方式來管理雲端基礎設施。從小型個人專案到大型企業環境,它都能有效地管理資源。關鍵是要建立良好的工作流程:使用遠端 State 儲存、充分利用 terraform plan 確認變更、以及適當地模組化你的設定。一旦熟悉了這套工具,你就再也不想回到手動點選雲端介面的日子了。

分享這篇文章