前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Ingress 的继任者 —— Gateway API?

Ingress 的继任者 —— Gateway API?

作者头像
崔秀龙
发布2021-07-19 10:23:24
1.8K0
发布2021-07-19 10:23:24
举报
文章被收录于专栏:伪架构师伪架构师

在 Kubernetes 集群边缘对外提供网络服务的时候,通常需要借助 Ingress 对象,这个对象提供了暴露 Service 所必须的核心要素,例如基于主机名的路由、对 URL 路径的适配以及 TLS 配置等。但是在实际开放服务的时候,往往会有更多的具体需求,这时 Ingress 对象所提供的核心功能就有些力不从心了,各种 Ingress 控制器往往会使用 metadata.annotations 中的特定注解,来完成对 Ingress 特定行为的控制,完成各自的个性化功能,例如认证、路径变更、黑白名单等,这就让 Ingress 对象变成了一个奇怪的东西:结构化的核心结构,和非结构化的标注结合起来形成各种 Ingress 方言,并且后期还出现了 Traefik Middleware 这样的 CRD 配置,这给 Ingress 功能的集中管理造成了一个较大的困扰;另外 Ingress 中可以随意定制主机名、路径以及后端服务,也给共享集群的用户造成了一定的安全隐患。包括 Cotour、Traefik 在内的 Ingress 控制器后期都提供了各自的基于 CRD 的功能表达,客观上也让 Ingress 世界更为分裂。 例如要移除路径前缀,Nginx Ingress 控制器需要使用 nginx.ingress.kubernetes.io/rewrite-target 注解,而 Traefik 1.7 中则需要使用 traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip 注解。

SIG-Network 基于实际现状和需求,提出了全新的 Gateway API 来作为 Ingress 的继任者,总体来说,相对于 Ingress,Gateway API 有几个显著特点:

  1. 职责分离,运维、开发等不同的角色都能够在适合的边界内完成工作;
  2. 扩展核心能力,并使用更结构化的方式进行表达;
  3. 易于扩展:Gateway API 为各种不同实现的控制器提供了一致的扩展方法。

目前该 API 还处于 Alpha 阶段,也仅有少量控制器提供了早期支持。下面做一些陈述和试验,来看看 Gateway API 有什么不一样。

概念层次

Ingress 中包含了 IngressClass/Ingress 两层概念,而 Gateway API 包含了三层概念:GatewayClass、Gateway 和 Route,其中的 Route 实际是包含了 HTTPRoute、TCPRoute、TLSRoute 和 UDPRoute 在内的一组对象。

GatewayClass

它是一个集群范围内的资源,由云基础设施中的 Gateway API 控制器提供,其职责和原有的 Ingress Class 类似。

Gateway

Gateway 对象是命名空间范围对象,可以视作是 GatewayClass 的一个实例,它通常是由具体机群的运维人员进行维护的,在 Gateway 对象中可以指定该对象负责的主机名称范围,用标签选择器选择对应的 Service,甚至还可以指定该 Gateway 生效的命名空间。这样就给具体应用的对外开放划定了一个范围,防止应用随意占用主机名,并完善命名空间的隔离能力。

Route

前文讲到,Route 对象除了像原有的 Ingress 对象一样提供 HTTP 服务的开放能力之外,还提供了 TCP、TLS 和 UDP 的对应资源,从而缓解了 Nginx、HAProxy Ingress 控制器使用 Configmap 配置 TCP/UDP 的窘境。HTTPRoute 除了提供基础的 Ingress 对象能力之外,还提供了一些“越界”的功能,例如对流量进行复制、分流;更重要的是其中还提供了 Filter 能力,这是一个扩展点,除了自带的核心处理能力之外,底层设施还可以在这里接入自己的 CRD,对流量进行处理,从而为流量处理能力的扩展提供了一个统一入口。UDPRoute 和 TCPRoute 也提供了对流量的判别能力,但是这部分仅提供了扩展点,而没有像 HTTP 一样的成熟能力。

举个栗子

目前 GKE 提供了 Gateway API 的公共预览版可以用于测试,仅限于以下区域的 1.20 以上版本的集群:

  • us-west1
  • us-east1
  • us-central1
  • europe-west4
  • europe-west3
  • europe-west2
  • europe-west1
  • asia-southeast1

不同区域的集群缺省开关可能不一致,注意需要在控制台的网络页面启用 HTTP 负载均衡功能,或者在命令行中的 --addons 参数值里加入 HttpLoadBalancing

使用如下命令部署网关资源:

代码语言:javascript
复制
$ kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.3.0" \
| kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/backendpolicies.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/gatewayclasses.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/gateways.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/httproutes.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/tcproutes.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/tlsroutes.networking.x-k8s.io created
customresourcedefinition.apiextensions.k8s.io/udproutes.networking.x-k8s.io created

部署完成之后,网关控制器会被触发,创建两个 GatewayClass

代码语言:javascript
复制
$ kubectl get gatewayclasses
NAME          CONTROLLER                  AGE
gke-l7-gxlb   networking.gke.io/gateway   1s
gke-l7-rilb   networking.gke.io/gateway   1s

不难发现,我们使用的是 HTTP 负载均衡,新建的 Gateway Class 也都包含 l7 字样,其实官方文档也明确说明:

