手把手教你理解並建立 GCP 平衡負載

前言

為什麼要使用 Load Balancer?

  1. 可以分攤流量, 利用多台機器跑多個服務
  2. 當一台機器掛了,你還有另外一台
  3. 當負載到達一定程度,可以啟動 auto scaling (本篇不會使用到)
  4. 配合適當的 CI / CD, 以及健康檢查,可達到 rolling upgrade 的效果

本篇重點

  • 本篇分享最簡單易設的 unmanaged Load Balancer
  • 為避免混淆,本篇對於有意義的元件術語,將維持原文,不會特別翻譯
  • 詳解每個元件行為

簡單的概念圖如下 (圖片來源: Google ):

  1. IPv4 以及 IPv6 的使用者,對我們的服務發請求
  2. 我們設定的 IPv4 以及 IPv6 Forwading rules,會將使用者導向我們設定好的 HTTP(S) proxy
  3. 到了 HTTP(S) proxy 的 request, 會根據我們設定好的 url-map 規則,導向相對應的backend-service, 例如說, 透過 domain name 為 ‘test1’ 的 request, 導向backend-service 1, 而 ‘test2’ 的 request 導向 backend-service 2
  4. backend-serviceinstance group 組成,舉例來說,我們可以指定, backend-service A 導向 instance group A 的 port 8000 , 而 backend-service B 導向 instance group B 的 port 6000
  5. instance group, 顧名思義,由 instance 所組成,當我們在 instance group 中設定好特定的 port, 並且設定好 backend-service, 那麼 request 將會經由 backend-service, 再到 instance group 指定的 port, 最後到依照 instance 本身的負載狀況, 將 request 導向適合服務的 instance
  6. 每個 backend-service 都可以設定一個 health-check, health-check 會根據指定的頻率向指定的 port 探測並取得回應,如果回應的速度低於我們設立的門檻,那麼該 instance 就會被判定為不健康。 request 不會導向已被判定為不健康的 instance
  7. 如果有 SSL 需求,可建立 SSL certificate, 並且掛在 HTTPS proxy
  8. 以下我們就開始來實作吧!

安裝 Google Cloud SDK

本篇所有的指令都會使用到 Google Cloud SDK 的指令, 所有在我們開始之前,先安裝它哦!
根據你的作業系統的不同,安裝方法也不一樣哦,請參考官方文件

建立 instance

  • 建立兩個 instances
gcloud compute instances create test-01 \
--image-project=ubuntu-os-cloud \
--image-family=ubuntu-1804-lts \
--boot-disk-size=30GB \
--boot-disk-type=pd-standard \
--machine-type=f1-micro \
--tags=test-01,http-server,https-server \
--zone=asia-east1-c
gcloud compute instances create test-02 \
--image-project=ubuntu-os-cloud \
--image-family=ubuntu-1804-lts \
--boot-disk-size=30GB \
--boot-disk-type=pd-standard \
--machine-type=f1-micro \
--tags=test-02,http-server,https-server \
--zone=asia-east1-c
  1. 建立二台機器, 叫做 test-01, test-02
  2. 開機碟的空間為 30GB
  3. ubuntu-os-cloud, 來 pull 我們需要的 image
  4. 我們使用 ubuntu-1804-ltsimage 版本, 這會自動使用這個版本的最新版
  5. 硬碟類型為 pd-standard, 不知道類型可以跑 gcloud compute disk-types list 來看看
  6. 機器型號為 f1-micro, 不知道類型可以跑 gcloud compute machine-types list 來看看
  7. tags 用來當作該 instance 的一個識別,等等開防火牆的時候會用到
  8. zone 指定該 instance 的地區, 有些資源只有相同 zone 或者 region 可以取用,要注意
  9. 可參考官方文件

instance 環境建置

以下為 instance 上的環境建置範例,與本篇主題較無關係,可跳過

apt-get update -y && apt-get install curl -y && curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash && export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" && nvm install yourNodeVersion && apt-get install npm -y && npm install pm2 -g && pm2 update && apt-get install git -y && apt-get install build-essential

開啟防火牆

看服務跑在哪一個 port, 我們需要將防火牆打開,這樣 instance group 才能將 request 從 Load Balancer 經由 backend-service 導向相對應的 port, 可參考官方文件

gcloud compute firewall-rules create test-01 --allow tcp:123,tcp:456,tcp:789 --target-tags test-01
gcloud compute firewall-rules create test-02 --allow tcp:123,tcp:456,tcp:789 --target-tags test-02

外部靜態 IP

這邊建立一個 IPv4 的靜態 IP , 之後會用到, 可參考官方文件

gcloud compute addresses create lb-test \
--ip-version=IPV4 \
--global

Instance group

Instance group 可由多個 instance 所組成,為組成 backend-service 的主體, 可參考官方文件

  • 建立 instance group, 之後 Load Balancer 可以用它來建立不同的 backend-service
