HTNN 初体验:使用 Istio API 和 Gateway API 借助 Redis 完成动态限流
HTNN 是 MOSN 社区基于 MoE(MOSN on Envoy)架构开源的新产品,我们将通过系列文章来展开介绍。本文作为第二篇,展示:
1. 如何仅使用若干行命令,即可安装 HTNN 并使用 Gateway API 配置路由和策略
2. HTNN 是如何借力 Go 生态实现基于 Redis 的复杂限流功能
GitHub: https://github.com/mosn/htnn
1
前提条件
Kubernetes 1.26.0 或更高版本。推荐使用 kind [1] 在本地快速搭建 Kubernetes 集群。
Helm 3.6 或更高版本。安装 Helm 请参考 Helm 安装指南。
https://helm.sh/docs/intro/install/
配置 helm 仓库地址。执行以下命令添加仓库:
helm repo add htnn https://mosn.github.io/htnn2
安装 HTNN
让我们把 HTNN 安装到 istio-system namespace 中。为了简单起见,HTNN 和其他用于 demo 的资源都会安装到该 namespace。
1. 更新仓库信息以获取最新的版本:
helm repo update2. 安装控制面组件:
$ helm install htnn-controller htnn/htnn-controller \--set global.hub=m.daocloud.io/ghcr.io/mosn \--namespace istio-system --create-namespace --debug --wait...NAME: htnn-controllerLAST DEPLOYED: Wed May 29 18:42:18 2024NAMESPACE: istio-systemSTATUS: deployedREVISION: 1TEST SUITE: None
3. 安装数据面组件:
$ helm install htnn-gateway htnn/htnn-gateway --namespace istio-system --create-namespace && \kubectl wait --timeout=5m -n istio-system deployment/istio-ingressgateway --for=condition=Available...NAME: htnn-gatewayLAST DEPLOYED: Wed May 29 19:59:22 2024NAMESPACE: istio-systemSTATUS: deployedREVISION: 1TEST SUITE: None
这里我们没有使用--wait参数,而是使用kubectl wait命令等待istio-ingressgateway部署完成。因为 kind 默认不支持 LoadBalancer 类型的 Service,所以 Serviceistio-ingressgateway的 ExternalIP 会一直处于Pending状态。这不影响我们的上手体验。如果你对此感兴趣,可以参考 kind 官方文档[2]以及安装 metallb。
3
配置路由
安装完 HTNN 后,让我们体验下它的功能。
在本指南中,我们将展示 HTNN 基于 Redis 的限流能力。为此,让我们先部署一个 Redis 服务:
kubectl apply -f https://raw.githubusercontent.com/mosn/htnn/main/examples/quick_start/redis.yaml && \kubectl wait --timeout=5m -n istio-system deployment/redis --for=condition=Available
我们还需要部署一个后端服务,这里我们使用一个简单的 echo 服务:
kubectl apply -f https://raw.githubusercontent.com/mosn/htnn/main/examples/quick_start/backend.yaml && \kubectl wait --timeout=5m -n istio-system deployment/backend --for=condition=Available
接下来,我们需要配置路由规则,将请求转发到后端服务:
kubectl apply -f https://raw.githubusercontent.com/mosn/htnn/main/examples/quick_start/route.yaml一切准备就绪,我们就可以应用 HTNN 自己的策略了:
kubectl apply -f - <<EOFapiVersion: htnn.mosn.io/v1kind: FilterPolicymetadata:name: policynamespace: istio-systemspec:targetRef:group: networking.istio.iokind: VirtualServicename: vsfilters:limitCountRedis:config:prefix: gateway-default-vsaddress: "redis:6379"rules:- count: 1timeWindow: "60s"key: |request.header("User") != "" ? request.header("User") : source.ip()EOF
这个策略在路由上添加了limitCountRedis插件。该插件使用 Go 实现,支持 Redis 作为限流存储。在这个例子中,我们限制每个用户每分钟最多访问 1 次。用户的标识是User请求头中的值,如果没有就按客户端 IP 限流。你可以在插件文档[3]查看更多关于limitCountRedis插件的信息。
4
验证配置
先通过 status 检查下策略是否被接受:
$ kubectl -n istio-system get filterpolicies.htnn.mosn.io policy -o yaml...status:conditions:...message: The policy has been acceptedobservedGeneration: 1reason: Accepted
让我们在一个终端上执行 port-forward,让本地的客户端可以访问到 k8s 里面的服务:
kubectl port-forward -n istio-system pod/"$(kubectl -n istio-system get pods | grep '^istio-ingressgateway' | cut -d' ' -f 1)" 18000:18000在另一个终端上,我们可以通过 18000 端口访问到 HTNN:
$ curl --resolve default.local:18000:127.0.0.1 'http://default.local:18000/' -iHTTP/1.1 200 OK...$ curl --resolve default.local:18000:127.0.0.1 'http://default.local:18000/' -iHTTP/1.1 429 Too Many Requests...# 切换到另一个用户$ curl --resolve default.local:18000:127.0.0.1 'http://default.local:18000/' -i -H "User: someone else"HTTP/1.1 200 OK...$ curl --resolve default.local:18000:127.0.0.1 'http://default.local:18000/' -i -H "User: someone else"HTTP/1.1 429 Too Many Requests...
可以看到限流逻辑已经生效。
5
使用 Gateway API 配置
HTNN 也支持使用 Gateway API 配置。目前 Gateway API 的 CRD 需要单独安装:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml让我们用 Gateway API 创建路由规则,将请求转发到后端服务:
kubectl apply -f https://raw.githubusercontent.com/mosn/htnn/main/examples/quick_start/route_gateway_api.yaml接下来应用 HTNN 自己的配置到由 Gateway API 创建的路由上:
kubectl apply -f - <<EOFapiVersion: htnn.mosn.io/v1kind: FilterPolicymetadata:name: policy-gateway-apinamespace: istio-systemspec:targetRef:group: gateway.networking.k8s.iokind: HTTPRoutename: routefilters:limitCountRedis:config:prefix: gateway-default-routeaddress: "redis:6379"rules:- count: 1timeWindow: "60s"key: |request.header("User") != "" ? request.header("User") : source.ip()EOF
这个策略和前面的一模一样,只是在 targetRef 里指向了 Gateway API 资源。
继续通过 status 检查下策略是否被接受:
$ kubectl -n istio-system get filterpolicies.htnn.mosn.io policy-gateway-api -o yaml...status:conditions:...message: The policy has been acceptedobservedGeneration: 1reason: Accepted
让我们在一个终端上执行 port-forward,让本地的客户端可以访问到 k8s 里面的服务:
kubectl port-forward -n istio-system pod/"$(kubectl -n istio-system get pods | grep '^default-istio' | cut -d' ' -f 1)" 18001:18001在另一个终端上,我们可以通过 18001 端口访问到 HTNN:
$ curl --resolve default.local:18001:127.0.0.1 'http://default.local:18001/' -iHTTP/1.1 200 OK...$ curl --resolve default.local:18001:127.0.0.1 'http://default.local:18001/' -iHTTP/1.1 429 Too Many Requests...
6
卸载 HTNN
helm uninstall htnn-controller -n istio-system && \helm uninstall htnn-gateway -n istio-system && \kubectl delete ns istio-system
7
参考链接
[1] Kind:
https://kind.sigs.k8s.io/
[2] kind 官方文档:
https://kind.sigs.k8s.io/docs/user/loadbalancer/
[3] 插件文档:
https://github.com/mosn/htnn/blob/main/site/content/zh-hans/docs/reference/plugins/limit_count_redis.md
欢迎大家加入社区与我们交流
GitHub
https://github.com/mosn/htnn
微信群
请微信添加 HTNN 小助手:spacewander_lzx
注明“HTNN”
钉钉群