注意:GKE Gateway Controller 仅支持 GatewayClass、网关和 HTTPRoute。不支持 TCPRoute、UDPRoute 和 TLSRoute。

这里初始化了两个 GatewayClass,gxlb 用于外部,rilb 用于内部,所以我们要在外网测试,就要用 gxlb 创建网关。

一个简单的工作负载:

代码语言:javascript
复制
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: flaskapp-v1
  name: flaskapp-v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: flaskapp-v1
  template:
    metadata:
      labels:
        app: flaskapp-v1
    spec:
      containers:
      - image: dustise/flaskapp:v0.2.6
        name: flaskapp
        env:
        - name: "VERSION"
          value: "v1"
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: flaskapp-v1
  name: flaskapp-v1
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: flaskapp-v1
  type: ClusterIP

创建 Gateway:

代码语言:javascript
复制
kind: Gateway
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
  name: gateway-gen
spec:
  gatewayClassName: gke-l7-gxlb
  listeners:
  - protocol: HTTP
    port: 80
    hostname: "*.microservice.xyz"
    routes:
      kind: HTTPRoute
      selector:
        matchLabels:
          app: flaskapp-v1
      namespaces:
        from: "All"

这个 Gateway 对象中仅定义了一个 Listener 对象,其中规定可以使用的域名为 *.microservice.xyzHTTPRoute,选择器要求使用这个对象的 Route 必须使用 app=flaskapp-v1 的标签,可以在所有命名空间中进行引用。创建之后查看一下状态:

代码语言:javascript
复制
$ kubectl describe gateway gateway-gen

...
Spec:
  Gateway Class Name:  gke-l7-gxlb
  Listeners:
    Hostname:  *.microservice.xyz
    Port:      80
    Protocol:  HTTP
    Routes:
      Group:  networking.x-k8s.io
      Kind:   HTTPRoute
      Namespaces:
        From:  All
      Selector:
        Match Labels:
          App:  flaskapp-v1
Status:
  Addresses:
    Type:   IPAddress
    Value:  37.132.121.12
...

看到 Gateway 中已经得到了一个 IP 地址。接下来建立一个对应的 HTTPRoute 对象:

代码语言:javascript
复制
kind: HTTPRoute
apiVersion: networking.x-k8s.io/v1alpha1
metadata:
  name: flaskapp-v1
  labels:
    app: flaskapp-v1
spec:
  hostnames:
  - "v1.microservice.xyz"
  - "v1.microservice.rocks"
  rules:
  - forwardTo:
    - serviceName: flaskapp-v1
      port: 80

这个里面我们用了一个多余的域名:v1.microservice.rocks,看看运行结果:

代码语言:javascript
复制
$ http http://v1.microservice.xyz/env/VERSION
HTTP/1.1 200 OK
...
Server: nginx/1.15.3
Via: 1.1 google

v1

$ http http://v1.microservice.rocks/env/VERSION
HTTP/1.1 404 Not Found
...
Via: 1.1 google

default backend - 404

这里看到,“超纲”的域名会返回 404,被缺省后端截获。如果更换一个命名空间来创建 HTTPRoute 来引用 Gateway,会发现虽然在 Gateway 中定义了 namespaces.from: "All",但是仍旧会返回 404describe httproute 一下会发现,spec.gateways.allow 缺省被设置为 SameNamespace,因此显式定义 spec.gateways.allow=All,就能正常访问了。

分流

HTTPRoute 的 spec.rules 是一个数组,实际上这是一个分流支持,例如我们如此定义:

代码语言:javascript
复制
  rules:
  - forwardTo:
    - serviceName: flaskapp-v1
      port: 80
  - forwardTo:
    - serviceName: flaskapp-v2
      port: 80

然后循环测试,会发现 v1v2 在一定时间内会交替出现。forwardTo 还有一个 weight 属性,这个数字决定了流量在不同转发目标之间的分配比例。

GKE 的分流好像比较弱,一百个请求测试,有时分配也并不明显。

条件分支

多个 Rule 之间还可以使用条件进行分流,例如:

代码语言:javascript
复制
  rules:
  - forwardTo:
    - serviceName: flaskapp-v1
      port: 80
  - forwardTo:  
    - serviceName: flaskapp-v2
      port: 80
    matches:
    - headers:
        type: Exact
        values:
          version: v2

测试一下有无特定 Header 的结果:

代码语言:javascript
复制
$ http http://v1.microservice.xyz/env/VERSION version:v2
...
v2

$ http http://v1.microservice.xyz/env/VERSION
...
v1

其他

在直接的 forwardTo 之外,Gateway API 还可以通过 Filter 的方式支持扩展能力,这个能够在转发之前进行流量处理的功能分为三种层级:

  • Core:所有实现者都必须实现该能力,例如 RequestHeaderModifier
  • Extended:建议实现这个层级的能力,例如 RequestMirror
  • Custom:实现者可以在这个层级实现各种扩展能力,如果多个厂商都实现了该功能,则可能升级到 Extended 或者 Core。

GKE 的公共 Gateway 并不支持流量复制,现阶段也不提供 TCP/UDP 的支持,可能需要靠其它控制器来实现。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-07-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 伪架构师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概念层次
    • GatewayClass
      • Gateway
        • Route
        • 举个栗子
          • 分流
            • 条件分支
            • 其他
            相关产品与服务
            SSL 证书
            腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档