目录
Service+kube-proxy结合可以实现对目标pod构建为一个服务集群,并通过统一的服务IP地址暴露给用户访问。其中Service可以通过标签选择器对目标pod的抓取,并形成所谓的集群,kube-proxy通过三种工作模式实现对用户访问的路由分发到目标pod上。
一、Service概述
Service可以实现对集群中服务暴露。
上图中,我们有3个Frontend v1的pod,他们是通过名为Frontend的Deployment控制器产生的。对于我们来讲如何对外部用户暴露Frontend v1的服务呢,可以通过Service来实现。简单来说,我们的pod就绪探测成功后,service的标签选择器会进行抓取甄别,符合标签选择器条件的就会被service通抓取到,然后放到负载均衡集群里面,实现我们的负载访问。
外部用户通过外部端点frontend service,负载均衡到多个pod上,怎么负载到pod上的呢,就是通过service标签选择器,满足两个条件:app=webapp, role=frontend的pod会被负载。
二、没有Service存在的问题
如下图,我们有两类app,一类是tomcat,提供前后端服务的,一类是Nginx,提供负载均衡的。
Tomcat有3个副本,假如其中一个副本pod出现异常退出了,deployment会检测到,所以会重新起一个pod副本,新的pod会有新的IP,但是nginx并不知道新的ip可以路由过去做负载,就会导致新的tomcat的pod空转。当然我们也有办法可以来规避这个问题,比如nginx通过域名来访问tomcat,而不是通过ip地址。
三、增加Service层
增加Service之后的情况如下图:
Service插入到两层之间,形成一个中间层。具体的话通过创建一个tomcat的Service,他的选择器匹配app=tomcat。一旦service创建成功,标签选择器就会把探测到app=tomcat的pod抓取放到一个负载均衡的集群里面。
如果deployment-Tomcat 3副本中有一个副本死掉了,service维护的集群中就会将该pod剔除出去,如果新增加了一个pod,且app=tomcat的话,service会抓取该pod进入集群中,这个pod就可以提供负载访问了。
deployment-nginx的话,他只需要在proxy-pass里面设置service的ip即可。只要kubernetes集群不死掉,当前的service对象就会一直存在。 这样外部用户的访问经过nginx,反向代理到service,service会把访问路由负载到刚才抓取形成的负载均衡集群里面。
Service提供的是4层负载均衡服务。
四、Service核心原理
Service的迭代历史
1、userspace运行模式
kube-proxy的主要作用:
1)监听apiServer,将service对象变化(集群负载均衡信息)修改本地的iptables规则;
2)代理来自当前节点pod的用户请求。当流量比较大的时候,proxy的压力会比较大。
2、iptables代理运行模式
kube-proxy的主要作用相比上一代只有第一项功能了:
1)监听apiServer,将service对象变化(集群负载均衡信息)修改本地的iptables规则;
优点:kube-proxy不再承接对server的请求以及代理返回给client的结果了。这样不会因为本机pod数量增多导致proxy的压力增大的情况。
3、ipvs代理运行模式
四层负载均衡里面,ipvs是优于iptables组件的,性能更强的。
为什么我们安装k8s集群之后默认启用的是iptables而不是ipvs呢,因为可能有些机器没有安装ipvs或者内核中没有开启ipvs,所以不能默认采用ipvs,而iptables是基本上都是安装的。
五、修改kube-proxy工作模式为ipvs
1、创建deployment控制器
创建deployment控制器,并扩容到10个pod。
[root@k8s-master01 5]# kubectl create deployment myapp --image=nginx:v1
deployment.apps/myapp created
[root@k8s-master01 5]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-6cc4846d7f-wsjd8 1/1 Running 0 24s
[root@k8s-master01 5]# kubectl scale deployment myapp --replicas=10
deployment.apps/myapp scaled
[root@k8s-master01 5]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-6cc4846d7f-2smpw 1/1 Running 0 4s
myapp-6cc4846d7f-5fwmm 1/1 Running 0 4s
myapp-6cc4846d7f-5vnrs 1/1 Running 0 4s
myapp-6cc4846d7f-7hvn7 1/1 Running 0 4s
myapp-6cc4846d7f-q8p9f 1/1 Running 0 4s
myapp-6cc4846d7f-rc6kg 1/1 Running 0 4s
myapp-6cc4846d7f-wjlh6 1/1 Running 0 4s
myapp-6cc4846d7f-wsjd8 1/1 Running 0 65s
myapp-6cc4846d7f-xvszm 1/1 Running 0 4s
myapp-6cc4846d7f-z7q8b 1/1 Running 0 4s
2、创建service
[root@k8s-master01 5]# kubectl create svc clusterip myapp --tcp=80:80
service/myapp created
[root@k8s-master01 5]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 10d
myapp ClusterIP 10.13.55.128 <none> 80/TCP 3m39s
我们检查下服务是否正常能够访问。
[root@k8s-master01 5]# curl 10.13.55.128
Welcome to Nginx V1.0 !!!
结果:服务访问正常,service对象创建成功。
查看ipvs是否被启用
[root@k8s-master01 5]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
结果:没有启用ipvs,所以系统默认启用的是iptables。接下来我们通过修改kube-proxy的configmap配置文件中mode工作模式的默认值为ipvs。
3、修改kube-proxy模式为ipvs
执行命令:kubectl edit configmap kube-proxy -n kube-system
修改kube-proxy的configmap,修改里面的mode参数。-n表示命名空间。
configmap是专门存储当前配置参数的一种存储方式或存储类型,下一章会讲解到。
注意:-n没有的话,默认是default命名空间。
[root@k8s-master01 5]# kubectl edit configmap kube-proxy -n kube-system
configmap/kube-proxy edited
如下图,左图是未修改前,右图为修改mode=ipvs。
4、重启kube-proxy让修改生效
上面只是修改了mode参数,要让mode参数生效,还需要重启kube-proxy。
[root@k8s-master01 5]# kubectl get pod -n kube-system -l k8s-app=kube-proxy
NAME READY STATUS RESTARTS AGE
kube-proxy-6z8h4 1/1 Running 2 (4d14h ago) 10d
kube-proxy-8rmhn 1/1 Running 2 (4d14h ago) 10d
kube-proxy-dv4bk 1/1 Running 2 (4d14h ago) 10d
将kube-proxy杀死重建:
[root@k8s-master01 5]# kubectl delete pod -n kube-system -l k8s-app=kube-proxy
pod "kube-proxy-6z8h4" deleted
pod "kube-proxy-8rmhn" deleted
pod "kube-proxy-dv4bk" deleted
[root@k8s-master01 5]# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-5fc7d6cf67-8jfs6 1/1 Running 2 (4d14h ago) 10d
calico-node-4xntb 1/1 Running 2 (4d14h ago) 10d
calico-node-m5rm6 1/1 Running 2 (4d14h ago) 10d
calico-node-nwvp6 1/1 Running 2 (4d14h ago) 10d
coredns-857d9ff4c9-7nf6s 1/1 Running 2 (4d14h ago) 10d
coredns-857d9ff4c9-j8rwt 1/1 Running 2 (4d14h ago) 10d
etcd-k8s-master01 1/1 Running 2 (4d14h ago) 10d
kube-apiserver-k8s-master01 1/1 Running 3 (4d22h ago) 10d
kube-controller-manager-k8s-master01 1/1 Running 3 (26h ago) 10d
kube-proxy-bd8q6 1/1 Running 0 23s
kube-proxy-rqcq2 1/1 Running 0 23s
kube-proxy-xm9jf 1/1 Running 0 23s
kube-scheduler-k8s-master01 1/1 Running 3 (26h ago) 10d
从上面结果看,kube-proxy重建并启动起来了。
验证下ipvs是否被kube-proxy启用:
[root@k8s-master01 5]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.0.0.1:443 rr
-> 192.168.21.11:6443 Masq 1 1 0
TCP 10.0.0.10:53 rr
-> 10.244.32.134:53 Masq 1 0 0
-> 10.244.32.136:53 Masq 1 0 0
TCP 10.0.0.10:9153 rr
-> 10.244.32.134:9153 Masq 1 0 0
-> 10.244.32.136:9153 Masq 1 0 0
TCP 10.13.55.128:80 rr
-> 10.244.58.228:80 Masq 1 0 0
-> 10.244.58.230:80 Masq 1 0 0
-> 10.244.58.231:80 Masq 1 0 0
-> 10.244.58.232:80 Masq 1 0 0
-> 10.244.58.237:80 Masq 1 0 0
-> 10.244.85.203:80 Masq 1 0 0
-> 10.244.85.204:80 Masq 1 0 0
-> 10.244.85.205:80 Masq 1 0 0
-> 10.244.85.206:80 Masq 1 0 0
-> 10.244.85.209:80 Masq 1 0 0
UDP 10.0.0.10:53 rr
-> 10.244.32.134:53 Masq 1 0 0
-> 10.244.32.136:53 Masq 1 0 0
我们查看下service服务地址:
[root@k8s-master01 5]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 10d
myapp ClusterIP 10.13.55.128 <none> 80/TCP 24m
[root@k8s-master01 5]# curl 10.13.55.128
Welcome to Nginx V1.0 !!!
从上面标红的红色字体可以看出来,我们的service集群ip地址,在ipvs里面采用rr即round robin轮训算法,将**10.13.55.128:80路由分发到下面的各个pod上。**可以查看各个pod的IP地址是否和ipvs里面列出来的地址一样:
验证是deployment为myapp的10个pod的ip地址。