Skip to main content

Terraform 基本架構

使用 Terraform 的工作流程

  1. 依據預計的架構寫一份 HCL 格式的組態檔 (configuration)
  2. 執行 terraform init 讓 Terraform 下載需要的外掛套件
  3. 執行 terraform plan 產生一份執行計劃,描述即將進行的階段
  4. 執行 terraform apply 實際建置基礎架構,並把目前的狀態儲存到狀態檔
  5. 若修改配置檔內容,Terraform 會自己決定如何調整基礎架構,產生一份對應的執行計劃
  6. 若不需要再使用環境,執行 terraform destroy

terraformarch.avif

Terraform 資料夾規範建議

Terraform
├── main.tf # terraform 入口
├── version.tf # 定義 terraform & provider 版本
├── terraform.tfvars # 定義 input variable
└── modules # 自製 terraform modlues
└── resource # terraform modlues 建議風格
├── output.tf # terraform output variable
├── variables.tf # terraform input variable
└── versions.tf # terraform 版本定義
  • 副檔名介紹
    • terraform.tf — 基本文件
    • terraform.tfvars — 變數文件
    • terraform.tfstate— 當前狀態
    • terraform.tfstate.backup— backup 狀態
組態檔 main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "3.5.0"
}
}
}

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

resource "aws_instance" "example" {
ami = "ami-0461b11e2fad8c14a"
instance_type = "t2.micro"
}

前面提過 Terraform 是以組態檔來描述我們期望基礎設施應該符合的狀態,現在就以一個簡單的範例來看一下 Terraform 組態檔大概長什麼樣子(檔案名稱是 main.tf):

Terraform 組態檔是以 HCL 語法語法來撰寫,副檔名是 .tf,例如 main.tf。前述範例當中有三個區塊(由一對大括號 {...} 來辨別):

  • 第一個區塊的 required_providers 宣告了我們的專案所需要用到的提供者。此範例只使用一個提供者:awssource 屬性告訴 Terraform 去哪裡下載這個提供者的程式碼,version 屬性則指定版本號碼。
  • 第二個區塊宣告此專案要使用 AWS 雲端服務。
  • 第三個區塊則表示需要建立一個 VPC,而該 VPC 資源的類型是 aws_vpc,名稱是 example

由以上範例可以看得出來,HCL 語法相當簡單,直觀,基本上就是在描述資源的類型、名稱,然後設定其屬性。你不會在組態檔案中撰寫類似「增加 2 台 VM」、「刪除某個 AWS 使用者的權限」這種命令式語法。就如前面提過的,Terraform 的組態配置是採用宣告的方式——我們只需定義 what,不用去指示 how。

值得一提的是,範例中的第一個區塊,也就是宣告 required_providers 的部分,如果是 Terraform 官方註冊的提供者(例如 aws),即使沒有寫這個區塊也能運作,但一般還是建議明白宣告專案會用到哪些提供者。如果用到的提供者數量較多,亦可將這塊宣告抽離出去,單獨放在一個名為 providers.tf 的檔案裡。至於非官方的提供者,就一定要明白宣告,否則 Terraform 會不知道如何獲取提供者相關資訊。

Terraform 網站的提供者清單頁面中,有提供選項與圖示可以快速尋找與辨認哪些是官方的提供者、哪些是由合作夥伴或第三方社群提供。如下圖:

初次撰寫 Terraform 組態檔案時,可參考官方網站上提供的教學文件,並利用文件中提供的現成範例來學習組態檔的語法。以下動畫展示了如何在官網上面查找 AWS Provider 的用法與範例。

狀態檔 terraform.tfstate
resource "aws_instance" "example" {
ami = "ami-0461b11e2fad8c14a"
...
availability_zone = "ap-northeast-1a"
cpu_core_count = 1
cpu_threads_per_core = 1
disable_api_termination = false
ebs_optimized = false
get_password_data = false
hibernation = false
id = "i-0ab21c3f140f6d9b2"
instance_state = "running"
instance_type = "t2.micro"
...
private_dns = "ip-172-31-18-145.ap-northeast-1.compute.internal"
private_ip = "172.31.18.145"
public_dns = "ec2-3-112-206-97.ap-northeast-1.compute.amazonaws.com"
public_ip = "3.112.206.97"
secondary_private_ips = []
security_groups = [
"default",
]
source_dest_check = true
subnet_id = "subnet-161fbc60"
tenancy = "default"
volume_tags = {}
vpc_security_group_ids = [
"sg-b42035d0",
]

credit_specification {
cpu_credits = "standard"
}

metadata_options {
http_endpoint = "enabled"
http_put_response_hop_limit = 1
http_tokens = "optional"
}

root_block_device {
delete_on_termination = true
device_name = "/dev/sda1"
encrypted = false
iops = 100
volume_id = "vol-086e8635eb3533e15"
volume_size = 8
volume_type = "gp2"
}
}
輸入參數 variables.tf
# variables.tf
variable "project" {
type = string
description = "介紹 variable 所用,若未先帶入執行 terraform apply 時會請輸入此value"
}
輸出參數 output.tf
output "external_ip" {
value = google_compute_global_address.bucket.address
}
  • 設定 Resources apply 執行完畢後可輸出的值
模組 Modules
- modules
|- module
|- main.tf # 主入口
|- output.tf # apply 輸出
|- variables.tf # var 定義
|- version.tf # module 版本
  • 建議使用官方出產品質保證的,亦可自己組裝,基本上是把 resources 組成常用的 module
version.tf
#vartion.tf
terraform {
required_version = ">= 0.13.0"
required_providers {
google = {
source = "hashicorp/google"
version = "< 5.0, >= 3.83"
}
}
}
  • 定義 module 版本,最低支援版本為何