作者:赵伟基(兆维)
在传统的应用开发中,通常需要管理底层的基础设施、服务器与网络配置等方面的工作。然而在云原生 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 服务的流量入口能够获得更强的流量治理、安全防护、可观测和可扩展能力。
接下来我们以 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 网络层中控制面实际承担的功能如下:
不同的 Knative 网络层控制面通过自身机制完成路由配置的转化和传递,实现基本的路由能力。但在更复杂的应用场景下,现有网络层可能无法完全满足诸如安全、认证、可观测、细粒度流量治理与可扩展等方面的需求。一个解决的思路是在 Knative 网络层之上继续集成诸如安全网关、流量网关与可观测平台等组件,但多层网关的设计无疑会占用更多运行资源、增加运维成本。
为了拓展 Knative 对各种场景的适应能力,叠加多层网关显然不是最好的选择。Higress 云原生网关作为集安全、流量、微服务三位于一体的下一代云上网关,使用 Higress 作为 Knative 服务的流量入口能够获得更强的流量治理、安全防护、可观测与可拓展能力,在稳定性、安全性上更有保证。目前,Higress 可以通过两种方式适配 Knative Serving,并在控制面能力进行了增强。
本方案适配 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 的兼容能力来代替 Istio 成为 Knative 网关的控制面。具体方案如下图所示。不难看出,本方案是基于 Higress 对 IstioCRD 的兼容能力,通过 net-istio-controller 完成路由配置向 IstioCRD 的转化,Higress Controller 解析 IstioCRD 资源并进行配置的数据面下发,从而完成路由配置的传递。
Higress+Kingress 与 Higress+IstioCRD 都可以实现 Knative 网络层的能力,并兼容 Higress 在流量治理、安全防护、可观测和可扩展等方面的大部分能力。Istio 是个优秀的服务网格解决方案,但如果在应用场景中不需要服务网格,IstioCRD 反而会给集群带来额外的复杂度与资源消耗。而 Higress+KIngress 方案脱离了对其他自定义资源的依赖,以一种更加“原生”的方式适配了 Knative 且能力不打折。
注:Higress Controller 部署时会进行 Knative CRD 检查,安装 Higress 前请确认 KnativeCRD 已经安装。
kubectl patch configmap/config-network \
--namespace knative-serving \
--type merge \
--patch '{"data":{"ingress-class":"higress"}}'
kubectl edit configmap config-domain -n knative-serving
通过编辑 configmap 中的 data 项来修改默认域名。本实践将默认域名修改为 example.com。该修改生效后,所有的 Knative 服务与路由将自动更新域名。
apiVersion: v1
data:
example.com: ""
kind: ConfigMap
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 服务。
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 服务提供诸如认证鉴权、限流、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
设置认证鉴权的相关规则,部署 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
除了上述 Higress+KIngress 解析的方法外,Higress 还可以基于自身对 IstioCRD 的兼容能力,通过 IstioCRD 来对接 Knative 服务。具体方式如下:
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
通过运行以下命令安装 Knative Istio Controller(即 net-istio-controller)
kubectl apply -f https://github.com/knative/net-istio/releases/download/knative-v1.10.1/net-istio.yaml
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 网络层的基本能力。
阿里云产品评测活动
邀请您参与下一代网关评测,可降低 50% 资源开销,展现技术和架构先进性,参与评测赢取猫超卡、Cherry 机械键盘,优秀文章还能署名发布到阿里开发者和阿里云云原生公众号。
进入链接立即参与:
https://developer.aliyun.com/mission/higress
相关链接:
[1] kubectl
https://kubernetes.io/docs/tasks/tools/
[2] Helm
https://helm.sh/
[3] Knative CLI (kn)https://knative.dev/docs/getting-started/quickstart-install/#install-the-knative-cli
[4] Knative 安装指南
https://knative.dev/docs/install/yaml-install/serving/install-serving-with-yaml/#install-the-knative-serving-component
[5] Higress
https://higress.io/zh-cn/docs/ops/deploy-by-helm/
[6] 基于 Key 限流https://higress.io/zh-cn/docs/plugins/key-rate-limit/
[7] 基于 Key 认证
https://higress.io/zh-cn/docs/plugins/key-auth/
[8] Install Istio for Knative-Knative
https://knative.dev/docs/install/installing-istio/#configuring-the-installation
[9] github: Higresshttps://github.com/alibaba/higress