gcloud compute instance-groups unmanaged create test --description 'run test project' --zone asia-east1-c
  • 設定 named port, 所以不同的 backend-service 可以指定要用哪一個 port
gcloud compute instance-groups unmanaged set-named-ports test --named-ports port1:3000,port2:6000,port3:9000,port4:12000,port5:15000 --zone asia-east1-c
  • 將現有的 instance 加到 instance group
gcloud compute instance-groups unmanaged add-instances test \
--instances test-01,test-02 \
--zone asia-east1-c

Health check

health-check , 可根據我們指定的頻率,探測指定的 port, 如果該 port 無回應, health-check 將判定這個 port 不健康, backend-service 不會將 request 送往不健康的 instance

可參考官方文件

gcloud compute health-checks create tcp test-tcp-3000 \
--description='test tcp 3000'\
--port=3000
gcloud compute health-checks create tcp test-tcp-6000 \
--description='test tcp 6000'\
--port=6000
gcloud compute health-checks create tcp test-tcp-9000 \
--description='test tcp 9000'\
--port=9000
gcloud compute health-checks create tcp test-tcp-12000 \
--description='test tcp 12000'\
--port=12000
gcloud compute health-checks create tcp test-tcp-15000 \
--description='test tcp 15000'\
--port=15000

Backend service

這邊的 --port-name, 就是上面我們在 instance-group 中,建立的 port, 在此範例中,不同的 backend-service 會將 request 導向不同的 port, 這邊看起來沒有提到 instance group ? 別緊張,下一步我們就會把 instance group 加到 backend-service 當中。

同理, health-check 也是掛在 backend-service 上的, 因為 backend-service 將決定要將 request 導向哪一個 instance。可參考官方文件

  • 建立後端服務
gcloud compute backend-services create backend-service-port1 \
--protocol http \
--port-name port1 \
--health-checks test-tcp-3000 \
--global
gcloud compute backend-services create backend-service-port2 \
--protocol http \
--port-name port2 \
--health-checks test-tcp-6000 \
--global
gcloud compute backend-services create backend-service-port3 \
--protocol http \
--port-name port3 \
--health-checks test-tcp-9000 \
--global
gcloud compute backend-services create backend-service-port4 \
--protocol http \
--port-name port4 \
--health-checks test-tcp-12000 \
--global
gcloud compute backend-services create backend-service-port5 \
--protocol http \
--port-name port5 \
--health-checks test-tcp-15000 \
--global

接下來,我們將 instance group 加到我們剛剛建立的 backend-service, 因為我們在建立 backend-service 時就已指定了 port, 所以 backend-service 會將 request 導向所屬的 instance group 中已指定的 port, 嗯, 聽起來有點饒舌, 不過的確是這樣。

除了設定導向的 port 之外,這邊也會設定 instance 的負載門檻。 設定 UTILIZATION 表示使用率,當使用到 80 % 時, backend-service 便會停止將 request 導向這個 instance

capacity-scaler 表示, 1 * 0.8, 所以說,如果你有多個 backend-service 使用這個 instance-group, 那你希望多保留一些 instance-group 的可使用率,給其他 backend-service 使用,那就可以將 capacity-scaler 調低,如此一來,當這個 backend-service 已使用了 capacity-scaler * max-utilization 的 CPU 時,來自於該 backend-service 的請求就不會導向該 instance-group, 可以很大程度地保留該 instance-group 服務其他 backend-service 的可用性。

下面範例,可參考官方文件

  • 將 instance group 加到 backend-service
gcloud compute backend-services add-backend backend-service-port1 \
--balancing-mode UTILIZATION \
--max-utilization 0.8 \
--capacity-scaler 1 \
--instance-group test \
--instance-group-zone asia-east1-c \
--global
gcloud compute backend-services add-backend backend-service-port2 \
--balancing-mode UTILIZATION \
--max-utilization 0.8 \
--capacity-scaler 1 \
--instance-group test \
--instance-group-zone asia-east1-c \
--global
gcloud compute backend-services add-backend backend-service-port3 \
--balancing-mode UTILIZATION \
--max-utilization 0.8 \
--capacity-scaler 1 \
--instance-group test \
--instance-group-zone asia-east1-c \
--global
gcloud compute backend-services add-backend backend-service-port4 \
--balancing-mode UTILIZATION \
--max-utilization 0.8 \
--capacity-scaler 1 \
--instance-group test \
--instance-group-zone asia-east1-c \
--global
gcloud compute backend-services add-backend backend-service-port5 \
--balancing-mode UTILIZATION \
--max-utilization 0.8 \
--capacity-scaler 1 \
--instance-group test \
--instance-group-zone asia-east1-c \
--global

URL map

前面介紹完了 backend-service, 那這個 url-map, 就是將 request 導向 backend-service 的元件。

首先,我們要先建立一個 url-map, 並且給予一個默認的 backend-service, 意思就是說,如果沒有特別指定的話,收到的 request 要導向哪一個 backend-service

