一、导读
我们将应用程序部署到 K8s 集群中,如果想要访问部署的 Pod,需要通过 Service 来进行访问,想要将应用暴露给集群外访问需要用到 Ingress ,那么这些服务之间是怎么进行协作的呢?
二、请求流程
流程看似很简单,但是里面涉及到的东西不少,下面将流程拆分出来单独梳理。
三、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 就行了
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 个
再来查看 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 的工作原理起到了不小的作用。