一、前言
在 Kubernetes
集群中,网络是非常重要的基础设施。对于大规模的节点和容器来说,要保证网络的连通性、网络转发的高效,同时能做 IP 和 Port 自动化分配和管理,并提供给用户非常直观和简单的方式来访问需要的应用,这是非常复杂且细致的设计。
Kubernetes
本身在这方面下了很大的功夫,它通过 CNI
、Service
、DNS
、Ingress
等一系列概念,解决了服务发现、负载均衡的问题,也大大简化了用户的使用和配置。其中的 Service 是 Kubernetes 微服务的基础,Kubernetes 是通过 kube-proxy
这个组件来实现服务的。kube-proxy 运行在每个节点上,监听 API Server
中服务对象的变化,通过管理 iptables 来实现网络的转发。用户可以创建多种形式的 Service,比如基于 Label Selector
、Headless
或者ExternalName
的 Service,kube-proxy 会为 Service 创建一个虚拟的 IP(即 Cluster IP),用于集群内部访问服务。
二、k8s集群中三种IP
2.1 三种IP概述
- NodeIP:Node 节点的 IP 地址,即物理机(虚拟机)的 IP 地址。
- PodIP:Pod 的 IP 地址,即 docker 容器的 IP 地址,也是虚拟 IP 地址。
- ClusterIP:k8s 虚拟的 Service 的 IP 地址,也是虚拟 IP 地址。
2.2 三种IP的理解
- Node IP:是物理机的IP(或虚拟机IP),代表的是物理节点或者虚拟节点的网络。每个Service都会在Node节点上开通一个端口,外部可以通过 http://NodeIP:NodePort 即可访问 Service 里的 Pod 提供的服务。
- Pod IP:是每个 Pod 的 IP 地址,Docker Engine根据 docker 网桥的 IP 地址段进行分配的,通常是一个虚拟的二层网络,Pod的ip经常变化,且在k8s集群外无法访问。特点如下:
- 同Service下的pod可以直接根据PodIP相互通信。
- 不同Service下的pod在集群间pod通信要借助于 cluster ip。
- pod和集群外通信,要借助于node ip。
- Cluster IP:是 Service 的 IP 地址,此为虚拟 IP 地址,只是出现在service的规则当中,外部网络无法 ping 通,只有kubernetes集群内部访问使用。特点如下:
- Cluster IP仅仅作用于Kubernetes Service这个对象,并由Kubernetes管理和分配P地址 Cluster。
- IP无法被ping,他没有一个“实体网络对象”来响应 Cluster IP只能结合Service。
- Port组成一个具体的通信端口,单独的Cluster IP不具备通信的基础,并且他们属于Kubernetes集群这样一个封闭的空间。
- 在不同Service下的pod节点在集群间相互访问可以通过Cluster IP。
2.3 三种IP关系图
①:代表外部通过公有云的 LoadBalancer 负载均衡服务访问集群内部服务流程②:代表外部用户直接访问集群内部 Service 的 ClusterIP 访问集群内部服务流程③:代表集群内部不同 Service 之间的 Pod 服务访问流程④:代表集群内部同一个 Service 中 Pod 服务之间访问流程
三、暴露服务的三种方式
如果需要从集群外部访问服务,即将服务暴露给用户使用,Kubernetes Service 本身提供了两种方式,一种是 NodePort,另外一种是 LoadBalancer。另外 Ingress 也是一种常用的暴露服务的方式。
3.1 通过NodePort方式暴露集群内部容器服务
Kubernetes
具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新 的,还可以动态扩容等,通俗地说,这个Pod可能在任何时刻出现在任何节点上,也可能在任何时刻死 在任何节点上;那么自然随着Pod的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的Pod IP暴露出去?这里借助于Kubernetes的 Service
机制,Service 可以以标签的形式选定一组带有指定标 签的Pod,并监控和自动负载他们的Pod IP,那么我们向外暴露只暴露Service IP就行了;如果将服务的类型设置为 NodePort,kube-proxy 就会为这个服务申请一个 30000 以上的端口号(默认情况下),然后在集群所有主机上配置 IPtables
规则,这样用户就能通过集群中的任意节点加上这个分配的端口号访问服务了,这就是 NodePort模式:即在每个节点上开启一个端口,然后转发到内部Pod IP 上,如下图所示:
NodePort 是通常最方便暴露服务的方式,但是缺点也很明显:
- 基于 SNAT 进行访问,Pod 无法看到真正的 IP。
NodePort
是将集群中的一个主机作为跳板访问后端服务,所有的流量都会经过跳板机,很容易造成性能瓶颈和单点故障,难以用于生产环境。- 端口管理问题:采用NodePort方式暴露服务,服务一旦多起来,NodePort在每个节点上开启的端口数量会极其庞大,一般都是用大端口,不容易记忆,而且难以维护。
注:NodePort 设计之初就不建议用于生产环境暴露服务,所以默认端口都是一些大端口。
3.2 通过LoadBalancer方式暴露集群内部容器服务
LoadBalancer
通过云厂商的 LB 插件实现,例如青云的LB 插件基于cloud-controller-manager这个包实现,阿里云slb插件基于Cloud Controller Manager这个包实现,这些插件会自动选择合适的后端暴露给 LB 插件,然后 LB 插件由此创建对应的负载均衡器,网络流量在云服务端就会被分流,就能够避免 NodePort 方式的单点故障和性能瓶颈。LoadBalancer 是 Kubernetes 设计的对外暴露服务的推荐方式,但是这种方式仅仅限于云厂商提供的 Kubernetes 服务上,对于物理部署或者非云环境下部署的 Kubernetes 集群,这一机制就存在局限性而无法使用。
当然了若是使用青云的QKE集群,开启项目网关时可选创建一个负载均衡器,这里就自动完成绑定了,不需要手动去配置。如下qingcloud-cloud-controller-manager:
云平台插件 | cloud-controller-manager | cloud-controller-manager 是青云自主研发的负载均衡器插件,自动集成于 QKE 中。 支持将 Kubernetes 内部服务和 QingCloud 负载均衡器关联起来,可自动创建负载均衡器、公网 IP,通过负载均衡器将服务暴露给集群外部调用。 配置操作说明请参见负载均衡器插件配置。 |
注:这种方式是需要ccm(cloud-controller-manager)自动完成lb监听器创建、绑定公网IP。
3.3 通过Ingress方式暴露集群内部容器服务
正如上面介绍的Ingress
其实并不是 Kubernetes 服务本身提供的暴露方式,而是借助于软件实现的同时暴露多个服务的一种类似路由器的插件。Ingress 通过域名来区分不同服务,并且通过 annotation 的方式控制服务对外暴露的方式。
Ingress
官网定义:Ingress可以把进入到集群内部的请求转发到集群中的一些服务上,从而可以把服务映射到集群外部。Ingress 能把集群内Service 配置成外网能够访问的URL,流量负载均衡,提供基于域名访问的虚拟主机等。
Ingress简单的理解就是你原来需要改Nginx配置,然后配置各种域名对应哪个Service
,现在把这个动 作抽象出来,变成一个 Ingress 对象
,你可以用 yaml 创建,而不是每次都是改nginx的配置文件,直接改yaml然后创建或者更新就行了。那么问题来了:”Nginx 应该怎么处理?”
就像矛和盾一样,有矛就有盾,Ingress Controller就是解决”Nginx 应该怎么处理?”的,Ingress Controller 通过与 Kubernetes API 交互,动态的去感知集群中Ingress规则变化,然后读取它,按照它自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,其原理如下图:
上图配置文件如下:
apiVersion: extensions/v1beta1 #api 版本 kind: Ingress #清单类型 metadata: #元数据 name: ingress-myapp #ingress 的名称 namespace: default #所属名称空间 annotations: #注解信息 kubernetes.io/ingress.class: "nginx" spec: #规格 rules: #定义后端转发的规则 - host: myapp.com #通过域名进行转发 http: paths: - path: #配置访问路径,如果通过url进行转发,需要修改;空默认为访问的路径为"/" backend: #配置后端服务 serviceName: myapp servicePort: 80
实际上Ingress
也是Kubernetes API的标准资源类型之一,它其实就是一组基于DNS
名称(host)或 URL路径把请求转发到指定的Service 资源的规则。用于将集群外部的请求流量转发到集群内部完成的服 务发布。我们需要明白的是,Ingress资源自身不能进行“流量穿透
”,仅仅是一组规则的集合,这些集合规则还需要其他功能的辅助,比如监听某套接字,然后根据这些规则的匹配进行路由转发,这些能够为 Ingress资源监听套接字并将流量转发的组件就是Ingress Controller
。
注:Ingress控制器不同于Deployment控制器的是,Ingress控制器不直接运行为kube-controllermanager的一部分,它仅仅是Kubernetes集群的一个附件,类似于CoreDNS,需要在集群上单独部署。
四、青云LB结合Ingress实现访问集群内部容器服务
4.1 青云LB
青云负载均衡(Load Balancer,简称LB)提供安全快捷的流量分发服务,来自多个公网地址的访问流量经由 LB 可以自动分配到多台云服务器上,并支持自动检测并隔离故障云服务器,提供业务系统的服务能力和可用性。负载均衡支持千万级别并发访问请求,可轻松应对大流量访问,满足业务需求。
4.2 KubeSphere的项目网关和应用路由
KubeSphere的项目网关就是Ingress Controller,是一个七层负载均衡调度器,客户端的请求先到达这个七层负载均衡调度器,应用路由就是Ingress,是定义规则的。
KubeSphere中的项目网关,开启后会自动安装Ingress Controller,如下图所示:
注:节点http端口为30014,https端口为30796,创建监听器的时候要用到。
对应在k8s集群中svc如下图所示:
KubeSphere中应用路由是需要手动创建的,如下图所示:
设置理由规则:
创建后对应的yaml文件如下:
4.2 青云控制台创建监听器
创建监听器443和80,后端是集群节点的nodeport,证书直接绑定到lb的监听器下,后端端口是如下:
注意:Ingress路由规则协议采用http即可。lb监听器也绑定http的端口即可。否则lb采用https,Ingress路由规则协议采用http或者https,都会请求不通,出现请求错误。若是采用https,证书绑定一端即可。
五、后续改进方案
目前存在的问题:青云负载均衡的绑定端口默认只有100个 ,随着项目越来越多,会存在不够用的情况,后续还是用ccm(cloud-controller-manager)自动完成lb监听器创建、绑定公网IP比较好。
采用ccm(比较推荐):
1、ccm会将每个nodeport节点自动的添加到监听器后端,避免单节点故障引起的服务不可用
2、lb这边就不用再配置转发策略了
注:ccm是需要自己安装的,自己维护,若是采用青云QKE,是自动集成ccm的。