云原生2.0网关API标准发展趋势
摘要:Gateway API希望取代Ingress API。
本文分享自华为云社区《云原生2.0网关API标准发展趋势》,作者:华为云云原生团队 。
云原生网关API标准背景及发展现状
Gateway API是一个开源的API标准,源自Kubernetes SIG-NETWORK兴趣组。从出身角度讲,可谓根正苗红,自从开源以来备受关注,被寄予厚望。Gateway API旨在通过声明式、可扩展性和面向角色的接口来发展Kubernetes服务网络,并且希望成为供应商的网关API标准并获得广泛行业支持。简而言之,Gateway API希望取代Ingress API。
Gateway API 项目自2019年开源,但是经历了缓慢的发展,直到2022年7月才发布Beta版本,同时发起了GAMMA(Gateway API for Mesh Management and Administration)。笔者认为这里主要有两方面的原因:
- Ingress存在已久,并且是几乎所有的Ingress Controller的默认实现,Kubernetes的用户早已习惯Ingress,尽管Ingress在易用性和功能丰富度上面存在很大的差距。
- 服务网格或者API网关项目,例如Istio、Linkerd、Kong、Contour、Ambassador等都有自己的API标准,Gateway API用户接受度还不够高。
- 由于Gateway API并没有强大的用户基础,因而缺少功能、体验上的反馈,因而迭代比较缓慢。
什么是GAMMA
GAMMA (Gateway API for Mesh Management and Administration)是Gateway API项目的一个工作组。该小组的目标是调查、设计和跟踪网关API资源、语义,并负责其他与服务网格技术和用户使用场景相关的工件。此外,GAMMA倡导服务网格项目的网关API实现之间的一致性,无论Istio还是Linkerd,大家最好都来遵守这里定义的API规范和标准。GAMMA的Lead团队由来自Google的John Howard(Istio),来自微软的Keith Mattix(Open Service Mesh)和来自HashiCorp的Mike Morris(Consul)组成,在不同组织和服务网格项目的推动下,Gateway API有望统一服务网格API。
推波助澜
KubeCon EUateway API, EG将会使Envoy扩展更加容易。
Envoy上游开源一个网关项目,并且EG是站在Ambassador以及Contour等项目的肩膀上前进,给普通开发者带来无限的遐想。最重要的是,EG是第一个主要实现Gateway API的项目,这一操作也为Gateway API带来新的活力,直接推动Gateway API在7月份发布了Beta版本。
Gateway API生态
前面提到Envoy Gateway项目宣布以Gateway API为唯一的网关标准,并且EG也是唯一一个只遵守Gateway API标准的Ingress网关项目。其他实现者,都是在自身API的基础上,额外支持Gateway API。并且对Gateway API的支持普遍比较初级:

Gateway API绝不仅仅关注南北向流量治理策略的标准,东西向流量也是它所重点覆盖的方向。南北向主要是一些网关项目的领地,东西向是服务网格的领地。当然服务网格如Istio都有自己的Ingress Gateway, 能够对北向流量进行管理。东西向流量从特征上要比南北向流量更多,因为客户端在集群中,可以通过Labels标签表示客户端的属性,通过ServiceAccount标识身份。网格在东西向流量治理时能够充分利用K8s工作负载的标签、身份进行更多的路由、安全策略控制。Gateway API标准在东西向流量这一块目前并没有对等服务网格现有的能力,具体在最后一章再来进行对比。前期Gateway API主要关注的还是南北向的流量治理标准,这与它 “取代Ingress” 的设计初衷相符。
Gateway API设计

