雲端架構部署救星!介紹 Terraform 是如何大幅改善雲端基礎建設的建立流程

  1. 過去在建立基礎架構時有許多痛點
  2. Terraform 是什麼?
  3. Terraform 如何運作
  4. Terraform 基本檔案結構
    1. providers.tf
    2. main.tf
      1. BigQuery Dataset
      2. BigQuery Tables
      3. Pub/Sub Topic
      4. Pub/Sub Subscriptions
    3. variables.tf
    4. terraform.tfvars
    5. outputs.tf
  5. 總結
    1. Terraform 注意事項與缺點
    2. Terraform 帶來的好處
  6. 後記
  7. 參考資料

過去在建立基礎架構時有許多痛點

當我們想要在雲端上建立各種服務時,通常都是透過 UI 的方式進行,但當架構越來越複雜,甚至還需要整組搬遷的時候,就會遇到很多困難,例如重新設定後可能剛好忘記 region 是設在哪、這個專案是用哪一個 Docker image,或這台機器的規格到底是幾個 CPU 多少記憶體。

整體來說,傳統建立基礎架構時會遇到以下的痛點

  • UI 操作過程繁雜
  • 大量人工操作,易出錯且難以維持一致性,增加除錯時間
  • 難以自動化,導致部署效率低
  • 無法版本控管、追蹤變更,增加操作風險
  • 無法重複利用,缺乏模組化設計,每次建立的成本都很高

所以我們過去在建立基礎架構時,常常需要花費大量時間與人力,效率太差,甚至可能會有許多都是重複性高的操作,而 Terraform 就是可以解決這些痛點的重要工具。

Terraform 是什麼?

Terraform 是一種「基礎架構即程式碼」工具 (Infrastructure as Code, Iac) ,讓我們使用人類易讀的設定檔中定義雲端和地端資源,並可對這些檔案進行版本控管、可重複使用和分享共用,讓所有基礎架構能在配置和管理上達成一致。

Terraform 如何運作

Terraform 主要是透過 Providers 來跟特定的雲端 API 做溝通,例如 GCP providers, AWS providers 等

在使用 Terraform 時主要有三個步驟:

  1. Write:
    1. 使用專屬的 HCL 配置語法撰寫 Terraform 的設定,例如 BigQuery Table 的名稱、VM 的規格等
    2. 執行 terraform init 後會產出一個 tfstate 檔案,做為執行紀錄,這樣 Terraform 才知道架構建立的現況
  2. Plan:
    • 這步驟就是執行 terraform plan 這個指令,可以預覽接下來可能發生的基礎架構變更,可能是 add, change 或 destroy
  3. Apply:
    • 這個就是最後執行 terraform apply 指令,會將變更實際套用到現在的架構上

Terraform 基本檔案結構

在撰寫 Terraform 設定的步驟中,主要需要以下檔案,其實只有 proiders.tf 和 main.tf 是必備的,其他檔案可有可無,但依照我個人目前使用的經驗,這五個檔案都要有會比較好

.
├── main.tf
├── outputs.tf
├── providers.tf
├── terraform.tfvars
└── variables.tf

各檔案的功能用途在官網上都有詳細解釋,我這邊只做簡單說明

  • main.tf:
    • 主要設定檔,用來管理各個資源 (resources)
  • outputs.tf:
    • 顯示建立後的架構資訊 (optional)
    • 例如一些 web server的 URL 是建立後才會有,就可以利用 outputs 來顯示
  • providers.tf:
    • 安裝並指定雲端 providers,以及指定 tfstate 的儲存位置
  • variables.tf:
    • 定義變數的型別、描述、特性和預設值 (optional)
  • terraform.tfvars:
    • 定義變數值(optional,可用來覆蓋 variables.tf 的預設值)

providers.tf

這個檔案就是用來安裝並指定雲端 providers,以及 tfstate 檔的儲存位置 (backend),也可以在這邊定義雲端的 project, region 相關基礎設定。

tfstate 檔是非常重要的檔案:

  • 作為 Terraform 和雲端之間的溝通橋樑,如果刪除它的話,Terraform 就會不知道雲端現在建立了哪些東西、還缺哪些設定要變更,我覺得有點類似 git 中的 .git 檔案
  • tfstate 檔案預設是存在你的本機上,但建議還是存在雲端,以利同事間的協作
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "6.25.0"
}
}
backend "gcs" {
bucket = "tfstate-bucket"
prefix = "demo-terraform"
}
}
provider "google" {
project = var.project_id
region = var.location
}
view raw providers.tf hosted with ❤ by GitHub

有了 providers.tf 後,我們就可以啟動這個專案的 terraform,在 terminal 中執行 terraform init 後就可以看到 terraform 設定了 gcs 為 backend(代表 tfstate 檔案存在 Google Cloud Storage 的指定 bucket 中)、尋找並安裝了 google provider,也建立了 .terraform 資料夾以及 .terraform.lock.hcl 檔。

main.tf

用來設定各個基礎架構的資源,基本上以 resource 為開頭,搭配服務名稱與自訂名稱。

如下方程式碼,分別設定了:

  • BigQuery 資料集
  • BigQuery 資料表
  • Pub/Sub Topic
  • Pub/Sub Subscriptions

BigQuery Dataset

##### BQ Dataset #####
resource "google_bigquery_dataset" "dataset" {
dataset_id = var.dataset_id
project = var.project_id
location = var.location
labels = var.service_labels
# lifecycle {
# prevent_destroy = true
# }
}

BigQuery Tables

