大家好,我是博哥爱运维,这节课内容给大家讲解下在K8S上如何来使用service做内部服务pod的流量负载均衡。
Service、pointK8s是运维人员的救星,为什么这么说呢,因为它里面的运行机制能确保你需要运行的服务,一直保持所期望的状态,还是以上面nginx服务举例,我们不能确保其pod运行的node节点什么时候会当掉,同时在pod环节也说过,pod的IP每次重启都会发生改变,所以我们不应该期望K8s的pod是健壮的,而是要按最坏的打算来假设服务pod中的容器会因为代码有bug、所以node节点不稳定等等因素发生故障而挂掉,这时候如果我们用的Deployment,那么它的controller会通过动态创建新pod到可用的node上,同时删除旧的pod来保证应用整体的健壮性;并且流量入口这块用一个能固定IP的service来充当抽象的内部负载均衡器,提供pod的访问,所以这里等于就是K8s成为了一个7x24小时在线处理服务pod故障的运维机器人。
同时也可以用生成yaml配置的形式来创建kubectlexposedeploymentnginx--port=80--target-port=80--dry-run=client-oyamlkubectlexposedeploymentnginx--port=80--target-port=80service/nginxexposed看下自动关联生成的point接下来测试下svc的负载均衡效果吧,这里我们先进到pod里面,把nginx的页面信息改为各自pod的hostnameechonginx-f89759699-bzwd2/usr/share/nginx/html/@nginx-f89759699-bzwd2:/kubectlexec-itnginx-f89759699-qlc8q--bashroot@nginx-f89759699-qlc8q:/'{"spec":{"type":"NodePort"}}'service/:20651nginx-f89759699-bzwd2[root@node-2~]v1是Service的apiVersionkind:ServiceService的名字为nginxspec:ports:-port:80selector指明挑选那些label为run:nginx的Pod作为Service的后端status:loadBalancer:{}我们来看下这个nginx的svc描述
首先看下kube-proxy的配置-------我们在最开始部署kube-proxy的时候就设定它的转发模式为ipvs,因为默认的iptables在存在大量svc的情况下性能很低Restart=alwaysRestartSec=5LimitNOFILE=65536ipaddr1:lo:LOOPBACK,UP,LOWER_UPmtu65536qdiscnoqueuestateUNKNOWNgroupdefaultqlen1000link/loopback00:00:00:00:00:00brd00:00:00:00:00:00/8scopehostlovalid_lftforeverpreferred_lftforeverinet6::1/128scopehostvalid_lftforeverpreferred_lftforever2:ens32:BROADCAST,MULTICAST,UP,LOWER_UPmtu1500qdiscpfifo_faststateUPgroupdefaultqlen1000link/ether00:0c:29:20:b8:39brdfe:fe:fe:fe:fe:/24_lftforeverpreferred_lftforeverinet6fe80::20c:29fe:fe20:b839/64scopelinkvalid_lftforeverpreferred_lftforever3:docker0:NO-CARRIER,BROADCAST,MULTICAST,UPmtu1500qdiscnoqueuestateDOWNgroupdefaultlink/ether02:42:91:ac:ce:13brdfe:fe:fe:fe:fe:/16_lftforeverpreferred_lftforever4:dummy0:BROADCAST,NOARPmtu1500qdiscnoopstateDOWNgroupdefaultqlen1000link/ether22:50:98:a6:f9:e4brdfe:fe:fe:fe:fe:ff5:kube-ipvs0:BROADCAST,NOARPmtu1500qdiscnoopstateDOWNgroupdefaultlink/ether96:6b:f0:25:1a:26brdfe:fe:fe:fe:fe:/32_lftforeverpreferred_/32_lftforeverpreferred_/32_lftforeverpreferred_/32_lftforeverpreferred_/32来看下lvs的虚拟服务器列表-----------SVC转发Pod的明细在这里-172.20.139.72:80:80:443:4443:80:80:80:443:443:443:10254:10254:10254:20651:80:80:53:53Masq100
除了直接用clusterip,以及上面说到的NodePort模式来访问Service,我们还可以用K8s的DNS来访问
kubectl-nkube-systemgetdeployment,pod|/coredns1/1115d2hpod/coredns-d9b6857b5-tt7j21/1Running127hkubectlrun-it--rmbusybox--image=(10.68.18.121):56:seq=0ttl=64time=0.096:seq=1ttl=64time=0.067:seq=2ttl=64time=0.065ms^,3packetsreceived,0%packetlossround-tripmin/avg/max=0.065/0.076/0.096ms/
service生产小技巧通过svc来访问非K8s上的服务
上面我们提到了创建service后,会自动创建对应的point,这里面的关键在于selector:app:nginx基于lables标签选择了一组存在这个标签的pod,然而在我们创建svc时,如果没有定义这个selector,那么系统是不会自动创建point的,我们可不可以手动来创建这个point呢?答案是可以的,在生产中,我们可以通过创建不带selector的Service,然后创建同样名称的point,来关联K8s集群以外的服务,这个具体能带给我们运维人员什么好处呢,就是我们可以直接复用K8s上的ingress(这个后面会讲到,现在我们就当它是一个nginx代理),来访问K8s集群以外的服务,省去了自己搭建前面Nginx代理服务器的麻烦
开始实践测试
这里我们挑选node-2节点,用python运行一个简易web服务器
[root@node-2mnt]注意我这里把两个资源的yaml写在一个文件内,在实际生产中,我们经常会这么做,方便对一个服务的所有资源进行统一管理,不同资源之间用"---"来分隔apiVersion:v1kind:Servicemetadata:name:mysvcnamespace:defaultspec:type:ClusterIPports:-port:80protocol:TCP---apiVersion:v1kind:pointsmetadata:name:mysvcnamespace:defaultsubsets:-addresses:-ip:10.0.1.202nodeName:10.0.1.202ports:-port:9999protocol:TCP
开始创建并测试
kubectlgetsvc,points|grepmysvcservice//TCP14spoints/:999914s我们回到node-2节点上,可以看到有一条刚才的访问日志打印出来了10.0.1.201--[25/Nov/202014:42:45]"GET/HTTP/1.1"200-
外部网络如何访问到Service呢?
在上面其实已经给大家演示过了将Service的类型改为NodePort,然后就可以用node节点的IP加端口就能访问到Service了,我们这里来详细分析下原理,以便加深印象
kubectlgetsvcnginx-oyamlapiVersion:v1kind:Servicemetadata:creationTimestamp:"2020-11-25T03:55:05Z"labels:app:nginxmanagedFields:我们看下这里,它定义的一个nodePort配置,并分配了20651端口,因为我们先前创建时并没有指定这个配置,所以它是随机生成的port:80protocol:TCPtargetPort:80selector:app:nginxsessionAffinity:Nonetype:NodePortstatus:loadBalancer:{}cat/etc/systemd/system/[Unit]Description=KubernetesAPIServerDocumentation=[Service]ExecStart=/opt/kube/bin/kube-apiserver\--advertise-address=10.0.1.201\--allow-privileged=true\--anonymous-auth=false\--authorization-mode=Node,RBAC\--token-auth-file=/etc/kubernetes/ssl/\--bind-address=10.0.1.201\--client-ca-file=/etc/kubernetes/ssl/\--point-reconciler-type=lease\--etcd-cafile=/etc/kubernetes/ssl/\--etcd-certfile=/etc/kubernetes/ssl/\--etcd-keyfile=/etc/kubernetes/ssl/\--etcd-servers=\--kubelet-certificate-authority=/etc/kubernetes/ssl/\--kubelet-client-certificate=/etc/kubernetes/ssl/\--kubelet-client-key=/etc/kubernetes/ssl/\--kubelet-https=true\--service-account-key-file=/etc/kubernetes/ssl/\--service-cluster-ip-range=10.68.0.0/16\--service-node-port-range=20000-40000\NodePort端口会在所在K8s的node节点上都生成一个同样的端口,这就使我们无论所以哪个node的ip接端口都能方便的访问到Service了,但在实际生产中,这个NodePort不建议经常使用,因为它会造成node上端口管理混乱,等用到了ingress后,你就不会想使用NodePort模式了,这个接下来会讲到[root@node-1~]这里-172.20.139.72:80:80Masq100[root@node-2mnt]这里-172.20.139.72:80:80Masq100生产中Service的调优