Kubernetes实践之从Ingress到Pod访问流程

2,024 阅读4分钟

一、导读

我们将应用程序部署到 K8s 集群中,如果想要访问部署的 Pod,需要通过 Service 来进行访问,想要将应用暴露给集群外访问需要用到 Ingress ,那么这些服务之间是怎么进行协作的呢?

二、请求流程

image.png

流程看似很简单,但是里面涉及到的东西不少,下面将流程拆分出来单独梳理。

三、Service访问Pod

我们不应该期望 Kubernetes Po d是健壮的,而是要假设 Pod 中的容器很可能因为各种原因发生故障而死掉。Deployment 等 Controller 会通过动态创建和销毁 Pod 来保证应用整体的健壮性。换句话说,Pod 是脆弱的,但应用是健壮的,所以每一次销毁重建 Pod 时,Pod 对应的 Ip 地址都会发生变化,Kubernetes 针对这个问题给出的解决方案就是使用 Service 来访问 Pod

1、Service 选定 Pod

Service 通过 label 来选择对应的 Pod,在 Service 的 yaml 描述文件中,使用 selector 来选中对用的 Pod

---
apiVersion: v1
kind: Service
metadata:
  name: codereviewapi
  namespace: codereview
spec:
  ports:
    - name: codereviewapip
      port: 80
      protocol: TCP
      targetPort: 8888
  selector:
    app: codereviewapi
    group: codereview
  sessionAffinity: None
  type: ClusterIP

在上面的描述文件中选中的是包含app=codereviewapi,group=codereview标签的Pod应用,同时对外暴露端口80

2、Cluster IP 底层实现

每一个 Service 会分配一个 Cluster 虚拟 Ip,可以将 Service 选中的 Pod 当成一个虚拟集群,那么这个 Cluster Ip 就是这个集群的 Ip

可以用过命令 kubectl describe svc {ServiceName} -n {Namespace} 来查看Service的详细信息,里面 Ip 那一行就是对应的Cluster Ip,这个我们不用记,使用时只要使用 ServiceName 就行了

image.png

3、Service 负载均衡

Service 通过 Cluster Ip 对 Pod 集群进行访问,主要是由 Kubernetes 节点上的 iptables 规则来实现的,下面我们打印出一个 Cluster Ip 对应的具体 iptables 规则。

在任一节点上执行: iptables-save | grep {Cluster Ip}

-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.111.72.52/32 -p tcp -m comment --comment "codereview/codereviewapi:codereviewapip cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.111.72.52/32 -p tcp -m comment --comment "codereview/codereviewapi:codereviewapip cluster IP" -m tcp --dport 80 -j KUBE-SVC-HTMIAQY6LYBBMDLQ

以上两条规则表示:

  • 如果 Cluster 内的 Pod(源地址来自10.244.0.0/16)要访问 codereviewapi,则允许。
  • 其他源地址访问要访问 codereviewapi,跳转到规则 KUBE-SVC-HTMIAQY6LYBBMDLQ。

接下来看一下 KUBE-SVC-HTMIAQY6LYBBMDLQ 规则
命令: iptables-save | grep KUBE-SVC-HTMIAQY6LYBBMDLQ

-A KUBE-SVC-HTMIAQY6LYBBMDLQ -m comment --comment "codereview/codereviewapi:codereviewapip" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-SWNXRCMT35EIIJA7
-A KUBE-SVC-HTMIAQY6LYBBMDLQ -m comment --comment "codereview/codereviewapi:codereviewapip" -j KUBE-SEP-6M3F5MB5GS3SEKLX

以上两条规则表示:

  • 1/2的概率跳转到规则 KUBE-SEP-SWNXRCMT35EIIJA7
  • 剩下的1/2的概率跳转到规则 KUBE-SEP-6M3F5MB5GS3SEKLX

我们做个实验,将对应的 Pod 副本增加到 5 个

image.png

再来查看 Service 对应的 iptable 规则

  • iptables-save | grep 10.111.72.52
-A KUBE-SERVICES ! -s 10.244.0.0/16 -d 10.111.72.52/32 -p tcp -m comment --comment "codereview/codereviewapi:codereviewapip cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.111.72.52/32 -p tcp -m comment --comment "codereview/codereviewapi:codereviewapip cluster IP" -m tcp --dport 80 -j KUBE-SVC-HTMIAQY6LYBBMDLQ
  • iptables-save | grep KUBE-SVC-HTMIAQY6LYBBMDLQ
-A KUBE-SVC-HTMIAQY6LYBBMDLQ -m comment --comment "codereview/codereviewapi:codereviewapip" -m statistic --mode random --probability 0.20000000019 -j KUBE-SEP-SWNXRCMT35EIIJA7
-A KUBE-SVC-HTMIAQY6LYBBMDLQ -m comment --comment "codereview/codereviewapi:codereviewapip" -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-KBOJZ2BRSNPOQUXM
-A KUBE-SVC-HTMIAQY6LYBBMDLQ -m comment --comment "codereview/codereviewapi:codereviewapip" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-PNCHQMQ4RHNHGK4S
-A KUBE-SVC-HTMIAQY6LYBBMDLQ -m comment --comment "codereview/codereviewapi:codereviewapip" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-GDQMZT4WINOZF4G6
-A KUBE-SVC-HTMIAQY6LYBBMDLQ -m comment --comment "codereview/codereviewapi:codereviewapip" -j KUBE-SEP-6M3F5MB5GS3SEKLX

可以看到 KUBE-SVC-HTMIAQY6LYBBMDLQ 发生了变化,每一条规则的概率改变了。
结论: iptables 将访问 Service 的流量转发到后端 Pod,而且使用类似轮询的负载均衡策略。

四、Ingress 访问 Service

1、DNS 访问 Service

在 Kubernetes 中,可以通过 Cluster Ip 来找到 Pod 的访问规则,但是 Cluster Ip 不好记啊,所以 Kuberbetes 提供了一个 CoreDns 的组件来对 Service 进行解析。

CoreDns 是一个 DNS 服务器,每当有 Service 创建时,都会在 DNS 服务里面增加一条记录。集群中的 Pod 可以通过 <SERVICE_NAME>.<NAMESPACE_NAME> 访问 Service

通过 nslookup 可以看到 Service 的解析

命令: nslookup codereviewapi

Server:         10.96.0.10
Address:        10.96.0.10:53

Name:   codereviewapi.codereview.svc.cluster.local
Address: 10.111.72.52

2、Ingress 访问 Service

在 Ingress 域名的 yaml 描述文件中,使用 serviceName 和 servicePort 来设置对应的 service 和端口

---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: codereviewapi
  namespace: codereview
spec:
  rules:
    - host: xxx.xxx.xxx.cn
      http:
        paths:
          - backend:
              serviceName: codereviewapi
              servicePort: codereviewapip
            path: /
  tls:
    - hosts:
        - xxx.xxx.xxx.cn
      secretName: tls

其中 host 表示域名信息,serviceName 和 servicePort 设置的是对应的 Service 和端口,tls 表示的是 Https证书选择。

五、总结

通过文章了解了在 Kubernetes 中,可以通过 Cluster Ip 的 Iptables 规则来实现 Pod 的负载请求,也可以通过 DNS 解析 Service 的形式来访问 Pod,对于我们理解 Kubernetes 的工作原理起到了不小的作用。