##### BQ Tables #####
resource "google_bigquery_table" "tables" {
for_each = toset(var.tables)
dataset_id = google_bigquery_dataset.dataset.dataset_id
table_id = "${each.key}_${var.env}"
project = var.project_id
schema = file("schema/${each.key}.json")
labels = var.service_labels
# lifecycle {
# prevent_destroy = true
# }
}

Pub/Sub Topic

##### Pub/Sub Topic #####
resource "google_pubsub_topic" "topic" {
name = var.topic_id
project = var.project_id
labels = var.service_labels
}

Pub/Sub Subscriptions

##### Pub/Sub Subscriptions #####
resource "google_pubsub_subscription" "subscriptions" {
for_each = toset(var.tables)
name = "${each.key}-sub-${var.env}"
topic = var.topic_id
project = var.project_id
labels = var.service_labels
ack_deadline_seconds = var.ack_deadline_seconds
bigquery_config {
table = "${var.project_id}:${var.dataset_id}.${each.key}_${var.env}"
use_table_schema = var.use_table_schema
drop_unknown_fields = var.drop_unknown_fields
}
expiration_policy {
ttl = "" # never expire
}
}

variables.tf

這檔案用來定義變數的型別、描述、特性和預設值,若沒有預設值的話,還有兩種方法可以帶入變數的值:

  1. 執行 terraform apply 時手動輸入(適用於 secrets, token 等機密資料)
  2. 使用 tfvars 檔案
# General Variables
variable "project_id" {
description = "GCP Project ID"
type = string
}
variable "env" {
description = "Environment name (e.g., dev, prod)"
type = string
}
variable "service_labels" {
description = "Labels of service"
type = map(string)
}
##### BQ #####
variable "dataset_id" {
description = "BigQuery dataset ID"
type = string
}
variable "tables" {
description = "BigQuery table ID"
type = list(string)
}
variable "location" {
description = "BigQuery dataset location"
type = string
}
##### Pub/Sub Topic #####
variable "topic_id" {
description = "Pub/Sub topic ID"
type = string
}
##### Pub/Sub Subscriptions #####
variable "use_table_schema" {
type = bool
}
variable "drop_unknown_fields" {
type = bool
}
variable "ack_deadline_seconds" {
type = number
}
view raw variables.tf hosted with ❤ by GitHub

我個人目前習慣使用 tfvars 檔案來帶入,簡單易懂又好維護

terraform.tfvars

用來自動帶入變數的值(或是覆蓋預設值)

# General Variables
env = "demo"
project_id = "my-project"
location = "asia-east1"
service_labels = {
author = "author_name"
project = "demo"
}
# BQ Variables
dataset_id = "demo_terraform"
tables = ["table1", "table2"]
# Pub/Sub Variables of Topics
topic_id = "demo-terraform"
# Pub/Sub Variables of Subscriptions
use_table_schema = true
drop_unknown_fields = true
ack_deadline_seconds = 120

使用 terraform.tfvars 的好處是,以後如果需要搬遷或是環境的變更,只要複製檔案並更改這個 tfvars 就可以。

如下圖,今天想要新增一個 prod 環境,是跟 demo 環境相同的基礎架構,只要將所有檔案複製到一個新的 prod 資料夾後,更改 terraform.tfvars 的 env, project_id 之類的變數即可,其他檔案都可以不用動,大幅提升效率也降低出錯率。

outputs.tf

在這個檔案中可以事先定義建立完成時想要顯示的資訊,因為有些服務的重要資訊是建立後才會生成,例如 web server 的 URL,我們想要在建立後就能直接複製網址並前往,這時候 outputs.tf 就很實用。

另外一個好處是,有設定 outputs 的話就可以在 terraform plan 後看到部分資訊,像是 table names 等,也可以當作快速驗證架構變更時的依據。

output "bq_dataset_id" {
description = "Dataset ID of created BigQuery Dataset"
value = google_bigquery_dataset.dataset.dataset_id
}
output "bq_tables_id" {
description = "Table ID of created tables"
value = [for table in google_bigquery_table.tables : table.table_id]
}
output "topic_name" {
description = "Topic name of created Pub/Sub topic"
value = google_pubsub_topic.topic.name
}
output "subscription_name" {
description = "Subscription name of created Pub/Sub subscription"
value = [for sub in google_pubsub_subscription.subscriptions : sub.name]
}
view raw outputs.tf hosted with ❤ by GitHub

總結

以上就是簡單的 Terraform 概念介紹,我實務上使用 Terraform 來建立 GCP 基礎架構的心得總結如下:

Terraform 注意事項與缺點

  • 需要使用專屬的 HCL 配置語法,所以學習門檻較高
  • terraform destroy 指令會把所有已建立的架構刪除,執行前要仔細檢查 plan!
  • BigQuery Table 如果需要變更 Schema 或 Data Type,Terraform 會把 Table 刪除後重建,導致資料遺失,記得要備份!

Terraform 帶來的好處

  • 簡化設定雲端的過程
  • 降低錯誤率
  • 可自動化
  • 可重複使用
  • 可版本控管
  • 可分享共用協作
  • 可快速搬遷架構及開發環境

後記

現在許多公司在招募 Data Engineer 的 JD 上會將 Terraform 列在加分技能項目,我個人認為在快速發展的 AI 時代下,現代數據架構很重要的一個概念就是架構必須要夠彈性、可以隨時做抽換,並且要能快速在雲端上部署數據產品,所以我覺得 Terraform 毫無疑問將會成為 Data Engineer 資料工程師的重要必備技能之一。

參考資料

發表留言