东西向网络service详解

1. service介绍

service主要解决两个问题,一个是pod的ip不固定,一个是pod的负载均衡需求,某种意义上类似微服务的注册中心,用于pod之间的注册与发现。

2. hostnames样例实践

因consul使用的是head less,没有负载均衡相关能力,故此处的示例通过官方的hostname样例进行说明。

#定义service
apiVersion: v1
kind: Service
metadata:
  name: hostnames
spec:
  selector:
    app: hostnames
  ports:
    - name: default
      port: 80
      targetPort: 9376
      protocol: TCP
#定义deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostnames
  labels:
    app: reviews
    version: v3
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hostnames
  template:
    metadata:
      labels:
        app: hostnames
    spec:
      containers:
      - name: hostnames
        image: k8s.gcr.io/serve_hostname:latest
        ports:
        - containerPort: 9376
          protocol: TCP

执行kubectl apply -f *.yaml后,hostnames就拉起来了。

可以看到cluster-ip为10.107.205.181,hostnames的endpoints为10.244.2.97:9376,10.244.3.49:9376,10.244.3.50:9376,宿主机上访问vip地址,可以看到能访问到其代理的pod。

[root@k8s-master snap]# kubectl get svc hostnames
NAME        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
hostnames   ClusterIP   10.107.205.181   <none>        80/TCP    8m6s

[root@k8s-master snap]# kubectl get endpoints hostnames
NAME        ENDPOINTS                                            AGE
hostnames   10.244.2.97:9376,10.244.3.49:9376,10.244.3.50:9376   21m

[root@k8s-master snap]# kubectl get pods -o wide
NAME                                     READY   STATUS    RESTARTS   AGE     IP             NODE        NOMINATED NODE   READINESS GATES
hostnames-659d5d6f56-bkr69               1/1     Running   0          3m22s   10.244.2.97    k8s-node2   <none>           <none>
hostnames-659d5d6f56-j5ptd               1/1     Running   0          3m23s   10.244.3.50    k8s-node3   <none>           <none>
hostnames-659d5d6f56-sblg9               1/1     Running   0          3m25s   10.244.3.49    k8s-node3   <none>           <none>

[root@k8s-node1 ~]# curl 10.107.205.181:80
hostnames-659d5d6f56-j5ptd
[root@k8s-node1 ~]# curl 10.107.205.181:80
hostnames-659d5d6f56-sblg9
[root@k8s-node1 ~]# curl 10.107.205.181:80
hostnames-659d5d6f56-j5ptd
[root@k8s-node1 ~]# curl 10.107.205.181:80
hostnames-659d5d6f56-bkr69
3. service实现解析
  1. service通过kube-proxy组件加linux的iptables实现,hostnames创建时,kube-proxy通过service的Informer机制感知到service对象的添加,然后再宿主机上创建一条iptables规则。

  2. 10.107.205.181端口为80的ip包会跳到KUBE-SVC-ODX2UBAZM7RQWOIU的iptables链进行处理。可以看到3条链的概率为0.33,0.5,1,因iptables规则匹配是从上往下逐条执行,所以每条链的概率都为1/3。

  3. 跟踪KUBE-SEP-ESCSO4DZ6QJFDVPZ链,可以看到其实是条DNAT规则,指向10.244.2.97:9376。

[root@k8s-node1 ~]# iptables-save | grep hostnames | grep cluster
-A KUBE-SERVICES -d 10.107.205.181/32 -p tcp -m comment --comment "default/hostnames:default cluster IP" -m tcp --dport 80 -j KUBE-SVC-ODX2UBAZM7RQWOIU

[root@k8s-node1 ~]# iptables-save | grep KUBE-SVC-ODX2UBAZM7RQWOIU
-A KUBE-SVC-ODX2UBAZM7RQWOIU -m comment --comment "default/hostnames:default" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-ESCSO4DZ6QJFDVPZ
-A KUBE-SVC-ODX2UBAZM7RQWOIU -m comment --comment "default/hostnames:default" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-P5WZKF5SFCHMY4QQ
-A KUBE-SVC-ODX2UBAZM7RQWOIU -m comment --comment "default/hostnames:default" -j KUBE-SEP-7ZEX5NM4FNAFXYKX

[root@k8s-node1 ~]# iptables-save | grep  KUBE-SEP-ESCSO4DZ6QJFDVPZ
:KUBE-SEP-ESCSO4DZ6QJFDVPZ - [0:0]
-A KUBE-SEP-ESCSO4DZ6QJFDVPZ -s 10.244.2.97/32 -m comment --comment "default/hostnames:default" -j KUBE-MARK-MASQ
-A KUBE-SEP-ESCSO4DZ6QJFDVPZ -p tcp -m comment --comment "default/hostnames:default" -m tcp -j DNAT --to-destination 10.244.2.97:9376
4. 基于iptables实现的弊端

可以看到iptables处理service,需要在宿主机上设置iptables规则,当宿主机存在大量pod时,iptables规则不断被刷新,会大量占用cpu资源。所以该实现不能支撑大量pod的k8s集群。

要解决该问题,一般会通过IPVS模式,IPVS与iptables的实现类似,也是基于netfilter的NAT模式,在转发的性能上看并没有提升,不过IPVS把iptables的规则处理放到了内核态,从而减少了维护这些规则的代价。

5. service的访问方式

除了前面通过VIP的方式,k8s也提供了dns访问pod的能力,在1.18是运行在集群的coredns pod提供dns的能力.

  • 对于clusterIP模式的service,,它的dns格式为 m y − s v c . my-svc. mysvc.my-namespace.svc.cluster.local,比如前面提到的hostnames,对应的访问方式为hostnames.default.svc.cluster.local.
  • 对于clusterIP=None的headless来说,它的dns格式同样为 m y − s v c . my-svc. mysvc.my-namespace.svc.cluster.local,比如前面章节提到的consul,但其返回的是所有consul pod的IP地址集合,如果客户端未做适配解析该集合,则只会返回第一个pod地址。
  • 对于headless来说,它可以直接访问到指定的pod,格式为 m y − p o d . my-pod. mypod.my-svc.$my-namespace.svc.cluster.local。
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