Gateway API基于可移植、可扩展、表达性强以及面向不同角色四个原则设计。
- 可移植:相对Ingress来说这一点并不是改进,而是保持与Ingress一致,通过通用的规范,能让更多的网关轻松实现。而Gateway API所追求的领域绝不仅限于南北向网关,而且它还要覆盖服务网格。
- 表达性强:Gateway API支持核心功能,如基于Header匹配、流量权重分隔以及其他功能,这些功能只有在Ingress中通过自定义注释Annotation才能实现。
- 可扩展:Gateway API允许引用其他的自定义资源对象,这使得在API结构中的适当位置进行个性化定制成为可能。
- 面向角色:从上图可见Gateway 由不同的API资源构成,分别为不同的角色设计。其中应用开发者定义HTTPRoute,集群维护者定义Gateway对象,基础设施提供者定义GatewayClass。
本章选取面向角色和可扩展性两个最具代表性的设计原则,详细解释Gateway API的设计。
面向角色的API设计
无论是道路、电力、数据中心还是Kubernetes集群,基础设施都是为共享而构建的。然而,共享基础架构提出了一个共同的挑战--如何为基础架构的用户提供足够的灵活性,同时保持基础架构所有者的独立控制?
Gateway API通过面向角色的设计为K8s服务网络提供灵活的控制,该设计在分布式灵活性和集中控制之间取得了平衡。它允许许多不同的团队使用共享网络基础架构(硬件负载平衡器、云网络、网关等),所有这些团队都受集群维护者设置的策略限制和约束。如下是Gateway API官网的实例,集群维护者通过Gateway定义流量入口,以及TLS Terminate。集群中有两个租户,其中存储开发者在Store命名空间部署了自己的微服务,站点开发者在Site命名空间也部署了自己的微服务。他们在集群网关上共用同一域名,同一端口,因此网关只能通过匹配不同的HTTP Authority来路由客户端的请求。路由策略的设置则是由应用开发者们(Store、Site开发者)自己定义,然后绑定到同一个Gateway上。

