前言

今天要來介紹的是如何用 Terraform 建立 Google Kubernetes Engine,如果對使用 Terraform 建立、修改和刪除的指令不清楚可以參考我之前的文章 Terraform 基本操作,這篇文章主要是要介紹如何使用 Terraform 建立 GKE 叢集,並且建立 Nginx Load Balancer 來做為服務的入口,最後再透過 kubectl 來部署一個簡單的應用程式來測試負載平衡器是否正常運作。同時也會介紹要怎麼撰寫 Google Kubernetes Engine tf 檔案,應該參考什麼網站。

GKE 結構

GKE 的結構是: 叢集(cluster) > 節點池(node_pool) > 節點(node)
叢集

  • 叢集是 Kubernetes 的核心單位,包含所有管理與執行工作負載所需的資源。它是由一組節點組成的容器管理平台。

節點池

  • 節點池是一組具有相同配置的節點(虛擬機),是叢集資源的計算單位。
  • 節點池內的所有節點使用相同的規格,例如機型、磁碟類型、映像類型等。
  • 在 GKE 中,一個叢集可以有多個節點池。

節點

  • 節點是 Kubernetes 叢集中的實際計算單位,通常是 GCP 的虛擬機(VM),負責執行容器化的工作負載。

1. 前置設定

這個章節主要會說明:

  • 如何設定 gcloud cli
  • 如何設定子網域指定 Pod 與 Service 的 IP 範圍

1.1 gcloud cli 的安裝與設定

可以參考官方文件 gcloud cli 來安裝 gcloud cli,安裝完成後可以使用 gcloud init 來設定帳號,選擇專案等等。

1.1.1 OAuth Login

user/password oauth login 如果你是Mac可以遵循以下步驟:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#######################################################
# 0. python3 安裝 (建議使用方法)
#######################################################
# 在安裝的時候就會建議安裝 python3,我因為本身有使用 conda 否則執行下面的指令
brew install python@3.11

#######################################################
# 1. brew 安裝 (建議使用方法)
#######################################################
brew install --cask google-cloud-sdk

#######################################################
# 2. 或使用下載後安裝 (1或2挑選一種方式即可)
#######################################################
# https://cloud.google.com/sdk/docs/install-sdk
# 先到上面的網站,下載安裝對應的壓縮檔案
./google-cloud-sdk/install.sh

#######################################################
# 無論方法一或是方法二,安裝完都需要測試gcloud是否完成
#######################################################
gcloud version

# 應該出現類似下列版本
Google Cloud SDK 427.0.0
beta 2023.04.17
bq 2.0.91
core 2023.04.17
gcloud-crc32c 1.0.0
gke-gcloud-auth-plugin 0.5.2
gsutil 5.23
kubectl 1.24.12

#######################################################
# gcloud init 設定環境
#######################################################
# 根據官方文件的連結,一步一步設定
# https://cloud.google.com/sdk/docs/install-sdk#initializing_the
gcloud init

#######################################################
# gcloud auth 得到權限
#######################################################」
gcloud auth application-default login

1.1.2 Service account

如果你想使用 service account login 可以參考以下步驟:

  1. 建立service account 後下載金鑰
  2. 把金鑰放在terraform執行的本地目錄
  3. provider 設置如下
1
2
3
4
5
6
7
8
9
10
11
12
# 記得不要上傳你的service account 檔案
provider "google" {
credentials = file("tf101-sa.json")
project = "terraform101-384507"
region = "asia-east1"
}

resource "google_storage_bucket" "quick-start-gcs" {
name = "quick-start-gcs-bucket"
location = "asia-east1"
force_destroy = true
}

1.2 設定子網域(可選)

如果你希望 Pod 與 Service 有特定的 IP 範圍,可以設定子網域,這樣可以避免 Pod 與 Service 的 IP 與其他服務衝突。

步驟如下:

  1. 進入虛擬私有雲網路 VPC 網路

  2. 因為我們案例打算把叢集建立在 default 網路裡面的asia-northeast1,所以我們要進入 default 網路的 asia-northeast1 子網路裡面

  3. 可以新增新的子網域,這邊我們使用 10.14.0.0/20 給 Pod 使用,而 Service 使用 10.18.0.0/20

設定可參考以下:

1
2
asia-northeast1-pods-03263bcb = 10.14.0.0/20
asia-northeast1-services-03263bcb = 10.18.0.0/20

2. 建立叢集

接下來這個章節會一步步教你撰寫Terraform的設定檔,並且建立GKE叢集。主要分為以下幾個部分:

  • VariableData Source 設定
    • 這邊我們會設定專案名稱、區域、叢集名稱等等,這樣比較好管理與修改。
    • 這裡的 data source 是用來取得 token 來連接 GKE 叢集,以及 email 等資訊,這樣我們就可以使用 kubectl 來操作叢集。
  • Provider 設定
    • 這邊我們會設定 provider 來連接 GCP,以及 kubernetes 來連接 GKE 叢集。
  • 建立叢集
    • 這邊我們會使用 terraform-google-modules/kubernetes-engine/google 來建立叢集,這個 module 是由 Google 官方提供的,可以參考 Terraform Registry 來了解更多設定參數。

