环境信息:
集群网络: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网络可达)