在 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
三种 IP 概述
Node IP:Node 节点的 IP 地址,即物理机 (虚拟机) 的 IP 地址。 Pod IP:Pod 的 IP 地址,即 Docker 容器的 IP 地址,也是虚拟 IP 地址。 Cluster IP:k8s 虚拟的 Service 的 IP 地址,也是虚拟 IP 地址。
三种 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 可以直接根据 Pod IP 相互通信。 不同 Service 下的 Pod 在集群间 pod 通信要借助于 Cluster IP。 Pod 和集群外通信,要借助于 Node IP。 Cluster IP:是 Service 的 IP 地址,此为虚拟 IP 地址,只是出现在 Service 的规则当中,外部网络无法 ping 通,只有 K8s 集群内部访问使用。特点如下:
Cluster IP 仅仅作用于 K8s Service 这个对象,并由 K8s 管理和分配 IP 地址。 IP 无法被 ping,他没有一个“实体网络对象”来响应,Cluster IP 只能结合 Service。 Port 组成一个具体的通信端口,单独的 Cluster IP 不具备通信的基础,并且他们属于 Kubernetes 集群这样一个封闭的空间。 在不同 Service 下的 Pod 节点在集群间相互访问可以通过 Cluster IP。
三种 IP 关系图

①:代表外部通过公有云的 LoadBalancer 负载均衡服务访问集群内部服务流程
②:代表外部用户直接访问集群内部 Service 的 ClusterIP 访问集群内部服务流程
③:代表集群内部不同 Service 之间的 Pod 服务访问流程
④:代表集群内部同一个 Service 中 Pod 服务之间访问流程
暴露服务的三种方式
如果需要从集群外部访问服务,即将服务暴露给用户使用,Kubernetes Service 本身提供了两种方式,一种是 NodePort,另外一种是 LoadBalancer。另外 Ingress 也是一种常用的暴露服务的方式。
通过 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 设计之初就不建议用于生产环境暴露服务,所以默认端口都是一些大端口。
通过 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。
通过 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 实现访问集群内部容器服务
青云 LB
青云负载均衡(Load Balancer,简称 LB)提供安全快捷的流量分发服务,来自多个公网地址的访问流量经由 LB 可以自动分配到多台云服务器上,并支持自动检测并隔离故障云服务器,提供业务系统的服务能力和可用性。负载均衡支持千万级别并发访问请求,可轻松应对大流量访问,满足业务需求。
KubeSphere 的项目网关和应用路由
KubeSphere 的项目网关就是 Ingress Controller,是一个七层负载均衡调度器,客户端的请求先到达这个七层负载均衡调度器,应用路由就是 Ingress,是定义规则的。
KubeSphere 中的项目网关,开启后会自动安装 Ingress Controller,如下图所示:

❝注:节点 http 端口为 30014,https 端口为 30796,创建监听器的时候要用到。
对应在 K8s 集群中 SVC 如下图所示:

KubeSphere 中应用路由是需要手动创建的,如下图所示:


设置路由规则:

创建后对应的 yaml 文件如下:

青云控制台创建监听器
创建监听器 443 和 80,后端是集群节点的 NodePort,证书直接绑定到 LB 的监听器下,后端端口是如下:

❝注意:Ingress 路由规则协议采用 http 即可。LB 监听器也绑定 http 的端口即可。否则 LB 采用 https,Ingress 路由规则协议采用 http 或者 https, 都会请求不通,出现请求错误。若是采用 https,证书绑定一端即可。
后续改进方案
目前存在的问题:青云负载均衡的绑定端口默认只有 100 个 ,随着项目越来越多,会存在不够用的情况,后续还是用 ccm(cloud-controller-manager)自动完成 LB 监听器创建、绑定公网 IP 比较好。
采用 ccm(比较推荐):
ccm 会将每个 NodePort 节点自动的添加到监听器后端,避免单节点故障引起的服务不可用 LB 这边就不用再配置转发策略了
注:ccm 是需要自己安装的,自己维护,若是采用青云 QKE, 是自动集成 ccm 的。
2022-08-30
2022-08-26
2022-08-25
KubeSphere (https://kubesphere.io)是在 Kubernetes 之上构建的开源容器平台,提供全栈的 IT 自动化运维的能力,简化企业的 DevOps 工作流。
KubeSphere 已被 Aqara 智能家居、爱立信、本来生活、东软、华云、新浪、三一重工、华夏银行、四川航空、国药集团、微众银行、杭州数跑科技、紫金保险、去哪儿网、中通、中国人民银行、中国银行、中国人保寿险、中国太平保险、中国移动、中国联通、中国电信、天翼云、中移金科、Radore、ZaloPay 等海内外数万家企业采用。KubeSphere 提供了开发者友好的向导式操作界面和丰富的企业级功能,包括 Kubernetes 多云与多集群管理、DevOps (CI/CD)、应用生命周期管理、边缘计算、微服务治理 (Service Mesh)、多租户管理、可观测性、存储与网络管理、GPU support 等功能,帮助企业快速构建一个强大和功能丰富的容器云平台。





