摘要:服務本身的源碼非常簡單,只返回客戶端地址,如下所示。結果顯示用戶的訪問地址是一臺云主機的內網地址,顯然不正確。重新部署服務后,再用瀏覽器訪問,可以發現正確獲取了瀏覽器的訪問。
如果是HTTP1.1協議,一般的反向代理或者負載均衡設備(如ULB7)支持X-Forwarded-For頭部字段,會在用戶的請求報文中加入類似X-Forwarded-For:114.248.238.236的頭部。Web應用程序只需要解析該頭部即可獲得用戶真實IP。
如果是TCP或UDP自定義協議,可以客戶端在協議字段里定義一個大端unsigned字段來保存自身IP,服務端把該字段解析出來然后調用inet_ntoa(3)等函數獲得ipv4點分字符串。
如果2中協議不支持填寫自身IP,則服務端可以通過socket系統調用getpeername(2)來獲取對端地址。下文討論此方式。
Kubernetes Loadbalancer ULB4碰到的問題UK8S使用ULB4和ULB7來支持Loadbalancer類型的Service。對于ULB7,由于只支持HTTP協議且默認支持X-Forwarded-For頭部,所以Web服務可以很容易獲取客戶端的真實IP。但對于使用ULB4接入的純四層協議的服務來說,可能需要使用getpeername(2)來獲取客戶端真實IP。然而由于目前kube-proxy采用Iptables模式,后端pod內的應用程序的網絡庫調用getpeername(2)會無法獲得正確的IP地址。以下例子可以說明問題。
部署一個簡單的webserver,通過Loadbalancer ULB4外網模式接入。
apiVersion: v1
kind: Service
metadata:
name: ucloud-nginx
labels:
app: ucloud-nginx
annotations:
service.beta.kubernetes.io/ucloud-load-balancer-type: "outer"
service.beta.kubernetes.io/ucloud-load-balancer-vserver-method: "source"
spec:
type: LoadBalancer
ports:
- protocol: "TCP"
port: 80
targetPort: 12345
selector:
app: ucloud-nginx
---
apiVersion: v1
kind: Pod
metadata:
name: test-nginx
labels:
app: ucloud-nginx
spec:
containers:
- name: nginx
image: uhub.service.ucloud.cn/uk8s/uk8s-helloworld:stable
ports:
- containerPort: 12345
部署完畢后,Service狀態如下所示,可以通過EIP 117.50.3.206訪問該服務。
# kubectl get svc ucloud-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ucloud-nginx LoadBalancer 172.17.179.247 117.50.3.206 80:43832/TCP 112s
服務本身的源碼非常簡單,只返回客戶端地址,如下所示。
package main
import (
"fmt"
"io"
"log"
"net/http"
"net/http/httputil"
)
func main() {
log.Println("Server hello-world")
http.HandleFunc("/", AppRouter)
http.ListenAndServe(":12345", nil)
}
func AppRouter(w http.ResponseWriter, r *http.Request) {
dump, _ := httputil.DumpRequest(r, false)
log.Printf("%q
", dump)
io.WriteString(w, fmt.Sprintf("Guest come from %v
", r.RemoteAddr))
return
}
在外網通過瀏覽器訪問該服務,如下所示。
結果顯示用戶的訪問IP地址是一臺云主機的內網IP地址,顯然不正確。
原因解釋Loadbalancer創建成功后,ULB4的VServer將UK8S集群中的每個Node云主機節點作為自身的RS節點,RS端口為Service申明的Port值(注意不是NodePort)。ULB4將訪問流量轉發到其中一個RS后,RS根據本機上kube-proxy生成的iptables規則將流量DNAT到后端Pod中,如下所示。
圖中ULB4先將流量轉發到Node1中,Node1中根據iptables DNAT規則,將流量轉發給Node2中的Pod。 需要注意的是,Node1將IP包轉發到Node2前,對這個包有一次SNAT操作。準確地說,是一次MASQUERADE操作,規則如下。
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE
這條規則將源地址改成Node1的本機地址,即10.9.31.26。當然,這個 SNAT 操作只針對本Service轉發出來的包,否則普通的IP包也受到影響了,而判定IP包是否由本Service轉發出來的依據是改包上是有有個"0x4000"標志,這個標志則是在DNAT操作前打上去的。
由于IP請求包的源地址被修改,Pod內的程序網絡庫通過getpeername(2)調用獲取到的對端地址是Node1的IP地址而不是客戶端真實的地址。
為什么需要對流出的包做SNAT操作呢?
原因比較簡單。參考下圖,當Node1上的Pod處理完請求后,需要發送響應包,如果沒有SNAT操作,Pod收到的請求包源地址就是client的IP地址,這時候Pod會直接將響應包發給client的IP地址,但對于client程序來說,它明明沒有往PodIP發送請求包,卻收到來自Pod的IP包,這個包很可能會被client丟棄。而有了SNAT,Pod會將響應包發給Node1,Node1再根據DNAT規則產生的conntrack記錄,將響應包通過返回給client。
client
^
v
ulb4
^
v
node 1 <--- node 2
| ^ SNAT
| | --->
v |
endpoint
如何獲取源IP?對于Pod需要明確知道客戶端來源地址的情況,我們需要顯示地將Service的spec.externalTrafficPolicy設置成Local,如下修改。
apiVersion: v1
kind: Service
metadata:
name: ucloud-nginx
labels:
app: ucloud-nginx
annotations:
service.beta.kubernetes.io/ucloud-load-balancer-type: "outer"
service.beta.kubernetes.io/ucloud-load-balancer-vserver-method: "source"
spec:
type: LoadBalancer
ports:
- protocol: "TCP"
port: 80
targetPort: 12345
selector:
app: ucloud-nginx
externalTrafficPolicy: Local
重新部署服務后,再用瀏覽器訪問,可以發現Pod正確獲取了瀏覽器的訪問IP。
而這個機制的原理也很簡單,當設置了externalTrafficPolicy為Local時,Node上的iptables規則會設置只將IP包轉發到在本機上運行的Pod,如果本機上無對應Pod在運行,此包將被DROP。如下圖,這樣Pod可以直接使用client的源地址進行回包而不需要SNAT操作。
client
^
v
ulb4
^ /
/ / VServer健康檢查失敗
/ v X
node 1 node 2
^ |
| |
| v
endpoint
對于其他未運行Service對應Pod的Node節點來說,ULB VServer對其健康檢查探測會因為iptables的DROP規則而失敗,這樣來自用戶的請求永遠不會被發往這些節點上,可以確保這些請求都能被正確響應。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/126937.html
摘要:原因解釋創建成功后,的將集群中的每個云主機節點作為自身的節點,端口為申明的值注意不是。如何獲取源對于需要明確知道客戶端來源地址的情況,我們需要顯示地將的設置成如下修改。重新部署服務后,再用瀏覽器訪問,可以發現正確獲取了瀏覽器的訪問。ULB屬性修改的處理方法如沒有實際需要,請避免修改ULB名稱及注釋根據cloudprovider插件使用提醒,由UK8S cloudprovider創建的ULB不...
摘要:詳細請見產品價格產品概念使用須知名詞解釋漏洞修復記錄集群節點配置推薦模式選擇產品價格操作指南集群創建需要注意的幾點分別是使用必讀講解使用需要賦予的權限模式切換的切換等。UK8S概覽UK8S是一項基于Kubernetes的容器管理服務,你可以在UK8S上部署、管理、擴展你的容器化應用,而無需關心Kubernetes集群自身的搭建及維護等運維類工作。了解使用UK8S為了讓您更快上手使用,享受UK...
摘要:提供在線升級的功能,插件升級不會影響現有的網絡。升級功能開啟后,即可看到插件版本信息,點擊升級即可進行升級。年月日修復固定意外釋放導致不可用的問題修復搶占文件鎖超時導致釋放失敗的問題插件開啟后,將默認使用其管理。 網絡插件 升級本篇目錄1. 網絡插件升級2. 網絡插件更新紀要UK8S 提供的 CNI (Container Network Interface)基于 UCloud VPC 網絡實...
摘要:更新商店信息查詢應用安裝商店應用安裝商店應用執行了安裝商店應用的命令后,我們看到了系統返回給我們了安裝的詳細信息。安裝應用安裝商店應用按照前文helm工具已經安裝完成,接下來通過helm客戶端在kubernetes集群中創建一個應用,執行安裝前最好先進行應用商店的同步,以獲得最新的應用信息。#更新商店信息 helm repo update #查詢tomcat應用 helm search to...
摘要:集群常見問題單個集群最多能添加多少個節點當前單個集群對應節點數量可查看集群節點配置推薦。創建失敗,使用發現報錯為,是啥原因在創建等資源時,都需要扮演云賬戶的身份調用來完成相關操作。集群內可以解析,但無法聯通外網拉取數據失敗。集群常見問題單個集群最多能添加多少個節點?A:當前單個UK8S集群對應節點數量可查看集群節點配置推薦。UK8S完全兼容原生Kubernetes API嗎?A:完全兼容。U...
摘要:通過暴露是社區的一個開源項目,你可以通過來部署更新應用排查應用故障以及管理集群資源。執行以下命令安裝,使用的鏡像已經去掉了的證書限制。不支持的版本范圍。通過ULB暴露Kubernetes DashboardDashboard是Kubernetes社區的一個Web開源項目,你可以通過Dashboard來部署更新應用、排查應用故障以及管理Kubernetes集群資源。另外,Dashboard還提...
閱讀 289·2024-11-07 18:25
閱讀 130366·2024-02-01 10:43
閱讀 868·2024-01-31 14:58
閱讀 828·2024-01-31 14:54
閱讀 82766·2024-01-29 17:11
閱讀 3048·2024-01-25 14:55
閱讀 1985·2023-06-02 13:36
閱讀 3033·2023-05-23 10:26