为什么 Higress 是 Knative 入口网关的最佳实践

简介: Knative Serving 是一款基于 K8s 的 Serverless 开源平台,用于构建和管理现代化、可拓展、流量驱动、无服务器的应用程序。本文重点关注 Knative 网络层能力的实现。

1.背景


在传统的应用开发中,通常需要管理底层的基础设施、服务器与网络配置等方面的工作。然而在云原生 Serverless 化的浪潮下,这些基础设施的细节被抽象和自动化,开发者无需关注服务器等配置、扩展、监控和维护等工作,可以更专注于应用程序的业务逻辑和功能开发。Serverless 架构的价值在于提供高效、弹性、无服务器管理、服务按需付费、快速部署与迭代、以及高可扩展性等优势,降低开发和运维的复杂性,提高开发效率和应用程序的质量。


Knative Serving 是一款基于 K8s 的 Serverless 开源平台,用于构建和管理现代化、可拓展、流量驱动、无服务器的应用程序。Knative Serving 提供了诸多特性来支持用户部署 Serverless 服务,如基于 HTTP 流量触发 pod 的自动扩缩容、服务版本修订、自动流量管理、故障恢复等。    


来源:https://knative.dev/docs/serving/architecture/


Knative 整体架构如上层所示,Controller 和 DomainMapping 等组件等负责管理 KnativeCRD 资源的生命周期,其弹性能力由核心的 Activator、Autoscaler 和 Queue-Proxy 等组件提供。网络和路由能力依赖各类 Ingress Gateway 提供。


本文重点关注 Knative 网络层能力的实现。Knative 网络层能力需要依赖 Knative Ingress CRD 与其他网络层组件实现。目前,Knative 官方提供了基于 Contour、Istio 和 Kourier 等作为其网络层组件,提供有限的网络能力,如基本的路由、认证鉴权和 TLS 等,可以满足基本的路由和安全要求。Higress 是安全、流量和微服务三合一的云原生网关,使用 Higress 作为 Knative 服务的流量入口能够获得更强的流量治理、安全防护、可观测和可扩展能力。



2.Knative 网络层工作原理


接下来我们以 Net-Istio 为例,介绍 Knative Serving 通过网络层实现服务对外发布的过程。Net-istio 网络层将数据面与控制面进行分离。数据面采用 Envoy,负责处理网络流量。控制面负责管理与配置数据面,支持对网关的动态配置和管理。



当有 KService 被部署的时候,Knative Serving Controller 将解析 Kservice 中的路由项并生成对应的 KIngress 资源。KIngress 是 Knative 的 CRD,其资源中包含了服务对外披露所需的所有信息,示例如下:


apiVersion: networking.internal.knative.dev/v1alpha1
kind: Ingress
metadata:
  annotations:
    networking.knative.dev/ingress.class: istio.ingress.networking.knative.dev #指定istio作为网络层
  name: hello
  namespace: default
spec:
  httpOption: Enable #用于定义是否开启HTTPS重定向
  rules:
  - hosts:
    - hello.default.example.com
    http:
      paths:
      - splits: #Split定义了流量按百分比分配分配到不同的服务修订上。
        - appendHeaders:
            Knative-Serving-Namespace: default
            Knative-Serving-Revision: hello-00001
          percent: 100
          serviceName: hello-00001
          serviceNamespace: default
          servicePort: 80
    visibility: ExternalIP  #定义服务是仅集群内可访问还是对外披露。
  tls:  #指定通过HTTPS协议披露Kservice时使用的证书及密钥。
  - hosts:
    - hello.default.example.com
    secretName: route-ecbe0df2-101a-4aa4-8cf9-f2e98773fcdf
    secretNamespace: default


以 Istio 作为网络层为例,Net-Istio 组件监听集群中的 Kingress资源。每次 Kingress 被创建、删除或者修改的时候,Net-Istio 会同步解析 Kingress 资源,将 KIngress 的路由配置转换为 Istio 的 Virtual Service 和 Gateway 等资源。Istio 监听 VirtualService,并通过 xDS 下发路由配置给数据面 Envoy,从而完成路由配置的传递。


Envoy 接收到这个路由目标集群的 EDS 数据后,根据 Service 关联到的 Endpoint 的 IP 将请求转发给 Activator Pod 或者 Revision Pod。处于冷启动状态或者缩容状态时,Knative Controller 会将 Service 关联到的 Endpoint 设置为 Activator 的 Pod IP;处于稳定态时,Service 关联的 Endpoint 将被设置为用户部署的 Revision Pod IP。


