Kubernetes资源管理之Service
1、概述
Kubernetes Service是对一组提供相同功能的Pod提供统一入口的抽象,借助Service,应用可以方便的实现服务发现与负载均衡,并实现应用的无缝升级。
2、原理
Service通过标签Label来选取后端服务,一般配合ReplicaSet或Deployment来保证后端容器的正常运行,这些匹配Label的Pod IP和端口列表组成endpoints,由kube-proxy负责将服务IP负载均衡到这些endpoint上。
3、工作模式
Service有三种工作方式,分别是userspace、iptables、ipvs
3.1、UserSpace

如上图,client Pod要访问Server Pod时,先将请求发给本机内核空间中的service规则,由它将请求转发给监听在用户空间指定套接字上的kube-proxy,kube-proxy处理并分发请求到内核空间Service IP,由Service转发请求到Server Pod。
此方式需要频繁在用户空间和内核空间交互通信,效率很低。故在k8s 1.1以后均不在使用此模式
3.2、iptables

此方式在client Pod发起请求后,由内核空间中的Service iptables规则接收,并直接调度给Server Pod
3.3、ipvs

ipvs方式直接由内核中的ipvs规则来接收Client Pod请求,并处理该请求,由内核封包后,直接转发给Server Pod。要使用这种方式,必须要在系统中激活ipvs模块,若ipvs没有被激活,则会降级使用iptables模式。
注:以上无论哪一种方式,kube-proxy都通过list-watch方式监控着kube-ApiServer写入etcd中关于Pod的最新状态信息,一旦检测到一个Pod资源有了更新,则立即将这些变化反应在iptables或ipvs规则中,以便iptables或ipvs在调度client pod请求到server pod时,不会出现pod不存在的情况。
4、Service四种类型
Service有四种类型,分别是ClusterIP、NodePort、LoadBalancer、ExternalName
4.1、ClusterIP
默认类型,用于集群内Pod访问时,提供固定的访问地址,默认是自动分配地址。
4.2、NodePort
基于ClusterIP,用于为集群外部访问Service后面Pod提供访问的入口,工作流程为:
- Client ——>NodeIP:NodePort——>ClusterIP:ServicePort——>PodIP:ContainerPort(targetPort)
4.3、LoadBalancer
用于当K8s运行在云环境中,若该云环境支持LBaaS,则此类型可自动触发创建一个软件负载均衡用于对Service做负载均衡调度。
4.4、ExternalName
用于将集群外部的服务引入到集群内部,在集群内部可直接访问来获取服务。通过DNS Cname记录方式转发到指定的域名,需要kube-dns版本在1.7以上。
5、iptable/ipvs下Service规则解析
5.1、创建Service示例
# 创建deploymentapiVersion: apps/v1kind: Deploymentmetadata:labels:app: webdepoymentname: webdepoymentspec:replicas: 3selector:matchLabels:app: webdepoymentstrategy: {}template:metadata:labels:app: webdepoymentspec:containers:- image: nginxname: nginxresources: {}---# 创建serviceapiVersion: v1kind: Servicemetadata:name: web-servicenamespace: defaultspec:selector: # 指定标签选择器选择的标签范围app: webdepoymenttype: NodePortports:- name: httpport: 80 # 设定Service提供服务的端口targetPort: 80 # 设定容器Pod的端口nodePort: 30080 # 仅在type为NodePort时才需要指定,如不指定默认会自动分配
Service在对外提供服务时,还支持会话保持,字段为sessionAffinity,支持ClientIP和None两种方式。
- None:不做会话保持,进行随机调度
- ClientIP:根据客户端IP来调度,同一个客户端IP都调度到同一个Server Pod
可以在配置清单中配置或者通过补丁方式来增加配置:
$ kubectl patch svc myapp-service -p '{"spec":{"sessionAffinity":"ClientIP"}}'
$ kubectl describe svc myapp-service #可以查看到多了一个Session Affinity的字段.
- 查看service和pod信息
[root@k8s-master resource]# kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/webdepoyment-78cff8f5f7-2jc52 1/1 Running 0 53m
pod/webdepoyment-78cff8f5f7-2xhgc 1/1 Running 0 53m
pod/webdepoyment-78cff8f5f7-cdt8l 1/1 Running 0 53m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 3h4m
service/web-service NodePort 10.105.144.52 <none> 80:30080/TCP 53m
5.2、iptable下Service路由规则
可以通过iptables-save |grep [ServiceName|链名]来查看
- 第一步:所有访问10.105.144.52的tcp 80端口的请求都转发到KUBE-SVC-LHVVVX6K6XR7TB6A链
-A KUBE-SERVICES -d 10.105.144.52/32 -p tcp -m comment --comment "default/web-service:http cluster IP" -m tcp --dport 80 -j KUBE-SVC-LHVVVX6K6XR7TB6A
- 第二步:对经过KUBE-SVC-LHVVVX6K6XR7TB6A链的流量进行权重设置,并转发到对应链处理。
逐条匹配,匹配到第一条的几率为33.3%,如果未匹配第二条几率为50%,最后一条几率为100%。
-A KUBE-SVC-LHVVVX6K6XR7TB6A -m comment --comment "default/web-service:http" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-EF2MT6LT2XA6QOB5
-A KUBE-SVC-LHVVVX6K6XR7TB6A -m comment --comment "default/web-service:http" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-TSO6USMBI4DALFPR
-A KUBE-SVC-LHVVVX6K6XR7TB6A -m comment --comment "default/web-service:http" -j KUBE-SEP-5VVM6DLIDKSFKFVS
- 第三步:最终将流量分发到对应的容器进行DNAT转发处理。
-A KUBE-SEP-EF2MT6LT2XA6QOB5 -p tcp -m comment --comment "default/web-service:http" -m tcp -j DNAT --to-destination 10.244.0.70:80
-A KUBE-SEP-TSO6USMBI4DALFPR -p tcp -m comment --comment "default/web-service:http" -m tcp -j DNAT --to-destination 10.244.92.7:80
-A KUBE-SEP-5VVM6DLIDKSFKFVS -p tcp -m comment --comment "default/web-service:http" -m tcp -j DNAT --to-destination 10.244.92.8:80
5.3、ipvs下Service路由规则
默认kube-proxy使用iptables规则,如果要切换成ipvs,需要满足以下条件:
- 修改kube-proxy工作模式为ipvs。
- 节点需安装ipvsadm组件。
5.3.1、切换节点为ipvs工作模式
kubectl edit configmap kube-proxy -n kube-system
# 修改mode字段为ipvs
yum -y install ipvsadm
# 安装ipvsadm组件
kubectl delete pod kube-proxy-gm2b2 -n kube-system
# 选择一个节点上的kube-proxy删除,重建此kube-proxy
5.3.2、查看ipvs规则
$ ipvsadm -L -n
TCP 10.211.55.102:30080 rr
-> 10.244.0.70:80 Masq 1 0 0
-> 10.244.92.7:80 Masq 1 0 0
-> 10.244.92.8:80 Masq 1 0 0
默认ipvs使用rr调度方式将请求调度到后端real-server。
5.3.3、修改ipvs调度算法
kubectl edit configmap kube-proxy -n kube-system
# 修改字段scheduler为指定算法
5.4、ipvs和iptables对比
iptables
- 灵活、功能强大
- 规则遍历匹配和更新,呈线性时延。
ipvs
- 工作在内核态,有更好的性能。
- 调度算法丰富:rr、wrr、lc、wlc、ip hash等
6、HeadLess Service(无头服务)
所谓headless service是指,没有ClusterIP的Service,它仅有一个service name,这个服务名解析得到的不再是Service的集群IP,而是Pod的IP,当客户端访问该Service时,将直接获得Pod的IP,进行访问
apiVersion: v1
kind: Service
metadata:
name: myapp-service-headless
namespace: default
spec:
selector:
app: myapp
release: canary
clusterIP: None # headless service的clusterip指定为None
ports:
- name: http
port: 80
targetPort: 80
创建完成后,可以通过dig来查看service解析的地址
$ dig -t A myapp-service-headless.default.svc.cluster.local. @10.96.0.10
;; ANSWER SECTION:
myapp-service-headless.default.svc.cluster.local. 30 IN A 10.244.1.64
myapp-service-headless.default.svc.cluster.local. 30 IN A 10.244.1.62
myapp-service-headless.default.svc.cluster.local. 30 IN A 10.244.1.66
myapp-service-headless.default.svc.cluster.local. 30 IN A 10.244.1.63
myapp-service-headless.default.svc.cluster.local. 30 IN A 10.244.1.65
