本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
使用 KPNG 編寫專門的 kube-proxier
本文將向您展示如何使用 Kubernetes Proxy NG kpng 建立一個專業的服務 kube-proxy 風格的網路代理器,而不會干擾現有的 kube-proxy。kpng 專案旨在更新預設的 Kubernetes Service 實現,即“kube-proxy”。kpng 的一個重要特性是它可以作為一個庫在 K8s 之外建立代理器。雖然這對於取代 kube-proxy 的 CNI 外掛很有用,但它也為任何人建立特殊用途的代理器提供了可能性。
定義一個使用專用代理器的服務
apiVersion: v1
kind: Service
metadata:
name: kpng-example
labels:
service.kubernetes.io/service-proxy-name: kpng-example
spec:
clusterIP: None
ipFamilyPolicy: RequireDualStack
externalIPs:
- 10.0.0.55
- 1000::55
selector:
app: kpng-alpine
ports:
- port: 6000
如果定義了 service.kubernetes.io/service-proxy-name
標籤,kube-proxy
將忽略該服務。自定義控制器可以監視帶有設定為其自身名稱(在此示例中為“kpng-example”)的標籤的服務,並設定專門的負載均衡。
service.kubernetes.io/service-proxy-name
標籤並非新功能,但迄今為止,編寫專用代理器一直相當困難。
專用代理器的常見用途被認為是處理 K8s 不支援的某些用例的外部流量。在這種情況下,不需要 ClusterIP
,因此在此示例中我們使用“無頭”服務。
使用 kpng 的專用代理器
基於 kpng 的代理器由處理所有 K8s API 相關功能的 kpng
控制器和一個實現負載均衡的“後端”組成。後端可以與 kpng
控制器二進位制檔案連結,也可以是使用 gRPC 與控制器通訊的單獨程式。
kpng kube --service-proxy-name=kpng-example to-api
這將啟動 kpng
控制器,並告訴它只監視帶有“kpng-example”服務代理名稱的服務。“to-api”引數將開啟一個 gRPC 伺服器用於後端。
您可以在叢集外部自行測試。請參閱下面的示例。
現在我們啟動一個後端,它只打印來自控制器的更新。
$ kubectl apply -f kpng-example.yaml
$ kpng-json | jq # (this is the backend)
{
"Service": {
"Namespace": "default",
"Name": "kpng-example",
"Type": "ClusterIP",
"IPs": {
"ClusterIPs": {},
"ExternalIPs": {
"V4": [
"10.0.0.55"
],
"V6": [
"1000::55"
]
},
"Headless": true
},
"Ports": [
{
"Protocol": 1,
"Port": 6000,
"TargetPort": 6000
}
]
},
"Endpoints": [
{
"IPs": {
"V6": [
"1100::202"
]
},
"Local": true
},
{
"IPs": {
"V4": [
"11.0.2.2"
]
},
"Local": true
},
{
"IPs": {
"V4": [
"11.0.1.2"
]
}
},
{
"IPs": {
"V6": [
"1100::102"
]
}
}
]
}
一個真正的後端將使用某種機制來平衡從外部 IP 到端點的流量。
編寫後端
kpng-json
後端如下所示:
package main
import (
"os"
"encoding/json"
"sigs.k8s.io/kpng/client"
)
func main() {
client.Run(jsonPrint)
}
func jsonPrint(items []*client.ServiceEndpoints) {
enc := json.NewEncoder(os.Stdout)
for _, item := range items {
_ = enc.Encode(item)
}
}
(是的,這就是整個程式)
當然,一個真正的後端會複雜得多,但這說明了 kpng
如何讓您專注於負載均衡。
您可以將多個後端連線到 kpng
控制器,因此在開發或除錯期間,讓 kpng-json
後端之類的東西與您的真實後端並行執行可能很有用。
示例
完整示例可在此處找到。
作為示例,我們實現了一個“all-ip”後端。它將所有外部 IP 的流量定向到本地端點,無論埠和上層協議如何。針對此功能有一個 KEP,本示例是一個大大簡化的版本。
要將所有來自外部地址的流量定向到本地 POD,只需一個 iptables 規則,例如:
ip6tables -t nat -A PREROUTING -d 1000::55/128 -j DNAT --to-destination 1100::202
如您所見,地址在對後端的呼叫中,它所要做的就是
- 提取
Local: true
的地址 - 為
ExternalIPs
設定 iptables 規則
執行此操作的指令碼可能如下所示
xip=$(cat /tmp/out | jq -r .Service.IPs.ExternalIPs.V6[0])
podip=$(cat /tmp/out | jq -r '.Endpoints[]|select(.Local == true)|select(.IPs.V6 != null)|.IPs.V6[0]')
ip6tables -t nat -A PREROUTING -d $xip/128 -j DNAT --to-destination $podip
假設上述 JSON 輸出儲存在 /tmp/out
中(jq 是一個很棒的程式!)。
由於這是一個示例,我們透過使用上述 kpng-json
後端的一個小變體來簡化自身。不是隻列印,而是呼叫一個程式,並將 JSON 輸出作為 stdin
傳遞給該程式。後端可以獨立測試
CALLOUT=jq kpng-callout
其中 jq
可以替換為您自己的程式或指令碼。指令碼可能看起來像上面的示例。有關更多資訊和完整示例,請參閱 https://github.com/kubernetes-sigs/kpng/tree/master/examples/pipe-exec。
總結
雖然 kpng 仍處於早期開發階段,但本文旨在展示您將來如何構建自己的專用 K8s 代理器。您的應用程式唯一需要做的就是在 Service manifest 中新增 service.kubernetes.io/service-proxy-name
標籤。
將新功能引入 kube-proxy
是一個繁瑣的過程,而且它們很可能被拒絕,因此編寫專用代理器可能是唯一的選擇。