【k8s系列十二】k8s 之 Service的类型

svc的类型

  • ClusterIp:默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP
  • NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过 : NodePort 来访问该服务
  • LoadBalancer:在 NodePort 的基础上,借助 cloud provider 创建一个外部负载均衡器,并将请求转发到: NodePort
  • ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 kubernetes 1.7 或更高版本的 kube-dns 才支持

1. ClusterIP

ClusterIP 主要是在集群内部访问使用.

【k8s系列十二】k8s 之 Service的类型_第1张图片

在没有service的时候, 我们有一个nginx做负载均衡, 还有12个应用服务器, 这12个应用服务器是有控制器管理的. 当一个请求请求到nginx的时候, nginx要想正确请求的应用服务器, 就要维护一份应用服务器的ip地址. 在容器时代, 死亡一个pod或者新增一个pod都是常事, 而如果nginx要维护pod的服务列表, 那就要频繁的修改服务列表, 这样很不方便. 因此, 我们引入了service.

【k8s系列十二】k8s 之 Service的类型_第2张图片

从上图中可以看出, service通过标签和pod进行匹配, nginx请求的时候, 不用直接去请求pod, 而是请求service, service在去请求pod. 这样就算pod增加了或者减少了, 通过标签都会自动匹配. 而我们需要给service一个固定的ip, 这个固定的ip就是ClusterIP方式了.

这就是ClusterIP的作用了, 在集群内部, 给集群一个负载均衡的方案

那有些服务是内部的, 有些服务是外部的, 如果是内部的就可以基于ClusterIP的方式, 如果是外部的就要基于第二种方式了.

2.NodePort

有些服务是要提供给集群外部去访问的, 这种情况就要用NodePort了.

上面的模式是nginx去请求tomcat, 那谁请求nginx呢? 肯定是外部服务或者浏览器请求nginx, 这个时候就是外部请求集群了, 使用clusterIP方式不行了, 要使用NodePort的方式.

【k8s系列十二】k8s 之 Service的类型_第3张图片

如上图所示,当外部服务, 或者外部用户,或者其他网络需要访问集群的时候,应该怎么办呢?总不能让人家ssh登录到集群内部访问吧. 这时候可以使用nodePort类型的svc。nginx是集群内部的pod, 我们在集群中创建一个svc, 类型是nodePort类型, svc同样会通过标签匹配到pod. 这个svc会绑定到当前的物理网卡, 比如ENS 33 的网卡, 他会把当前物理网卡的地址以及端口映射称成自己的调度器地址, 或者vip地址. 比如 物理网卡上提供了一个端口30009, 为什么要30009呢?因为要大于30000以上. 那么,这时只要客户端访问30009端口, 就可以基于svc-nginx调度器负载到nginx, nginx接收到请求以后, 在反向代理到svc-tomcat调度器, svc-tomcat再将请求分配给tomcat-pod

所以, 如果是集群内部组件相互访问, 我们通过clusterIP将其关联起来. 如果是集群外部想访问集群内部, 我们就通过nodePort将端口暴露出去.

【k8s系列十二】k8s 之 Service的类型_第4张图片

但这样是不是就可以了呢? 显然不是, 让用户访问30009端口, 这基本不可能, 用户请求的一般都是80端口或者334端口. 那怎么办呢? 有路由器啊, 我们可以吧路由器的dail net 端口映射到30009端口. 还有一种方案, 负载均衡, 我们来看看负载均衡的方案.

【k8s系列十二】k8s 之 Service的类型_第5张图片

假设现在集群中有两个节点node1和node2, deployment控制器在两个节点上创建了8个tomcat, 然后创建了一个svc, 专门用来管理tomcat. 在node1节点上有一个nginx的pod, 为了能够和外部进行通讯, 我们还创建了一个nodePort类型的svc, 重点来了, 当我们创建了这个svc以后, 它会绑定到物理机的网卡上, 他不仅是绑定到node1物理机的网卡, 同时他还会绑定到node2物理机的网卡.物理网卡的地址以及端口映射成自己的调度器地址. 比如我们还是创建了30009端口, 不仅在node1节点上会映射一个30009端口, 而且在node2节点上也会映射一个30009端口. 当外部访问node1的30009端口是, 可以反向代理到node1节点的svc-nginx调度器, 进而负载到nginx. 当外部访问node2的30009端口时, 一样可以反向代理到node1节点的svc-nginx调度器. 进而负载到nginx上.

在外面还有负载均衡slb, 这是一个高可用的slb, 有多台. 然后将slb的80端口或者443端口映射到node1或者node2的30009端口, 这样用户在访问80端口或者443端口的时候, 就可以请求到svc-nginx调度器了.

这种情况就完美的解决了80端口和443端口了.

3.loadBalance