下面範例,可參考官方文件

  • 建立 URL-map
gcloud compute url-maps create web-map \
--default-service backend-service-port1

上面建立了 url-map, 並且指定了一個默認的 backend-service, 現在我們可以定義怎麼樣的 request 該導向哪一個 backend-service

路徑的指定,我們需要使用 path-matcher, 範例如下:

path-matcher: 建立一個 path-matcher, 並給予指定的路徑規則

new-hosts: 當 request 是對 host sunday.com.tw 發請求時,會套用此規則

所以就是說, 當 request 的 host 為 sunday.com.tw 時,會導向 backend-service-port1

以下為範例,可參考官方文件

  • 新增 path-matcher
gcloud compute url-maps add-path-matcher web-map \
--default-service backend-service-port1 \
--path-matcher-name pathmap-port1 \
--new-hosts=sunday.com.tw

這邊可以看到比上面多了一個新的元件,叫做 path-rules

當 request 的 host 為 monday.com.tw, 默認路徑如 / 會導向 backend-service-port2

當 request 的路徑為 happy, 如 monday.com.tw/happy, 會導向 backend-service-port1

當 request 的路徑為 unhappy, 如 monday.com.tw/unhappy, 會導向 backend-service-port2

當 request 的路徑為 sad, 如 monday.com.tw/sad, 會導向 backend-service-port3

gcloud compute url-maps add-path-matcher web-map \
--default-service backend-service-port2 \
--path-matcher-name pathmap-port2 \
--path-rules=/happy=backend-service-port1,/unhappy=backend-service-port2,/sad=backend-service-port3 \
--new-hosts=monday.com.tw

以下範例同上,當 request 為 tuesday.com.tw 時,導向 backend-service-port3

gcloud compute url-maps add-path-matcher web-map \
--default-service backend-service-port3 \
--path-matcher-name pathmap-port3 \
--new-hosts=tuesday.com.tw

建立 SSL 憑證

要讓我們的服務支援 HTTPS, 我們需要建立 ssl-certificates, ssl-certificates 分成 self-managed, 以及 google-managed

self-managed 顧名思義就是你提供你自己的 ssl 簽證,以下範例採用 google-managed

可參考官方文件

gcloud beta compute ssl-certificates create www-ssl-cert \
--domains sunday.com.tw,monday.com.tw,tuesday.com.tw

HTTP proxy

所有來自 HTTP 的請求,都會先到這裡,再經由我們剛剛建立的 url-map 導向指定的 backend-service

可參考官方文件

  • 建立 HTTP proxy
gcloud compute target-http-proxies create http-lb-proxy \
--url-map web-map

HTTPS proxy

所有來自 HTTPS 的請求,都會先到這裡,再經由我們剛剛建立的 url-map 導向指定的 backend-service

並且,我們剛剛建立的 ssl-certificates 也要掛在這, 這樣 target-https-proxies 才能支援 HTTPS

可參考官方文件

  • 建立 HTTPS proxy
gcloud compute target-https-proxies create https-lb-proxy \
--url-map web-map \
--ssl-certificates www-ssl-cert

查看外部靜態 IP 清單

列出我們一開始建立的 addresses

可參考官方文件

gcloud compute addresses list

轉發規則

當 request 的 address 以及 port 符合 forwarding-rules, 導向指定的 target-http-proxy

下面範例的 [LB_IP_ADDRESS] 請替換為上面建立的靜態 IP

可參考官方文件

  • 建立 HTTP forwarding-rules
gcloud compute forwarding-rules create http-content-rule \
--address [LB_IP_ADDRESS] \
--global \
--target-http-proxy http-lb-proxy \
--ports 80

當 request 的 address 以及 port 符合 forwarding-rules, 導向指定的 target-https-proxy

下面範例的 [LB_IP_ADDRESS] 請替換為上面建立的靜態 IP

可參考官方文件

  • 建立 HTTPS forwarding-rules
gcloud compute forwarding-rules create https-content-rule \
--address [LB_IP_ADDRESS] \
--global \
--target-https-proxy https-lb-proxy \
--ports 443

總結

以上便是 GCP Load Balancer 的 gcloud 各元件順序流程,順序如下:
request => forwarding-rules => target-http(s)-proxy => url-map => backend-service => instance-group => instance

照著以上範例跑完之後,只要在 instance 跑服務,並且跑在範例上指定的 port 號,那 request 應會照著上面的順序到達我們的服務。

我花了不少時間來寫這篇文章,希望有幫到需要的人,如果你已經看到這裡,很感謝你把它看完了!

最後,如果你覺得這篇文章有幫到你,或者你覺得寫得不錯,你的掌聲將是對我最大的鼓勵!

如果有發現任何錯誤,還請不吝指教哦!

Cloud Storage 初探 - 主控台 MySQL 學習筆記

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×