您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Model Center   Code  
会员   
   
 
     
   
 
 订阅
K8s & K3s 对外服务暴露分析
 
作者:流雨声
   次浏览      
 2022-5-5
 
编辑推荐:
本文主要介绍了K8s & K3s 对外服务暴露分析。希望对您的学习有所帮助。
本文来自于简书,由Linda编辑、推荐。

背景简介

K8s & K3s 将外部流量引入群集有哪些不同方式,在何种场景选用那种方式,我们进行如下探讨:

NodePort

NodePort在集群中的主机节点上为Service提供一个代理端口,以允许从主机网络上对Service进行访问。

NodePort的流量转发机制和Cluster IP的iptables模式类似,唯一不同之处是在主机网络上开了一个“NodePort”来接受外部流量。从上面的规则也可以看出,在创建Nodeport时,Kube-proxy也会同时为Service创建Cluster IP相关的iptables规则。

NodePort提供了一种从外部网络访问Kubernetes集群内部Service的方法,但该方法存在下面一些限制,导致这种方式主要适用于程序开发,不适合用于产品部署。

Kubernetes cluster host的IP必须是一个well-known IP,即客户端必须知道该IP。但Cluster中的host是被作为资源池看待的,可以增加删除,每个host的IP一般也是动态分配的,因此并不能认为host IP对客户端而言是well-known IP。

客户端访问某一个固定的host IP的方式存在单点故障。假如一台host宕机了,kubernetes cluster会把应用 reload到另一节点上,但客户端就无法通过该host的nodeport访问应用了。

通过一个主机节点作为网络入口,在网络流量较大时存在性能瓶颈。

LoadBalancer

Kubernetes提供了LoadBalancer。通过将Service定义为LoadBalancer类型,Kubernetes在主机节点的NodePort前提供了一个四层的负载均衡器。该四层负载均衡器负责将外部网络流量分发到后面的多个节点的NodePort端口上。

下图展示了Kubernetes如何通过LoadBalancer方式对外提供流量入口,图中LoadBalancer后面接入了两个主机节点上的NodePort,后端部署了三个Pod提供服务。根据集群的规模,可以在LoadBalancer后面可以接入更多的主机节点,以进行负荷分担。

备注:LoadBalancer类型需要云服务提供商的支持,Service中的定义只是在Kubernetes配置文件中提出了一个要求,即为该Service创建Load Balancer,至于如何创建则是由Google Cloud或Amazon Cloud等云服务商提供的,创建的Load Balancer的过程不在Kubernetes Cluster的管理范围中。

目前WS, Azure, CloudStack, GCE 和 OpenStack 等主流的公有云和私有云提供商都可以为Kubernetes提供Load Balancer。一般来说,公有云提供商还会为Load Balancer提供一个External IP,以提供Internet接入。如果你的产品没有使用云提供商,而是自建Kubernetes Cluster,则需要自己提供LoadBalancer。

Ingress

LoadBalancer类型的Service提供的是四层负载均衡器,当只需要向外暴露一个服务的时候,采用这种方式是没有问题的。但当一个应用需要对外提供多个服务时,采用该方式则要求为每一个四层服务(IP+Port)都创建一个外部load balancer。

一般来说,同一个应用的多个服务/资源会放在同一个域名下,在这种情况下,创建多个Load balancer是完全没有必要的,反而带来了额外的开销和管理成本。另外直接将服务暴露给外部用户也会导致了前端和后端的耦合,影响了后端架构的灵活性,如果以后由于业务需求对服务进行调整会直接影响到客户端。为了解决该问题,可以通过使用Kubernetes Ingress来作为网络入口。

Kubernetes Ingress声明了一个应用层(OSI七层)的负载均衡器,可以根据HTTP请求的内容将来自同一个TCP端口的请求分发到不同的Kubernetes Service,其功能包括:

按HTTP请求的URL进行路由

同一个TCP端口进来的流量可以根据URL路由到Cluster中的不同服务,如下图所示:

按HTTP请求的Host进行路由

同一个IP进来的流量可以根据HTTP请求的Host路由到Cluster中的不同服务,如下图所示:

Ingress 规则定义了对七层网关的要求,包括URL分发规则,基于不同域名的虚拟主机,SSL证书等。Kubernetes使用Ingress Controller 来监控Ingress规则,并通过一个七层网关来实现这些要求,一般可以使用Nginx,HAProxy,Envoy等。

Ingress配合NodePort和LoadBalancer提供对外流量入口

虽然Ingress Controller通过七层网关为后端的多个Service提供了统一的入口,但由于其部署在集群中,因此并不能直接对外提供服务。实际上Ingress需要配合NodePort和LoadBalancer才能提供对外的流量入口,如下图所示:

上图描述了如何采用Ingress配合NodePort和Load Balancer为集群提供外部流量入口,从该拓扑图中可以看到该架构的伸缩性非常好,在NodePort,Ingress,Pod等不同的接入层面都可以对系统进行水平扩展,以应对不同的外部流量要求。

上图只展示了逻辑架构,下面的图展示了具体的实现原理:

流量从外部网络到达Pod的完整路径如下:

外部请求先通过四层Load Balancer进入内部网络

Load Balancer将流量分发到后端多个主机节点上的NodePort (userspace转发)

请求从NodePort进入到Ingress Controller (iptabes规则,Ingress Controller本身是一个NodePort类型的Service)

Ingress Controller根据Ingress rule进行七层分发,根据HTTP的URL和Host将请求分发给不同的Service (userspace转发)

Service将请求最终导入到后端提供服务的Pod中 (iptabes规则)

从前面的介绍可以看到,K8S Ingress提供了一个基础的七层网关功能的抽象定义,其作用是对外提供一个七层服务的统一入口,并根据URL/HOST将请求路由到集群内部不同的服务上。

场景应用分析

ClusterIP

ClusterIP 服务是 Kubernetes 的默认服务。它给你一个集群内的服务,集群内的其它应用都可以访问该服务。集群外部无法访问它。

ClusterIP 服务的 YAML 文件类似如下:

apiVersion: v1

kind: Service
metadata:
name: my-internal-service
selector:
app: my-app
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
protocol: TC

 

从Internet 没法访问 ClusterIP 服务,那么为什么要讨论它呢?那是因为我们可以通过 Kubernetes 的 proxy 模式来访问该服务!

# 启动 Kubernetes proxy 模式:
kubectl proxy --port=8080
# 通过Kubernetes API,使用如下模式来访问这个服务:
http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>
/services/<SERVICE-NAME>:<PORT-NAME>
# 要访问上面定义的服务,可以使用如下地址:
http://localhost:8080/api/v1/proxy/namespaces/default/services
/my-internal-service:http/

 

何时使用这种方式?

有一些场景下,你得使用 Kubernetes 的 proxy 模式来访问你的服务:

由于某些原因,你需要调试你的服务,或者需要直接通过笔记本电脑去访问它们。

容许内部通信,展示内部仪表盘等。

这种方式要求我们运行 kubectl 作为一个未认证的用户,因此我们不能用这种方式把服务暴露到 internet 或者在生产环境使用。

NodePort

NodePort 服务是引导外部流量到你的服务的最原始方式。NodePort,正如这个名字所示,在所有节点(虚拟机)上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务。

NodePort 服务的 YAML 文件类似如下:

apiVersion: v1

kind: Service
metadata:
name: my-nodeport-service
selector:
app: my-app
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30036
protocol: TC

 

NodePort 服务主要有两点区别于普通的“ClusterIP”服务。第一,它的类型是“NodePort”。有一个额外的端口,称为 nodePort,它指定节点上开放的端口值 。如果你不指定这个端口,系统将选择一个随机端口。大多数时候我们应该让 Kubernetes 来选择端口,因为如评论中 thockin 所说,用户自己来选择可用端口代价太大。

何时使用这种方式?

这种方法有许多缺点:

每个端口只能是一种服务

端口范围只能是 30000-32767

如果节点/VM 的 IP 地址发生变化,你需要能处理这种情况。

基于以上原因,我不建议在生产环境上用这种方式暴露服务。如果你运行的服务不要求一直可用,或者对成本比较敏感,你可以使用这种方法。这样的应用的最佳例子是 demo 应用,或者某些临时应用。

LoadBalancer

LoadBalancer 服务是暴露服务到 internet 的标准方式。在 GKE 上,这种方式会启动一个 Network Load Balancer,它将给你一个单独的 IP 地址,转发所有流量到你的服务。