可是, 这种方案如果在实体机搭建, 肯定没问题. 但如果在阿里云/百度云/腾讯云上搭建, 那就不行了, 为什么呢? 因为如果你买了一台centos服务器, 想要搭ipvs集群, 他不让你搭.原因是他们把云主机内核的ipvs模块给移除了, 为什么移除了呢?因为耽误他们赚钱. 阿里云/百度云/腾讯云/AWS都有一种服务, 叫LAAS服务, 也就是负载均衡器服务. 他们希望你去购买负载均衡器服务实现负载均衡, 而不是自己买一个非常便宜的云主机,在centos上搭建一个负载均衡.

于是, 我们自己搭建的SLB负载均衡的部分, 就没法实现了, 需要使用云厂商的LAAS服务才行, 如下图深红色模块. LAAS是通过在云供应商购买界面鼠标点击购买创建的, 挺费劲的. 那我们是不是希望, 如果我创建了一个NodePort类型的svc, 那么肯定需要创建负载均衡lvs, 他就自己帮我在nodePord当前的端口通过LAAS暴露出去. 也就是灰色框出的部分,变成自动化的了. 这就是第三类loadBalance. 基于云供应商提供的负载均衡的方式.

【k8s系列十二】k8s 之 Service的类型_第6张图片

这种基于云供应商的模式是单独收费的, 那么他有什么优点呢? 基于云供应商提供的LAAS底层是ipvs或者F5, 所以可以用较低的价格获得更高的扩展性. 但如果用不上f5的话,相对来说价格是比较贵的. 毕竟如果用不到F5, 我卖一台普通的服务器就搞定了. 普通服务器相对应LAAS来说价格是便宜很多的.

第三种使用常用

  • 公有云环境, 私有云是不可以的, 纯物理环境也不行.

4. ExternalName

【k8s系列十二】k8s 之 Service的类型_第7张图片

什么场景会使用 ExternalName 呢? 如上图, 我们来分析一下. 现在集群中有n个节点, 主要有两种类型的pod, 一种是tomcat, 假设有100个tomcat节点, 另一个是mysql, mysql的pod就有1个. 那么web应用想要访问mysql, 会怎么做呢? 在每一个web服务器的配置文件中直接配置mysql所在的ip地址. 假设值192.168.17.11. 现在有100个web服务, 就要配置100次. 我们都知道pod每次创建ip都会变, 如果mysql的pod死了然后重建了, 这时候ip地址就会发生变化, 那么我们就要去挨个修改100个web服务器中的mysql地址, 这要崩溃呀. 于是,就有了第四种svc类型--ExternalName. 将mysql的地址剥离开来, 不要直接写在没有web服务器里面, 怎么做呢?

【k8s系列十二】k8s 之 Service的类型_第8张图片

ExternalName类型的svc会借助一个组件CoreDNS, 这是一个DNS服务器. 既然是DNS服务器就可以实现解析, 或者叫别名. 比如: 我们想要访问www.baidu.com, 通过dns解析的时候会解析baidu.sousuo.com. 把我想解析的域名替换去解析另一个.

在之前, 我们web服务器想访问mysql的时候, 需要把ip地址写到web服务器的配置里面, 现在不需要了. 我们创建一个svc, 类型是ExternalName类型. tomcat只需要将地址解析成svc的访问地址. 这里需要注意的是, ExternalName是没有调度器的, 这是4中类型中最特殊的一种.它的创建不会新建ipvs规则, 只会新建一个dns解析规则. dns怎么解析呢? 假设这个svc的名字叫做tomcatSvc, 我们要想访问外部的mysql, 还需要在svc中配置mysql的地址192.168.17.11, 那么在每一个web服务器配置里只需要写上tomcatSvc.default.svc.clusterlocal就可以访问到mysql了. 解析一下:

  • tomcatSvc是svc的名称
  • default: 是svc所在的名称空间
  • svc: 这是一个固定值
  • clusterLocal: 是我们在初始化集群时指定的域名.

所以, 只要svc的名字不变, 这个调用规则就不会变. 然后CoreDNS服务器会将svc中指定的ip解析到对应的地址上. 假设后面mysql的地址变成192.168.17.15了, 那我们只需要修改svc里面的地址, 改一次就可以了.

将外部的地址抽象成集群内部的域名被访问, 相对固定化. 这就是ExternalName类型的svc

总结

svc有4中方式, 什么时候使用什么方式呢? 看下面的图:

【k8s系列十二】k8s 之 Service的类型_第9张图片

当一个需求来了, 要判断倒是是那种场景

  • 是内部请求还是外部请求? 如果是内部请求, 例如nginx想要请求tomcat, 使用clusterIP
  • 如果是外部请求, 需要判断是谁访问谁? 是我想访问外部的mysql么? 如果是, 我就要考虑是否要相对静态的ip给到内部, 如果需要使用ExternalName
  • 如果是外部请求我, 那么还有区分是公有云还是私有云. 如果是公有云, 比如阿里云/百度云/华为云, 他们都是公有云, 需要使用loadBalance方式
  • 如果是私有云或者物理主机, 使用loadPort方式.

你可能感兴趣的:(kubernetes,运维,docker)