如果想要在 Google Cloud Platform 的 GKE 上使用 Ingress 功能,最簡單的方式就是用 GKE 本身預設提供的 ingress-gce
controller。不過不知道大家在設定 ingress yaml 的時候,有沒有留意到 ingress-gce
規定 service type 只能是 NodePort
,但是 ingress-nginx
卻沒有這種限制呢?
本篇文章會從 Google Cloud Platform 所提供的 load balancer 服務開始說明,並且結合 ingress-gce
controller,讓大家瞭解兩者的運作方式和限制原因。
Google Cloud Platform Load Balancer
首先來說明 Google Cloud Platform 的 external load balancer 的運作流程:
- user 向 server 發送 request 後,GCP 會將 package 的 dest. IP address 和 forwarding table 進行比對(match),並將 network packages 轉送到比對成功的 forwarding rule 所指定的 proxy server。
- Proxy server 取出 package 中的 URL 資訊,再根據 GCP 上設定的 URL map 來決定該將 package 轉發到哪一個 backend service。(routing)
- 最後,依據 backend service 的設定將 package 分配到對應 group 底下的 backend server。
而實際對應到 GCP load balancer 設定,就會是:
如果是使用 GCP cloud console 的話,也可以切換到 advanced menu,就能看到上述所提到的各細節設定,包含 target proxy 和 forwarding rule 等。
Ingress-gce with GCP Load Balancer
了解基本 GCP load balancer 運作方式之後,接著我們來看 ingress-gce
如何結合 GCP load balancer 來實現 ingress 功能。
ingress-gce
是實現 Kubernetes ingress 抽象層的 controller,而實際負責管理 traffic 的 ingress server 當然就是 GCP load balancer。另外,ingress-gce
controller 目前支援建立 L7 external / internal HTTP(S) Load Balancing,所以假如是只需要 L4(TCP/UDP) 的 load Balancing,就需要指定其他 ingress controller。
因此,當使用者部署或是更新 ingress resource 時,ingress-gce
ingress controller 就會 call GCP compute load balancer API 來調整相關配置。
而在第一部分已經有簡單介紹過 GCP load balancer 所需要的各設定,那麼這些設定該怎麼跟 Kubernetes 的 ingress resource 和機制做整合呢?
1. Forwarding Rules
建立 forwarding rule 需要 (1) external IP address 和 (2) proxy server。
如果在 yaml annotation 沒有設定既有的 static external IP, ingress-gce
controller 就會自動建立一個 global external IP,並且根據 yaml 內的 TLS 設定來決定要選擇 HTTP 或是 HTTPS proxy server。
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-ingress
annotations:
kubernetes.io/ingress.global-static-ip-name: <static-address>
仔細看 static IP 的設定,它是 global-static-ip-name,Global 這字非常重要,原因是 GCP 的 HTTP(s) load balancer 是比對 global forwarding table,因此就需要使用 global static IP, 假設既有的 static IP 是 regional static IP ,那它是不能被套用在設定上的。
URL map
URL map 相對來說就簡單理解,就是把 yaml 設定檔中的 host 和 path 組成 GCP load balancer 所需要的 URL map,舉例來說:
spec:
rules:
- host: example.com
http:
paths:
- path: /
backend:
serviceName: web-server
servicePort: http
- host: beta.example.com
http:
paths:
- path: /
backend:
serviceName: beta-web-server
servicePort: http
就會產生三個對應 mapping rules,分別是
default
example.com/*
beta.example.com/*
而這三個 rules 會分別對應到各自不同的 backend service。
Backend Service
最後一步就是要將 kubernetes cluster 中的 nodes 對應到 GCP load balancer 的 backend service。Backend service 需要關聯到至少一個 Backend Group,這個 Backend Group 可以是:
- instance group
- network endpoints group
而在 GKE Ingress for HTTP(S) load balancing 有提到,如果可以的話,盡可能地使用 Network Endpoint Groups (NEGs)
以提高 package 轉送效率,因此我們就以 network endpoints group 來做說明。
在 service yaml 加入{"ingress": true}
:
apiVersion: v1
kind: Service
metadata:
name: neg-demo-svc
annotations:
cloud.google.com/neg: '{"ingress": true}'
spec:
type: NodePort
selector:
run: neg-demo-app
ports:
- port: 80
protocol: TCP
targetPort: 9376
source code from Using container-native load balancing
這樣 ingress-gce
controller 就會根據 service selector 所選到的 pods 來組成一個 network endpoints group。示意圖如下:
每個 endpoint 是由 node ID 和 pod IP 所組成,這樣在轉送 package 的時候,就可以直接送到 pod 內,而不需要透過 node 內的 iptable 再轉發到 pod 了。
NodePort
回到文章一開始的問題,為什麼 ingress-gce
controller 的 service 必須要是 NodePort type?
這原因很簡單,從上面描述可以知道 ingress server 就是 GCP load balancer,而 ingress-gce
controller 根據 ingress resource 來更新 GCP load balancer 設定,但是 GCP load balancer 這個 ingress server 並不在我們 cluster 中,如果我們將 service type 設為 clusterIP,那麼外部的 ingress server 就無法解析出正確 IP 位置,也無法透過 : 方式來將 package 送到正確的 pod 中。
Recap
最後,總結幾個重點:
- GKE default 的 ingress controller 是
ingress-gce
而 ingress server 是 GCP load balancer。 - GCP load balancer 有幾個必備 components,包含:forwarding rules(static IP and proxy server)、URL map、backend service。當建立 ingress 時,controller 會根據 yaml 內容建立起對應的 load balancer component。
- 推薦在建立 cluster 時啟用
VPC-native
功能,並且設定NEGs(network endpoints group)
,有助於提升 package 轉送效率。