何时使用这种方式?

如果你想要直接暴露服务,这就是默认方式。所有通往你指定的端口的流量都会被转发到对应的服务。它没有过滤条件,没有路由等。这意味着你几乎可以发送任何种类的流量到该服务,像 HTTP,TCP,UDP,Websocket,gRPC 或其它任意种类。

这个方式的最大缺点是每一个用 LoadBalancer 暴露的服务都会有它自己的 IP 地址,每个用到的 LoadBalancer 都需要付费,这将是非常昂贵的。

有别于以上所有例子,Ingress 事实上不是一种服务类型。相反,它处于多个服务的前端,扮演着“智能路由”或者集群入口的角色。

你可以用 Ingress 来做许多不同的事情,各种不同类型的 Ingress 控制器也有不同的能力。

GKE 上的默认 ingress 控制器是启动一个 HTTP(S) Load Balancer。它允许你基于路径或者子域名来路由流量到后端服务。例如,你可以将任何发往域名 foo.yourdomain.com 的流量转到 foo 服务,将路径 yourdomain.com/bar/path 的流量转到 bar 服务。

GKE 上用 L7 HTTP Load Balancer 生成的 Ingress 对象的 YAML 文件类似如下:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
backend:
serviceName: other
servicePort: 8080
rules:
- host: foo.mydomain.com
http:
paths:
- backend:
serviceName: foo
servicePort: 8080
- host: mydomain.com
http:
paths:
- path: /bar/*
backend:
serviceName: bar
servicePort: 8080

 

何时使用这种方式?

Ingress 可能是暴露服务的最强大方式,但同时也是最复杂的。Ingress 控制器有各种类型,包括 Google Cloud Load Balancer, Nginx,Contour,Istio,等等。它还有各种插件,比如 cert-manager,它可以为你的服务自动提供 SSL 证书。

如果你想要使用同一个 IP 暴露多个服务,这些服务都是使用相同的七层协议(典型如 HTTP),那么Ingress 就是最有用的。如果你使用本地的 GCP 集成,你只需要为一个负载均衡器付费,且由于 Ingress是“智能”的,你还可以获取各种开箱即用的特性(比如 SSL,认证,路由,等等)。

拓展阅读

针对网络流量的负载均衡,在实际生产工作中都是机其重要的角色的,我们几乎所有的流量通信服务都是需要对外暴露,这是第一步,之后才会开始考虑鉴权,负载,限流等诸多问题的,所以如何安全合适的暴露我们的流量是一个值得探讨的话题,尤其在微服务领域,当开发人员的所有开发能力永远和 IP+Port 时,技术人员也应该反思下自己的能力了,流量分析的问题是一个很大的面,也是从初级开发人员迈向高级/资深工程师的很关键的一步。

 

   
次浏览       
相关文章

聊聊云原生和微服务架构
Serverless:微服务架构的终极模式
如何实现微服务架构下的分布式事务?
微服务下的数据架构设计
相关文档

微服务和云原生应用
微服务架构原理和设计方法
0到3000万用户微服务之旅
微服务在微信后台的架构实践
相关课程

微服务架构设计与实践
领域驱动+微服务架构设计
云计算、微服务与分布式架构
云平台与微服务架构设计

最新活动计划
C++高级编程 12-25 [线上]
白盒测试技术与工具实践 12-24[线上]
LLM大模型应用与项目构建 12-26[特惠]
需求分析最佳实践与沙盘演练 1-6[线上]
SysML建模专家 1-16[北京]
UAF架构体系与实践 1-22[北京]
 
 
最新文章
云原生架构概述
K8S高可用集群架构实现
容器云管理之K8S集群概述
k8s-整体概述和架构
十分钟学会用docker部署微服务
最新课程
云计算、微服务与分布式架构
企业私有云原理与构建
基于Kubernetes的DevOps实践
云平台架构与应用(阿里云)
Docker部署被测系统与自动化框架实践
更多...   
成功案例
北京 云平台与微服务架构设计
通用公司GE Docker原理与实践培训
某军工研究单位 MDA(模型驱动架构)
知名消费金融公司 领域驱动设计
深圳某汽车企业 模型驱动的分析设计
更多...