2.1 設定 Variable 與 Data Source

因為我們要在特定專案下建立 GKE 叢集,所以我們需要設定專案名稱、區域、叢集名稱等等,這樣比較好管理與修改。這裡的 data source 是用來取得 token 來連接 GKE 叢集,以及 email 等資訊,這樣我們就可以使用 kubectl 來操作叢集。

./variables.tf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
data "google_client_config" "default" {}

data "google_compute_default_service_account" "default" {}

variable "GCP_PROJECT" {
type = string
default = "terraform101-xxxxx" # <==== 請使用你的專案 id
}

variable "GCP_REGION" {
type = string
default = "asia-northeast1" # <==== 請使用你的區域
}

variable "cluster_name" {
type = string
default = "shannon-gke-cluster" # <==== 請使用你的叢集名稱
}

2.2 設定 Provider

如果你已經正常安裝gcloud cli並且登入,可以直接使用以下的設定:
./provider.tf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
##################################################################################
# CONFIGURATION
##################################################################################
terraform {
required_version = ">=1.0"
required_providers {
google = {
source = "hashicorp/google"
version = ">= 4.40.0"
}
}
}

##################################################################################
# PROVIDERS
##################################################################################
provider "google" {
project = var.GCP_PROJECT # <==== 我們剛剛設定的專案名稱
region = var.GCP_REGION # <==== 我們剛剛設定的區域
}

# 複製 terraform-google-modules/kubernetes-engine/google | Terraform Registry
provider "kubernetes" {
host = "https://${module.gke.endpoint}"
cluster_ca_certificate = base64decode(module.gke.ca_certificate)
token = data.google_client_config.default.access_token # <==== 需要使用 data source 來取得 token
}

2.3 建立叢集

可以參考官方的相關設置參數了解怎麼寫terraform的設定檔 GKE Cluster

這邊需要注意的是:
要先完成Step1設定子網域,否則ip_range_podsip_range_services會出錯喔

!!!的地方是需要根據你的node pool名稱來設定,這樣可以更好的管理與識別。其他可以複製貼上即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