理顺 Knative 网络层的工作原理后,我们可发现在 Knative 网络层中控制面实际承担的功能如下:

  1. 监听并获取 Knative Service 产生的 KIngress 资源。
  2. 将 KIngress 资源映射为数据面 Envoy 配置信息。
  3. 将配置信息披露给其管理的 Envoys。


不同的 Knative 网络层控制面通过自身机制完成路由配置的转化和传递,实现基本的路由能力。但在更复杂的应用场景下,现有网络层可能无法完全满足诸如安全、认证、可观测、细粒度流量治理与可扩展等方面的需求。一个解决的思路是在 Knative 网络层之上继续集成诸如安全网关、流量网关与可观测平台等组件,但多层网关的设计无疑会占用更多运行资源、增加运维成本。


3.Higress 适配 Knative Serving 方案


为了拓展 Knative 对各种场景的适应能力,叠加多层网关显然不是最好的选择。Higress 云原生网关作为集安全、流量、微服务三位于一体的下一代云上网关,使用 Higress 作为 Knative 服务的流量入口能够获得更强的流量治理、安全防护、可观测与可拓展能力,在稳定性、安全性上更有保证。目前,Higress 可以通过两种方式适配 Knative Serving,并在控制面能力进行了增强。


方案一:Higress+KIngress



本方案适配 Knative Serving 的工作原理与其他 Knative 网络层类似,包含 KIngress 的监听与更新、路由配置的转换与数据面配置推送等过程。与此同时,Higress 兼容了 Knative Serving 网络层的所有特性,如不同服务修订间的流量划分、TLS、超时、重试、流量打标、自动端点发现等,确保 Knative 服务能够轻松使用 Higress 作为其流量入口。


值得一提的是,在此方案中,Higress 脱离了对其他自定义资源的依赖,只依赖于 Knative Serving 管理的 KIngress 资源与 K8s 集群通用资源如 endpoints,secrets 等,以一种更加“原生”的方式适配了 Knative。


得益于与微服务技术栈的良好集成和 WASM 扩展机制,Higress 能够为 Knative 服务提供诸如认证鉴权、限流、Waf 防护与可观测等更强大的能力。Serverless 服务开发者将无需关注基本能力的实现,只需关注于开发自己的业务逻辑。Higress 推出插件市场,在满足基本的安全、限流、认证鉴权等需求的同时,开放了自定义插件的接口,帮助用户更好的适配自身的 Serverless 应用。


方案二:Higress+IstioCRD

Higress 可以通过自己对 IstioCRD 的兼容能力来代替 Istio 成为 Knative 网关的控制面。具体方案如下图所示。不难看出,本方案是基于 Higress 对 IstioCRD 的兼容能力,通过 net-istio-controller 完成路由配置向 IstioCRD 的转化,Higress Controller 解析 IstioCRD 资源并进行配置的数据面下发,从而完成路由配置的传递。



方案比较

Higress+Kingress 与 Higress+IstioCRD 都可以实现 Knative 网络层的能力,并兼容 Higress 在流量治理、安全防护、可观测和可扩展等方面的大部分能力。Istio 是个优秀的服务网格解决方案,但如果在应用场景中不需要服务网格,IstioCRD 反而会给集群带来额外的复杂度与资源消耗。而 Higress+KIngress 方案脱离了对其他自定义资源的依赖,以一种更加“原生”的方式适配了 Knative 且能力不打折。


4.Higress 对接 Knative 服务实践


4.1前提条件

  1. 已安装 kubectl[1]、Helm[2]、Knative CLI (kn)[3]
  2. 已有 K8s 集群,版本在 Kubernetes v1.24 或以上。为演示方便,本文在本地 K8s 集群上进行实践。
  3. 安装 Knative CRD 与 Knative Serving 组件,详情可参考 Knative 安装指南[4]
  4. 安装 Higress[5]

📌注:Higress Controller 部署时会进行 Knative CRD 检查,安装 Higress 前请确认 KnativeCRD 已经安装。

4.2方案一:Higress+KIngress


配置 Knative 与 Higress 的适配项


1. 配置 Knative 使用 Higress 作为 Ingress :


kubectl patch configmap/config-network \
  --namespace knative-serving \
    --type merge \
      --patch '{"data":{"ingress-class":"higress"}}'


2. Knative 默认的路由策略是围绕域名展开的,需要设置 Knative 域名:


kubectl edit configmap config-domain -n knative-serving


通过编辑 configmap 中的 data 项来修改默认域名。本实践将默认域名修改为 example.com。该修改生效后,所有的 Knative 服务与路由将自动更新域名。


