kubernetes系列之 service代理模式ipvs

环境信息:
集群网络: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
kubernetes系列之 service代理模式ipvs

172.16.20.121: eth0 , 看到的是 172.16.20.120 -> 172.16.20.121:8472 是flannel进程的端口 , udp ,这里有一个OTV ,可以网上查一查
kubernetes系列之 service代理模式ipvs

172.16.20.120: flannel.1 ,和 172.16.20.121 flannel.1看到的是一样的。
kubernetes系列之 service代理模式ipvs

再查看nat转发表, 可以看到这是fullnat转发。 另外两台是lvs转发给5.24和5.23的,这是120本地的容器。
kubernetes系列之 service代理模式ipvs

执行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
kubernetes系列之 service代理模式ipvs
在121节点,查看nat表
kubernetes系列之 service代理模式ipvs
在120节点,eth0抓包,172.16.20.121.50813 > 172.16.20.120.8472 , 有一层udp封装
kubernetes系列之 service代理模式ipvs
这里只做了目标地址转换, 因为10.244.3.10在各节点是可达的(通过flannel网络可达)

相关推荐