module "gke" {
source = "terraform-google-modules/kubernetes-engine/google"
project_id = var.GCP_PROJECT # <==== 我們剛剛設定的專案名稱
region = var.GCP_REGION # <==== 我們剛剛設定的區域
name = var.cluster_name # <==== 我們剛剛設定的叢集名稱
zones = ["asia-northeast1-a"] # <==== 我們要建立在哪個區域的哪個zone,也因此 Step1 的 子網域要在這個區域下
deletion_protection = false # <==== 是否要開啟刪除保護 這樣才可以使用 terraform remove 刪除叢集

network = "default" # <==== 這邊使用預設
subnetwork = "default" # <==== 這邊使用預設 也就是 default 裡面的 asia-northeast1 (default) 子網域

ip_range_pods = "asia-northeast1-pods-03263bcb" # <==== 我們剛剛Step1 設定的子網域 這樣 Pod 的 IP 範圍就會在這個範圍
ip_range_services = "asia-northeast1-services-03263bcb" # <==== 我們剛剛Step1 設定的子網域 這樣 Service 的 IP 範圍就會在這個範圍

create_service_account = false # <==== 這邊不建立 service account 因為我們已經有了
service_account = data.google_compute_default_service_account.default.email # <==== 使用 data source 取得 service account email

# use spot pool
remove_default_node_pool = true # <==== 若你想使用 Spot 節點池或對資源進行更細緻的控制,移除預設節點池是必要的,避免產生不必要的資源消耗和額外成本。
http_load_balancing = true # <==== 是否要開啟 HTTP 負載平衡器
gce_pd_csi_driver = true # <==== 是否要開啟 GCE PD CSI 驅動程式 支援動態持久化卷 (PVC),可根據需求自動創建和管理存儲資源。
filestore_csi_driver = false # <==== 關閉 Filestore CSI 驅動,因為可能你的應用程序不需要使用 NFS(網路文件系統)存儲,或者為了降低成本
kubernetes_version = "1.30.5-gke.1443001" # <==== 使用的 Kubernetes 版本(這邊建議用GCP介面,創建叢集時所使用的版本)

# Node Pool 是一組具有相同配置(如機器類型、磁碟大小)的節點集合
# 每個 Node Pool 都可以有不同的資源配置,適用於不同的工作負載需求
node_pools = [
{
name = "shannon-worker-pool" # !!! <==== 節點池名稱 有助於在多個節點池中識別其用途。
machine_type = "e2-medium" # <==== 機器類型 e2 類型是 Google Cloud 的經濟型 VM,價格比高性能機器低,適合節省成本的輕量工作負載。

# 根據需求動態調整節點數量,避免閒置資源浪費。低需求時節點池可完全關閉,降低運行費用。
min_count = 0 # <==== 在無需工作負載時,節點池可縮至 0(無節點)。
max_count = 3 # <==== 在高需求時最多擴展至 3 個節點。

spot = true # <==== 使用較便宜的 Spot VM(搶占式虛擬機)。
disk_size_gb = 100 # <==== 節點的磁碟大小,預設為 100 GB。
disk_type = "pd-standard" # <==== 節點的磁碟類型,預設為標準磁碟。
image_type = "COS_CONTAINERD" # <==== 節點的映像類型,預設為 Container-Optimized OS。
enable_gcfs = false # <==== 是否啟用 GKE Filestore CSI 驅動程式。
enable_gvnic = false # <==== 是否啟用 GKE GvNIC 網路介面卡。提供高性能網路,禁用可能因應成本或需求考量。
auto_repair = true # <==== 是否啟用節點自動修復功能。
preemptible = false # <==== 搶占式虛擬機在任務結束前可能被終止,此處禁用該特性。
initial_node_count = 3 # <==== 節點池中的初始節點數量。
},
]

# 為節點池配置 OAuth 授權範圍(Scopes),用來限制節點的 API 訪問權限。
node_pools_oauth_scopes = {
all = [
"https://www.googleapis.com/auth/logging.write", # <==== 允許節點寫入日誌到 Google Cloud Logging
"https://www.googleapis.com/auth/monitoring", # <==== 允許節點向 Google Cloud Monitoring 發送監控數據
]
}

# 為節點池中的所有節點配置標籤 (Labels),用於標記節點的用途或屬性。
node_pools_labels = {
all = {} # <==== 對所有節點池不添加通用標籤。

# !!! 對 shannon-worker-pool 節點池添加自定義標籤(shannon-worker-pool: true)。
shannon-worker-pool = {
shannon-worker-pool = true
}
}

# 為節點池中的所有節點添加自定義元數據,用於存儲關於節點的附加信息。
node_pools_metadata = {
all = {}

# !!! 為該節點池添加鍵值對元數據。
shannon-worker-pool = {
node-pool-metadata-custom-value = "shannon-node-pool"
}
}

# 為節點添加 Taints,定義 Kubernetes 排程行為,用於限制哪些 Pod 可以調度到特定節點。
node_pools_taints = {
all = []

# !!! 為 shannon-worker-pool 節點池添加 Taints,限制 Pod 調度到這些節點。
shannon-worker-pool = [
{
key = "shannon-worker-pool"
value = true
effect = "PREFER_NO_SCHEDULE" # <==== 表示 Kubernetes 優先不將 Pod 調度到這些節點,但如果無其他合適節點,Pod 仍可調度。
},
]
}

# 為節點添加網絡標籤(Tags),用於網絡流量控制(如防火牆規則)
node_pools_tags = {
all = []

# !!! 為該節點池添加標籤 shannon-worker-pool
shannon-worker-pool = [
"shannon-worker-pool",
]
}
}

然後執行以下指令開始進行部署:

1
2
3
$ terraform init
$ terraform plan -out plan.out
$ terraform apply -auto-approve plan.out

部署完之後就可以在 GCP 的 Kubernetes Engine 看到剛建立的叢集了。

3. 負載平衡器與測試

接下來我們會:

  1. 使用透過網頁介面建立 Nginx Load Balancer
  2. 使用 kubectl 連線到 GKE 叢集
  3. 部署一個簡單的應用程式來測試負載平衡器是否正常運作

3.1 建立 Nginx Load Balancer

進入工作負載,點擊『部署』

設定Deployment的名稱、要部署的叢集、映像、埠口等等


檢查創立是否成功,要可以在『閘道、Service 與 Ingress』看到剛建立的服務

然後就可以透過點擊『端點』看到這個服務了

3.2 建立 Hello World App

在開始之前我們需要使用kubectl來連線到我們的叢集,這裡我們會使用gcloud cli進行操作,首先我們需要取得gcloud的登入資訊,這樣我們才能使用kubectl來連線到叢集。

  1. 進入叢集

  2. 取得登入資訊,你就複製上面的指令,然後執行在你的終端機

1
2
3
4
5
6
7
8
9
# 從gcp複製來的
gcloud container clusters get-credentials xxxxxx --region asia-northeast1 --project terraform101-xxxxx

# 這樣就可以連線到叢集了然後建立以下的應用程式
kubectl create deployment hello-server --image=gcr.io/google-samples/hello-app:1.0
kubectl expose deployment hello-server --type=LoadBalancer --port 8080
kubectl get service

http://[EXTERNAL-IP]:8080

就可以看到 app hello-server 的 附載平衡,裡面都會記錄著你的 app 的 log 資訊


結論

在這篇我們學到了什麼?

  1. 如何使用 Terraform 建立 GKE 叢集
  2. 如何使用 kubectl 連線到 GKE 叢集
  3. 如何建立 Nginx Load Balancer

參考連結