K8S NGINX Ingress如何实现全局限速
最近我需要在生产系统上为 Kubernetes 部署实施全局速率限制。有许多解决方案,例如 Azure WAF,它提供速率限制,但它们都是针对每个客户端的速率限制,这意味着我们应用的任何规则都将应用于单个客户端,这是进行速率限制的一种方式,但我们需要全局速率-也有限制。
Image from https://articles.bplans.com
为什么要进行全局速率限制?
事实证明,最著名的速率限制方法是Per Client Rate Limiting。根据 Azure 支持,由于 DDoS 保护,我们不需要全局速率限制。只有当我们看到大量非法流量试图到达服务器时,DDoS 才会生效。但是,如果我们的应用程序无法提供大量合法流量怎么办?这就是全局速率限制发挥作用的地方。它保护我们免受两件事的伤害。
- 由于无法控制的合法流量,应用程序没有响应
- 由于大量合法流量导致意外扩展,基础设施成本飙升——应用扩展限制是实现这一目标的一种方法,但全局速率限制可能是一种故障保护。
可用于全局速率限制的解决方案
我的要求是在不向系统添加新跃点的情况下对现有基础设施实施全局速率限制,这意味着我必须对系统上已有的某些组件实施全局速率限制。在互联网上搜索了几个小时并没有给我一个很好的解决方案,并且鉴于 Azure WAF 不支持全局速率限制,唯一的选择是在 NGINX Ingress 控制器上实施全局速率限制。
然而,使用 NGINX Ingress控制器实现全局速率限制需要一个额外的memcached
pod 来同步 NGINX pod 之间的计数器。在与 Kubernetes Slack 社区交谈后,我发现任何全局速率限制的方法都会在性能上造成严重的瓶颈,这排除了这种方式作为进行全局速率限制的选项。
ngx_http_limit_req_module
经过进一步搜索,我发现了以下文章,这些文章解释了如何将 NGINX http_limit_req 模块与 Kubernetes Ingress Controller 一起使用(这似乎是唯一一篇关于如何使用 K8s 执行此操作的博客文章)
上述帖子中提到的方法有两个主要问题。
- 这实现了Per NGINX Pod Rate Limiting
- 此模块还实现了每个客户端速率限制
问题 1 是我不得不忍受的,因为很明显,真正的全局速率限制不再可行。但是,对于问题 2,我已经对 Azure WAF 进行了每客户端速率限制,因此这种方法没有产生任何结果。
Time to get Creative
似乎缺少有关 ngx_http_limit_req_module 的文档,但是,NGINX 对此有一个非常好的文档(不是 NGINX K8 控制器,而是普通 NGINX)
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
location /login/ {
limit_req zone=mylimit;
proxy_pass http://my_upstream;
}
}
上面的示例在每个用户的 /login/ 端点上实现了每秒 10 个请求的速率限制。
由于这是每个客户端的速率限制,我想对其进行修补以实现每个pod 的全局速率限制。阅读文档对上述命令参数解释如下
limit_req_zone <key> zone=<zone_name>:<allocated_memory> rate=<rate_limit>
如何用 K8s 实现
那是互联网上没有太多信息的另一部分。K8s NGINX Ingress 控制器包含一组用于速率限制的注释,例如nginx.ingress.kubernetes.io/limit-connections , nginx.ingress.kubernetes.io/limit-rps (
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#rate-limiting)。但是这些再次创建了每个客户端速率限制,而不是全局限制。
因此,要实现这一点,您必须使用另一种解决方法。那就是使用自定义代码将外部 configmap 挂载到你的 K8s 部署中。
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-ingress-ingress-nginx-controller
namespace: ingress-basic
data:
http-snippet : |
limit_req_zone $binary_remote_addr zone=rd_ingress-hello_rps:5m rate=100r/m ;
location-snippet: |
limit_req zone=rd_ingress-hello_rps burst=20 nodelay;
limit_req_status 429;
上面的 ConfigMap 将在您的 K8 NGINX Ingress Controller 上创建一个Per Pod Global Rate Limit(作用于每个Pod的限速)。
或者,如果您的应用程序中需要多个不同Ingress限速资源,您可以删除上述 location-snippet 并将其作为configuration-snippet 添加到Ingress资源中。它将允许您为每个Ingress资源添加全局速率限制。但是请注意,您应用的限制将单独应用于您拥有的所有Ingress副本。
例如:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
limit_req zone=mgt burst=20 nodelay;
limit_req_status 503;
spec:
tls:
- hosts:
- test.com
rules:
- host: test.com
http:
paths:
- path: /
backend:
serviceName: test-service
servicePort: 9443
原文链接 https://faun.pub/global-rate-limiting-with-kubernetes-nginx-ingress-controller-fb0453447d65