第8章:深入理解Service
-
防止Pod失联(服务发现)
-
定义一组Pod的访问策略(负载均衡)
8.2 为什么要使用Service
Kubernetes Pod`是平凡的,由`Deployment`等控制器管理的`Pod`对象都是有生命周期的,它们会被创建,也会意外挂掉。虽然它们可以由控制器自动重建或者滚动更新,但是重建或更新之后的`Pod`对象的IP地址等都会发生新的变化。这样就会导致一个问题,如果一组`Pod`(称为`backend`)为其它`Pod`(称为 `frontend`)提供服务,那么那些`frontend`该如何发现,并连接到这组`Pod`中的哪些`backend`呢? 这时候就用到了:`Service
示例说明为什么要使用Service
如下图所示,当Nginx Pod
作为客户端访问Tomcat Pod
中的应用时,IP
的变动或应用规模的缩减会导致客户端访问错误。而Pod
规模的扩容又会使得客户端无法有效的使用新增的Pod
对象,从而影响达成规模扩展之目的。为此,Kubernetes
特地设计了Service
资源来解决此类问题。
8.3 Service实现原理
Service
资源基于标签选择器将一组Pod
定义成一个逻辑组合,并通过自己的IP
地址和端口调度代理请求至组内的Pod
对象之上,如下图所示,它向客户端隐藏了真实的、处理用户请求的Pod
资源,使得客户端的请求看上去就像是由Service
直接处理并响应一样。
Service
对象的IP
地址也称为Cluster IP
,它位于Kubernetes
集群配置指定专用IP
地址的范围之内,是一种虚拟IP
地址,它在Service
对象创建后既保持不变,并且能够被同一集群中的Pod
资源所访问。Service
端口用于接收客户端请求并将其转发至其后端的Pod
中的相应端口之上,因此,这种代理机构也称为“端口代理”(port proxy
)或四层代理,工作于TCP/IP
协议栈的传输层。
Service
资源会通过API Server
持续监视着(watch
)标签选择器匹配到的后端Pod
对象,并实时跟踪各对象的变动,例如,IP
地址变动、对象增加或减少等。Service
并不直接链接至Pod
对象,它们之间还有一个中间层——Endpoints
资源对象,它是一个由IP
地址和端口组成的列表,这些IP
地址和端口则来自由Service
的标签选择器匹配到的Pod
资源。当创建service
对象时,其关联的Endpoints
对象会自动创建。
8.4 虚拟IP和服务代理
一个
Service
对象就是工作节点上的一些iptables
或ipvs
规则,用于将到达Service
对象IP
地址的流量调度转发至相应的Endpoints
对象指定的IP
地址和端口之上。kube-proxy
组件通过API Server
持续监控着各Service
及其关联的Pod
对象,并将其创建或变动实时反映到当前工作节点上的iptables
规则或ipvs
规则上。
ipvs
是借助于Netfilter
实现的网络请求报文调度框架,支持rr
、wrr
、lc
、wlc
、sh
、sed
和nq
等十余种调度算法,用户空间的命令行工具是ipvsadm
,用于管理工作与ipvs
之上的调度规则。
Service IP
事实上是用于生成iptables
或ipvs
规则时使用的IP
地址,仅用于实现Kubernetes
集群网络的内部通信,并且能够将规则中定义的转发服务的请求作为目标地址予以相应,这也是将其称为虚拟IP
的原因之一。
kube-proxy
将请求代理至相应端点的方式有三种:userspace(用户空间)、iptables和ipvs。因userspace传输效率太低,不推荐使用,在1.1版本之前是默认转发策略,现在默认是iptables。
8.5 iptables代理模式
iptables
代理模式中,kube-proxy
负责跟踪API Server
上Service
和Endpoints
对象的变动(创建或移除),并据此作出Service
资源定义的变动。同时,对于每个Service
对象,它都会创建iptables
规则直接捕获到达Cluster IP
(虚拟IP)和Port
的流量,并将其重定向至当前Service
的后端。对于每个Endpoints
对象,Service
资源会为其创建iptables
规则并关联至挑选的后端Pod
资源,默认的调度算法是随机调度(random
)。实现基于客户端IP
的会话亲和性(来自同一个用户的请求始终调度到后端固定的一个Pod
),可将service.spec.sessionAffinity
的值设置为“ClientIP”
(默认值为“None”
)。
其代理过程是:请求到达service
后,其请求被相关service
上的iptables
规则进行调度和目标地址转换(DNAT
)后再转发至集群内的Pod
对象之上。
Iptables:
-
灵活,功能强大
-
规则遍历匹配和更新,呈线性时延
8.6 ipvs代理模式
kube-proxy
跟踪API Server
上Service
的Endpoints
对象的变动,据此来调用netlink
接口创建ipvs
规则,并确保与API Server
中的变动保持同步,其请求流量的调度功能由ipvs
实现,其余的功能由iptables
实现。ipvs
支持众多调度算法,如rr
、lc
、dh
、sh
、sed
和nq
等。
IPVS:
-
工作在内核态,有更好的性能
-
调度算法丰富:rr,wrr,lc,wlc,ip hash...
8.7 Pod与Service的关系
-
通过label-selector相关联
-
通过Service实现Pod的负载均衡( TCP/UDP 4层)
8.8 Service三种类型
Service
的IP
地址只能够在集群内部可访问,对一些应用(如frontend
)的某些部分,可能希望通过外部(kubernetes
集群外部)IP
地址暴露Service
,这时候就需要使用到NodePort
。kubernetes ServiceTypes
支持四种类型:ClusterIP
、NodePort
、LoadBalancer
、其默认是Cluster IP
类型。
ClusterIP:默认策略,分配一个稳定的IP地址,即VIP,只能在集群内部访问(同Namespace内的Pod)。
pod ---> ClusterIP:ServicePort --> (iptables、ipvs)DNAT --> PodIP:containePort
NodePort:在每个节点上启用一个端口来暴露服务,可以在集群外部访问。也会分配一个稳定内部集群IP地址。
访问地址:<NodeIP>:<NodePort>
clietn --> <NodeIp>:<NodePort> --> (iptables、ipvs)DNAT --> <PodIP>:<ContainerPort>
。
LoadBalancer:与NodePort类似,在每个节点上启用一个端口来暴露服务。除此之外,Kubernetes会请求底层云平台上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去。
8.9 将service代理模式改为IPVS
1 验证所有node节点是否启用了ipvs
# lsmod | grep ip_vs
ip_vs_sh 12688 0
ip_vs_wrr 12697 0
ip_vs_rr 12600 0
ip_vs 141432 6 ip_vs_rr,ip_vs_sh,ip_vs_wrr
nf_conntrack 133053 7 ip_vs,nf_nat,nf_nat_ipv4,xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_netlink,nf_conntrack_ipv4
libcrc32c 12644 4 xfs,ip_vs,nf_nat,nf_conntrack
2 修改kube-proxy配置文件
[root@k8s-admin ~]# kubectl edit configmap kube-proxy -n kube-system
mode: "ipvs"
3 重建kube-proxy
[root@k8s-admin ~]# kubectl get pod -n kube-system -o wide
[root@k8s-admin ~]# kubectl delete pod kube-proxy-2n5j5 -n kube-system
[root@k8s-admin ~]# kubectl delete pod kube-proxy-mwgw2 -n kube-system
[root@k8s-admin ~]# kubectl delete pod kube-proxy-nq9jb -n kube-system
[root@k8s-admin ~]# kubectl get pod -n kube-system -o wide
4 验证
在k8s-node1,k8s-node2节点上进行验证
# grep ipvs /var/log/messages
# yum install ipvsadm -y
[root@k8s-admin ~]# kubectl get deploy,pod,svc,ep -o wide
# 访问nginx
http://172.16.1.71:31522/
http://172.16.1.72:31522/
[root@k8s-node1 ~]# ipvsadm -L -n # 会出现很多的ipvs规则,kube-proxy把pod的路由规则绑定到ip上
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
......
TCP 172.16.1.71:31522 rr
-> 10.244.2.6:80 Masq 1 2 0
TCP 10.96.116.184:80 rr
-> 10.244.2.6:80 Masq 1 0 0
......
[root@k8s-node2 ~]# ipvsadm -L -n # 会出现很多的ipvs规则,kube-proxy把pod的路由规则绑定到ip上
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
......
TCP 172.16.1.72:31522 rr
-> 10.244.2.6:80 Masq 1 2 0
TCP 10.96.116.184:80 rr
-> 10.244.2.6:80 Masq 1 0 0
......
8.10 Service DNS名称
DNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析。
ClusterIP A记录格式:<service-name>.<namespace-name>.svc.cluster.local
示例:my-svc.my-namespace.svc.cluster.local
# cat busybox.yaml# kubectl apply -f busybox.yamlapiVersion: v1 kind: Pod metadata: labels: run: busybox name: busybox namespace: default spec: containers: - image: busybox:1.28.4 name: bs command: - "ping" - "baidu.com"
# kubectl get pod
NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 1 7m7s
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 9d
nginx NodePort 10.96.116.184 <none> 80:31522/TCP 9d
# kubectl exec -it busybox sh
/ # nslookup kubernetes
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes
Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local
/ # nslookup nginx
Server: 10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
Name: nginx
Address 1: 10.96.116.184 nginx.default.svc.cluster.local
/ #
8.11 小结
-
采用NodePort对外暴露应用,前面加一个LB实现统一访问入口
-
优先使用IPVS代理模式
-
集群内应用采用DNS名称访问
-
service只支持四层负载均衡 四层:OSI中的传输层,TCP/UDP,四元组,只负责IP数据包转发。 七层:OSI中的应用层,HTTP、FTP、SNMP协议,可以拿到这些协议头部信息,那就可以实现基于协议层面的处理。
-
NodePort访问流程 user -> 域名(公网IP)-> node ip:port -> iptables/ipvs -> pod
一般生产环境 node 都是部署在内网,那30008这个端口怎么让互联网用户访问呢 (1) 找一台有公网IP的服务器,装一个nginx,反向代理 -> node ip:port (2) 只用你们外部负载均衡器 (Nginx、LVS、HAProxy) -> node ip:port
-
LoadBalancer 访问流程 user -> 域名(公网IP) -> 公有云上的负载均衡器(自动配置,控制器去完成) -> node ip:port
-
kube-proxy工作 (1) 实现pod数据包转发 (2) 将service相关路由规则落地实现