環境信息:
集群網絡:10.244.0.0/16
Service網絡: 10.243.0.0/16
節點: 172.16.20.120 , 集群網絡: 10.244.5.0/24 , cni0: 10.244.5.1/24 ,flannel.1: 10.244.5.0/32
節點: 172.16.20.121 , 集群網絡: 10.244.3.0/24 , cni0: 10.244.3.1/24 , flannel.1: 10.244.3.0/32
Service是由kube-proxy組件實現,而kube-proxy支持多種負載均衡機制,今天講ipvs模式在kubenertes中的應用。
修改ipvs模式:
kubectl edit configmap kube-proxy -n kube-system
mode: "ipvs"
kube-proxy不能動態生效,需要刪除kube-proxy,后才會生效
kubectl delete pod kube-proxy-xxx -n kube-system
我們寫一個測試yml文件 nginx-deploy-svc.yml,如下:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: lvs-test
name: lvs-deploy-test
spec:
replicas: 3
selector:
matchLabels:
app: lvs-test
template:
metadata:
labels:
app: lvs-test
spec:
containers:
- image: nginx
name: lvs-pod-test
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
app: lvs-test
name: lvs-svc-test
spec:
ports:
- port: 8880
protocol: TCP
targetPort: 80
selector:
app: lvs-test
type: NodePort
部署
kubectl apply -f nginx-deploy-svc.yml
獲取svc/deploy/pod
# kubectl get svc,pod,deploy -l app=lvs-test -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/lvs-svc-test NodePort 10.243.21.14 <none> 8880:30981/TCP 25m app=lvs-test
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/lvs-deploy-test-5944d4f9dc-2ljcw 1/1 Running 0 28m 10.244.5.23 cvm-120 <none> <none>
pod/lvs-deploy-test-5944d4f9dc-h8l8x 1/1 Running 0 28m 10.244.5.24 cvm-120 <none> <none>
pod/lvs-deploy-test-5944d4f9dc-wpqtc 1/1 Running 0 28m 10.244.3.32 cvm-121 <none> <none>
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment.apps/lvs-deploy-test 3/3 3 3 28m lvs-pod-test nginx app=lvs-test
獲取svc詳情
# kubectl describe service/lvs-svc-test
Name: lvs-svc-test
Namespace: default
Labels: app=lvs-test
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"lvs-test"},"name":"lvs-svc-test","namespace":"default"},...
Selector: app=lvs-test
Type: NodePort
IP: 10.243.21.14
Port: <unset> 8880/TCP
TargetPort: 80/TCP
NodePort: <unset> 30981/TCP
Endpoints: 10.244.3.32:80,10.244.5.23:80,10.244.5.24:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
從上面可以看到訪問宿主機+30981 (網絡可達宿主機就行),訪問 10.243.21.14:8880 (由於是vip,非集群主機不能訪問,只能集群內部訪問) 時會轉發流量到 10.244.3.32:80,10.244.5.23:80,10.244.5.24:80。 那這種轉發是如何實現的了?
我們查看lvs
# ipvsadm -L -n (省略部分輸出)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.243.21.14:8880 rr
-> 10.244.3.32:80 Masq 1 0 0
-> 10.244.5.23:80 Masq 1 0 0
-> 10.244.5.24:80 Masq 1 0 0
再查看ipvsadm幫助
# ipvsadm -L -n
--gatewaying -g gatewaying (direct routing) (default) # DR
--ipip -i ipip encapsulation (tunneling) # TUN
--masquerading -m masquerading (NAT) # NAT
# man ipvsadm
rr - Round Robin: distributes jobs equally amongst the available real servers. # 輪詢
可以看到這里ipvs使用的是NAT模式(NAT模式可參考其他文章)。
測試,在172.16.20.120 執行 curl http://10.243.21.14:8880 ,在各機器抓包
172.16.20.121:flannel.1 , 看到的是10.244.5.0 -> 10.244.3.32:80
172.16.20.121: eth0 , 看到的是 172.16.20.120 -> 172.16.20.121:8472 是flannel進程的端口 , udp ,這里有一個OTV ,可以網上查一查
172.16.20.120: flannel.1 ,和 172.16.20.121 flannel.1看到的是一樣的。
再查看nat轉發表, 可以看到這是fullnat轉發。 另外兩台是lvs轉發給5.24和5.23的,這是120本地的容器。
執行curl的大致過程如下:
120機器
請求發起:10.243.21.14:48480->10.243.21.14:8880
IPVS-輪詢,目標為:10.244.3.32:80
根據路由表,下一跳為 10.244.3.0 ,出口為flannel.1 ,flannel.1的ip地址為10.244.5.0 #10.244.3.0 10.244.3.0 255.255.255.0 UG 0 0 0 flannel.1
根據FULLNAT:10.244.5.0:48480->10.244.3.32:80 (稱為:原始包), 並記錄nat表。# ipv4 2 tcp 6 112 TIME_WAIT src=10.243.21.14 dst=10.243.21.14 sport=48480 dport=8880 src=10.244.3.32 dst=10.244.5.0 sport=80 dport=48480 [ASSURED] mark=0 zone=0 use=2
根據etcd學習到的 10.244.3.0的mac地址為ee:d6:38:55:d5:c7 ,封裝vxlan , 包格式: vni| 10.244.5.0的mac , 10.244.3.0的mac | 原始ip包 。 (稱為:vxlan包) # 10.244.3.0 ether ee:d6:38:55:d5:c7 CM flannel.1
根據etcd學習到 10.244.3.0在172.16.20.121節點, 封裝udp包, udp端口 8472. 包格式: udp封裝部分 | xvxlan包 。
121機器收到包,過程也一樣,目標為121,接收,端口為 8472 ,接收 , 解封裝, 目標mac為3.0的,接收,解封裝,目標為 3.32 ,到達目的地。 反包這里就不再抒寫了。
120接到回包解封裝后,為10.243.3.32:80 -> 10.244.5.0:48480 ,尋找NAT標, 轉發給 10.243.21.14L48480, curl進程接收,
結束。
再測試,從121節點上的 busybox容器 telnet 10.243.21.14 8880
在121節點, flannel.1抓包, 看到的是10.244.3.10:59528 (busybox) -> 10.244.5.23:80
在121節點,查看nat表
在120節點,eth0抓包,172.16.20.121.50813 > 172.16.20.120.8472 , 有一層udp封裝
這里只做了目標地址轉換, 因為10.244.3.10在各節點是可達的(通過flannel網絡可達)