apiVersion: v1
data:
  example.com: ""
kind: ConfigMap


3. 确认 Higress 对 Knative 资源的 RBAC 权限:


kubectl get clusterrole higress-controller-higress-system -o yaml


RBAC 权限列表中应有下列字段,如没有请通过 kubectl edit 命令手动添加:


apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
rule:
 ...
- apiGroups:
  - networking.internal.knative.dev
  resources:
  - ingresses
  verbs:
  - get
  - watch
  - list
- apiGroups:
  - networking.internal.knative.dev
  resources:
  - ingresses/status
  verbs:
  - get
  - patch
  - update


完成上述配置后,即可使用 higress 无缝对接 Knative 服务。


Higress 兼容 Knative 网络层特性功能验证


1. 部署 Knative 服务

kn service create hello \
--image ghcr.io/knative/helloworld-go:latest \
--port 8080 \
--env TARGET=World


#Expected Output
Service hello created to latest revision 'hello-00001' is available at URL: 
http://hello.default.${LOADBALANCER_IP}.example.com
#其中${LOADBALANCER_IP}即为Higress Gateway IP,本地k8s集群部署时为空。


2. 验证 Knative AutoScaling

向 Hello 服务发送请求:


#本地部署时,LOADBALANCER_IP为127.0.0.1,此处通过No DNS的方式模拟
curl -H "host: hello.default.example.com" http://${LOADBALANCER_IP}
#Expected Output
Hello World!


通过下列命令观察 AutoScaling 过程:


kubectl get pod -l serving.knative.dev/service=hello -w


可以观察到请求转发到 Hello Service 上时触发了扩容过程,当一段时间没有请求时,Pod 数量自动缩容到 0:


NAME                                      READY   STATUS              RESTARTS   AGE
hello-00001-deployment-689c99c59b-6f5fw   0/2     Pending             0          0s
hello-00001-deployment-689c99c59b-6f5fw   0/2     ContainerCreating   0          0s
hello-00001-deployment-689c99c59b-6f5fw   1/2     Running             0          1s
hello-00001-deployment-689c99c59b-6f5fw   2/2     Running             0          1s
hello-00001-deployment-689c99c59b-6f5fw   2/2     Terminating         0          62s
hello-00001-deployment-689c99c59b-6f5fw   1/2     Terminating         0          91s
hello-00001-deployment-689c99c59b-6f5fw   0/2     Terminating         0          92s


3. 验证 Knative Traffic Splitting

KIngress 定义的 Traffic Splitting 特性负责管理不同 Knative 服务修订(Revision)间的流量划分规则。这个特性可以用于 Knative 服务蓝绿发布与灰度部署。Revision 是应用程序代码和配置的即时快照。每次更改 Knative 服务的配置时,都会创建一个新的修订。当有新修订发布时,Higress 会根据 KIngress 中的路由规则在 Knative 服务的不同版本之间划分流量。


创建 Hello 服务新的修订:


kn service update hello --env TARGET=Knative


#Expected Output   
Service 'hello' created to latest revision 'hello-00002' is available at URL:
http://hello.default.${LOADBALANCER_IP}.example.com


设置不同修订的流量百分比,其中 hello-00001 的流量百分比为 50%,hello-00002 的流量百分比为 50%。


kn service update hello --traffic hello-00001=50  --traffic @latest=50


多次向 Hello 服务发送请求,可以观察到流量被划分到两个不同的 Revision 上,并且比例满足设定的流量比例:


#Expected Output   
Hello Knative!
Hello World!
Hello Knative!
Hello World!


基于 Higress 插件增强 Knative 网络层能力


前文提到,Higress 能够为 Knative 服务提供诸如认证鉴权、限流、Waf 防护与可观测等更强大的能力。在本节实践中我们将结合 Higress 插件市场中的 key-auth 和 key-rate-limit 插件来简要演示 Higress 作为 Knative 网络层能够提供的认证鉴权和限流的能力。


1. 验证 Higress 对 Knative 服务的限流能力

设置限流规则,部署 key-rate-limit 插件。详情可参考基于 Key 限流[6]


apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
  name: key-rate-limit
  namespace: higress-system
spec:
  defaultConfig:
    _rules_:
    # 规则二:按域名匹配生效
    - _match_domain_:
      - "hello.default.example.com"
      limit_by_header: x-ca-key
      limit_keys:
      - key: 123456
        query_per_minute: 2
  url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/key-rate-limit:1.0.0