下面通过一个官方示例,为大家展示不同的角色如何根据自己的权限来定义服务的治理策略。
集群维护者通过Gateway定义Listener以及允许绑定的路由策略。如下 *shared-gateway*表示在443端口监听连接,通过 *foo-example-com*证书在网关处做TLS终结。
```yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: shared-gateway
namespace: infra-ns
spec:
gatewayClassName: shared-gateway-class
listeners:
- name: https
hostname: "foo.example.com"
protocol: HTTPS
port: 443
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway-access: "true"
tls:
certificateRefs:
- name: foo-example-com
```
集群维护者定义只允许以下命名空间的路由策略能够绑定网关,因为它们有shared-gateway-access: "true"标签。
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: infra-ns
labels:
shared-gateway-access: "true"
---
apiVersion: v1
kind: Namespace
metadata:
name: site-ns
labels:
shared-gateway-access: "true"
---
apiVersion: v1
kind: Namespace
metadata:
name: store-ns
labels:
shared-gateway-access: "true"
```
Store开发者可以定义以下HTTP路由,当请求路径前缀是/store时,将其路由到store服务,同理Site开发者也可以定义自己的路由然后绑定到网关。
```yaml
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: store
namespace: store-ns
spec:
parentRefs:
- name: shared-gateway
namespace: infra-ns
rules:
- matches:
- path:
value: /store
backendRefs:
- name: store
port: 8080
```
这里可以看出,不同角色权限控制比较严格,只有集群维护者允许的路由策略才能绑定到网关上。应用开发者,只能对所拥有的服务具有控制权。
可扩展性-Policy挂载
策略挂载提供了高扩展性,虽然超时,重试,以及个性化的健康检查在一些网关实现中很常见,但是大多数网关的实现方式是不同的,没有统一的API标准。保持这类API的一致性变得艰难,所以Gateway API特意设计了Policy挂载,允许在网关、路由中插入个性化的策略控制。

Ingress策略挂载

Mesh策略挂载
从上图可以看到,无论是Gateway还是HTTPRoute都允许任意引用其他的策略,此设计大大提高了Gateway API的扩展能力。
Gateway API还有多远

Gateway API与其他主流API对比
从上述功能丰富度对比来看,Istio API > Gateway API > Ingress, 然而Gateway API通过Reference其他自定义对象提供的扩展能力明显强于Istio。尽管当前Gateway API没有提供故障注入,超时、重试,限流等策略,但是通过它超强的扩展能力能够很容易做到。
相信通过阅读本文,大家对Gateway API一定充满了好奇,Gateway API距离成熟、大规模商用还有多远?
首先从目前的生态分析,Gateway API被Kubernetes圈普遍认可,包括开源项目、甚至商业服务GKE的支持。归根到底,Gateway API由Kubernetes网络组发起、维护,并且吸引了大量开源网络项目的维护者参与。当然实际背后控制者是Google,Google在开源技术的领导力毋庸置疑。但是不得不认识到,目前所有Gateway API的支持都处于初级阶段。
其次,从兼容性的角度看,一些成熟的项目,比如Istio,用户长期以来习惯了Istio的API标准,Istio社区也不会贸然的废弃原有的API,转而只支持Gateway API。因此这种多种API并存的局面将会持续很久,即使在未来Gateway API成熟了。
最后,前面讲到Gateway API对超时、重试、故障注入等能力预留了扩展能力,但是这种基本的网络能力,Gateway API应该提供标准的API,而不是让用户自己去定义私有的标准。这也违背了Gateway API想要统一服务网络标准的初衷。除此之外,灵活的扩展性如果违背了易用性,显然用户是不会买账的。
综上所述,笔者认为至少在一两年之内,Gateway API将会持续迭代,短时间内很难形成成熟的标准。或许可以期待,2024年以后服务网格和API网关的标准将会统一。
在当前的历史契机下,华为云应该牢牢把握机会,基于Gateway API推出自己的云原生网关服务,这将是一次难得的弯道超车的好机会。添加小助手微信k8s2222,进入技术交流群。
参考文献
1. Kubernetes gateway API官网:https://gateway-api.sigs.k8s.io/2. https://blog.envoyproxy.io/introducing-envoy-gateway-ad385cc595323. Istio官网:https://istio.io/4. Nginx Ingress Controller:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/
1. Kubernetes gateway API官网:https://gateway-api.sigs.k8s.io/2. https://blog.envoyproxy.io/introducing-envoy-gateway-ad385cc595323. Istio官网:https://istio.io/3. Nginx Ingress Controller:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/
云原生2.0网关API标准发展趋势的更多相关文章
- 云原生之旅 - 8)云原生时代的网关 Ingress Nginx
前言 当我们在Kubernetes部署的服务需要暴露给外部用户使用时,有三种选择:LoadBalancer,NodePort, Ingress. LoadBalancer类型得结合各个Cloud Pr ...
- OpenTelemetry - 云原生下可观测性的新标准
CNCF 简介 CNCF(Cloud Native Computing Foundation),中文为"云原生计算基金会",CNCF是Linux基金会旗下的基金会,可以理解为一个非 ...
- 拥抱云原生 2.0 时代,Tapdata 入选阿里云首期云原生加速器!
3月9日,阿里云首期云原生加速器官宣,Tapdata 突出重围,成功入选31 强,将与多家行业知名企业,携手阿里云共建云原生行业新生态,加速拥抱云原生新时代的无限潜能. 2021年,阿里云正式 ...
- API 管理在云原生场景下的机遇与挑战
作者 | 张添翼 来源 | 尔达Erda公众号 云原生下的机遇和挑战 标准和生态的意义 自从 Kubernetes v1.0 于 2015 年 7 月 21 日发布,CNCF 组织随后建立以来,其 ...
- 云原生之旅 - 9)云原生时代网关的后起之秀Envoy Proxy 和基于Envoy 的 Emissary Ingress
前言 前一篇文章讲述了基于Nginx代理的Kuberenetes Ingress Nginx[云原生时代的网关 Ingress Nginx]这次给大家介绍下基于Envoy的 Emissary Ingr ...
- 理想汽车 x JuiceFS:从 Hadoop 到云原生的演进与思考
理想汽车在 Hadoop 时代的技术架构 首先简单回顾下大数据技术的发展,基于我个人的理解,将大数据的发展分了4个时期: 第一个时期: 2006 年到 2008 年.2008 年左右,Hadoop 成 ...
- 华为云亮相QCon2020深圳站,带你体会大厂的云原生玩法与秘诀
摘要:在QCon全球软件开发大会上,华为云开发者生态总监张全文作为"云原生应用开发实践"专题出品人,携手华为云四位资深技术专家带来精彩分享. 作为当下技术领域最火热的技术趋势之一, ...
- 云原生生态周报 Vol. 14 | K8s CVE 修复指南
业界要闻 Mesosphere 公司正式更名为 D2IQ, 关注云原生. Mesosophere 公司日前发布官方声明正式更名为:D2iQ(Day-Two-I-Q),称关注点转向 Kubernetes ...
- 持续优化云原生体验,阿里云在Serverless容器与多云上的探索
近日,阿里云宣布推出Serverless Kubernetes服务此举意在降低容器技术的使用门槛.简化容器平台运维.并同时发布阿里云服务对Open Service Broker API标准支持,通过一 ...
- 重磅!业界首个云原生批量计算项目Volcano正式晋级为CNCF孵化项目
摘要:4月7日,云原生计算基金会(CNCF)宣布,由华为云捐献的业界首个云原生批量计算项目Volcano正式晋级为CNCF孵化项目. 4月7日,云原生计算基金会(CNCF)宣布,由华为云捐献的业界首个 ...
随机推荐
- GDB 调试 - 正确地加载调试符号文件
一.开发流程 1. 编译可执行文件 1 #include <stdio.h> 2 #include <unistd.h> 3 4 void test() 5 { 6 char ...
- IntelliJ IDEA 2021.2 暴力破解
注意 本教程适用于 IntelliJ IDEA 2021.2 以下所有版本,请放心食用~ 本教程适用于 JetBrains 全系列产品,包括 Pycharm.IDEA.WebStorm.Phpstor ...
- go语言读取文件的简单使用
注意:打开文件记得一定要关闭 file, err := os.Open("文件名称") defer file.Close() 一.打开文件 1. file, err := os.O ...
- C++ 全面总结
1. 基本数据类型:没什么好说的.知道浮点数存储起来不精确.各种类型占的大小在不同平台可能不一样就行了 2. 初始化列表:能用就用.能防止潜在的类型收窄, 3. static_cast 和 dynam ...
- 【QT5】学习整理包含引用资料
视频学习资料 [[6天学会QT] 视频教程及QT5.11.1安装包安装方法][含代码]](https://www.bilibili.com/video/BV1hg4y1B7Vu?from=search ...
- python多线程获取线程执行结果
In [1]: from threading import Thread def fun(t): """ //执行函数体 //t:时间 """ ...
- 自己动手从零写桌面操作系统GrapeOS系列教程——19.硬盘读写理论知识
学习操作系统原理最好的方法是自己写一个简单的操作系统. 一.硬盘控制器 我们前面已经讲过硬盘控制器是一种I/O接口,CPU通过它就能间接的读写硬盘.硬盘控制器主要有IDE和SATA两种,我们这里只考虑 ...
- springboot---多环境启动命令格式
一.多环境命令启动 maven插件中首先clean,再package打包,(修改字符集为UTF-8) 使用cmd命令java -jar s(Tab键自动补全) -spring.profiles.ac ...
- 在java中String类为什么要设计成final?Java面试常见问题
2023Java面试题最经典的问题之一了,非常经典的Java基础知识,一定要学会! 在Java中,String类被设计成final,这意味着它的值在创建后不可更改.这是因为字符串在Java中使用广泛, ...
- 20个值得收藏的实用JavaScript技巧
1.确定对象的数据类型 function myType(type) { return Object.prototype.toString.call(type).slice(8, -1); 使用Obje ...