上述配置具体含义如下,含请求头 “x-ca-key: 123456” 的请求速率将被限制为每分钟 3 次,1 分钟内超过 3 次的请求无法访问到 Knative 服务,该配置对 Knative 服务域名 "hello.default.example.com" 生效。我们通过如下请求进行验证:


curl -H "Host: hello.default.example.com" http://127.0.0.1 -H "x-ca-key: 123456" 
Hello World!    #正常请求到Knative服务,返回200
curl -H "Host: hello.default.example.com" http://127.0.0.1 -H "x-ca-key: 123456" 
Hello Knative!  #正常请求到Knative服务,返回200
curl -H "Host: hello.default.example.com" http://127.0.0.1 -H "x-ca-key: 123456" 
rate_limited   #触发限流,返回429


2. 验证 Higress 对 Knative 服务的认证鉴权能力

设置认证鉴权的相关规则,部署 key-auth 插件。详情可参考基于 Key 认证[7]


apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
  name: key-auth
  namespace: higress-system
spec:
  defaultConfig:
    consumers:
    - credential: 2bda943c-ba2b-11ec-ba07-00163e1250b5
      name: consumer1
    - credential: c8c8e9ca-558e-4a2d-bb62-e700dcc40e35
      name: consumer2
    keys:
    - apikey
    in_query: true
    _rules_:
    - _match_domain_:
      - "hello.default.example.com"
      allow:
      - consumer2
  url: oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/key-auth:1.0.0


上述配置具体含义如下:在用户组 consumer 中,只有 consumer2 有权访问,该配置对 knative 服务域名 "hello.default.example.com" 生效。我们通过如下请求进行验证:


curl -H "Host: hello.default.example.com" http://127.0.0.1
#请求未提供APIKey,返回401
curl -H "Host: hello.default.example.com" http://127.0.0.1/?apikey=2bda943c-ba2b-11ec-ba07-00163e1250b5
#consumer1不具备访问权限,返回403
curl -H "Host: hello.default.example.com" http://127.0.0.1/?apikey=c8c8e9ca-558e-4a2d-bb62-e700dcc40e35
Hello World!  #consumer2具备访问权限,返回200


4.3方案二:Higress+IstioCRD

除了上述 Higress+KIngress 解析的方法外,Higress 还可以基于自身对 IstioCRD 的兼容能力,通过 IstioCRD 来对接 Knative 服务。具体方式如下:


Step 1. 安装 IstioCRD


helm repo add istio https://istio-release.storage.googleapis.com/charts
helm install istio-base istio/base -n istio-system --create-namespace


启用 IstioCRD 时,需更新 Higress 的部署参数:


helm upgrade higress -n higress-system --set global.enableIstioAPI=true higress.io/higress --reuse-values


Step 2. 安装相关网络层组件


通过运行以下命令安装 Knative Istio Controller(即 net-istio-controller)


kubectl apply -f https://github.com/knative/net-istio/releases/download/knative-v1.10.1/net-istio.yaml


Step 3. 配置 Istio Config 指向 Higress


Knative 社区给出了使用非默认网关的配置,详情参见 Install Istio for Knative-Knative[8]。具体步骤:


修改 config-istio 中的 svc 为 higress-gateway:


kubectl edit configmap config-istio -n knative-serving


添加如下配置:


data:
  gateway.knative-serving.knative-ingress-gateway: higress-gateway.higress-system.svc.cluster.local
  local-gateway.knative-serving.knative-local-gateway: higress-gateway.higress-system.svc.cluster.local


更新命名空间 Knative-serving 中网关实例 knative-local-gateway 与 knative-ingress-gateway:


kubectl edit gw knative-local-gateway -n knative-serving
kubectl edit gw knative-ingress-gateway -n knative-serving


将网关实例 Knative-local-gateway 与 Knative-ingress-gateway 的 selector 下的 label 替换为 higress-gateway 的 label,higress-gateway 的默认如下:


spec:
  selector:
    app: higress-gateway
    higress: higress-system-higress-gateway


上述配置完成后,同样可以通过 Higress 实现 Knative 网络层的基本能力。


加入 Higress 社区



如果您觉得 Higress 对您有帮助,欢迎前往 github: Higress[9]为我们 star 一下!


相关链接:

[1] kubectl

[2] Helm

[3] Knative CLI (kn)

[4] Knative 安装指南

[5] Higress

[6] 基于 Key 限流

[7] 基于 Key 认证

[8] Install Istio for Knative-Knative

[9] github: Higress

作者介绍
目录