Istio-限流配置
装载了 istio 之后,会默认安装 istio-ingress-gateway,这个组件的能力在 ingress-nginx 之上添加了很多其他的能力底层使用的 envoy 进行网络的转发和配置,包括 sidecar 底层同样使用 envoy 去实现,然后加上了配置同步 安全验证等相关功能。
# --------------------------------------------
# 0) Redis 密码放 Secret(更安全)
# 用 Secret 存放敏感信息(如 Redis 密码),避免明文进入镜像或 Pod 环境变量历史
# --------------------------------------------
apiVersion: v1
kind: Secret
metadata:
name: ratelimit-redis-secret # Secret 名称,后续 Deployment 通过 secretKeyRef 引用
namespace: istio-system # 放在与 ratelimit 服务相同的命名空间,便于引用与管理
type: Opaque
stringData:
REDIS_AUTH: "password" # 明文由 K8s 负责 base64 编码存储
---
# --------------------------------------------
# 1) Ratelimit 配额配置(Envoy Ratelimit Server 的运行时配置)
# - 该 ConfigMap 被容器以只读方式挂载到 /data/ratelimit/config
# - domain 必须与 Envoy HTTP 过滤器里的 domain 完全一致,否则不会命中
# - descriptors 用来描述限流的“维度组合”(actions 组合后形成的描述符)
# --------------------------------------------
apiVersion: v1
kind: ConfigMap
metadata:
name: ratelimit-config
namespace: istio-system
data:
config.yaml: |
domain: ingress-ratelimit # 必须与 RateLimit 过滤器的 domain 一致
descriptors:
- key: header_match # 顶层 key:与 HTTP_ROUTE 中的 header_value_match 对应(actions 1/2)
value: path-api # 顶层 value:来自路由上 actions 的 descriptor_value
descriptors: # 二级描述符:继续细分 (组合成唯一的限流键)
- key: generic_key # 与 HTTP_ROUTE 中 generic_key 对应(actions 2/2)
value: istio-limit-v1 # 对应路由里设置的 descriptor_value
rate_limit:
unit: second # 时间单位:second / minute / hour / day
requests_per_unit: 5 # 配额:单位时间内允许的请求数(此处为 1 秒 1 次)
---
# --------------------------------------------
# 2) Ratelimit Service(连接你现有 Redis 单机)
# - 通过 envoyproxy/ratelimit 实现全局滑窗/令牌桶限流的配置服务
# - replicas=1:测试环境单副本;生产建议至少 2-3 副本并配合 Redis 高可用
# - readiness/liveness:通过 6070 端口健康检查
# - 关键环境变量:REDIS_URL / REDIS_AUTH / RUNTIME_ROOT / RUNTIME_SUBDIRECTORY
# --------------------------------------------
apiVersion: v1
kind: Service
metadata:
name: ratelimit # 供 Envoy 通过集群名解析 (outbound|8081||ratelimit.istio-system.svc.cluster.local)
namespace: istio-system
spec:
selector: { app: ratelimit } # 与 Deployment 的 labels 匹配
ports:
- name: grpc
port: 8081 # gRPC 服务端口(Envoy RateLimit 过滤器将连此端口)
targetPort: 8081
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ratelimit
namespace: istio-system
spec:
replicas: 1 # 测试设 1,生产建议 ≥3 并做好 HPA/PodDisruptionBudget
selector:
matchLabels: { app: ratelimit }
template:
metadata:
labels: { app: ratelimit }
spec:
containers:
- name: ratelimit
image: envoyproxy/ratelimit:875d418c # 指定 commit/tag,保证版本可重现;可考虑升级到官方较新 tag
imagePullPolicy: IfNotPresent
command: ["/bin/ratelimit"] # 启动入口
ports:
- containerPort: 8080 # HTTP Admin(可选:metrics/调试)
- containerPort: 8081 # gRPC 主服务端口
- containerPort: 6070 # 健康检查端口(/healthcheck)
env:
- name: REDIS_SOCKET_TYPE
value: tcp # 通过 TCP 连接 Redis
- name: REDIS_URL
value: "redis://1.1.1.1:6379"# 你的 Redis 地址(生产建议内网域名 + 哨兵或集群)
- name: REDIS_POOL_SIZE
value: "20" # 连接池大小;视并发/副本数调优
- name: REDIS_AUTH
valueFrom:
secretKeyRef:
name: ratelimit-redis-secret # 从 Secret 注入密码,避免明文
key: REDIS_AUTH
- name: USE_STATSD
value: "false" # 如有 statsd/Prometheus sidecar 可打开
- name: RUNTIME_ROOT
value: /data # 对应挂载点根目录
- name: RUNTIME_SUBDIRECTORY
value: ratelimit # 子目录,最终配置路径 /data/ratelimit/config
- name: RUNTIME_IGNOREDOTFILES
value: "true" # 忽略隐藏文件
volumeMounts:
- name: config
mountPath: /data/ratelimit/config # 与上面 runtime 路径一致,确保装载到 config 子目录
readinessProbe:
httpGet:
path: /healthcheck
port: 6070
initialDelaySeconds: 2 # 初始延迟,避免冷启动误判
periodSeconds: 5 # 探测频率
livenessProbe:
httpGet:
path: /healthcheck
port: 6070
initialDelaySeconds: 10
periodSeconds: 10
volumes:
- name: config
configMap:
name: ratelimit-config # 装载上面的 ConfigMap
---
# --------------------------------------------
# 3) IngressGateway 注入全局 RateLimit 过滤器 + 指向 ratelimit 的 CLUSTER
# - 通过 EnvoyFilter 在 HTTP Router 之前插入全局 ratelimit HTTP 过滤器
# - workloadSelector:限定只作用于网关工作负载(label: istio=ingressgateway)
# - rate_limit_service:连到上面定义的 ratelimit gRPC(通过集群名/authority)
# - 追加一个 Lua 响应过滤器:当后端返回 429 时,改写为统一 JSON
# --------------------------------------------
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: gateway-global-limit-filter
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway # 只作用在 IngressGateway 实例
configPatches:
# 3.1 在 router 之前插入 ratelimit HTTP 过滤器(全局生效)
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager # HTTP 连接管理器
subFilter:
name: envoy.filters.http.router # 在 Router 之前插入
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.ratelimit
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
domain: ingress-ratelimit # 必须与 ConfigMap 里的 domain 一致
failure_mode_deny: false # 后端 ratelimit 服务异常时是否拒绝请求;false=放行(推荐)
timeout: 10s # 访问 ratelimit 服务的超时
rate_limit_service:
grpc_service:
envoy_grpc:
cluster_name: outbound|8081||ratelimit.istio-system.svc.cluster.local # Istio 自动生成的集群名
authority: ratelimit.istio-system.svc.cluster.local # HTTP/2 Host (SNI),可省略
transport_api_version: V3 # 使用 v3 API(推荐)
# 3.2 基于端口 1035 的 Listener 再插入 Lua 响应过滤器(可选:仅对该监听端口生效)
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
portNumber: 1035 # 仅对 1035 端口的 Listener 生效(你的网关暴露此端口)
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
subFilter:
name: envoy.filters.http.router
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.lua
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
inlineCode: |
function envoy_on_response(handle)
local s = tonumber(handle:headers():get(":status") or "0")
if s == 429 then
local body = '{"code":429,"message":"Too many requests. Please try again later."}'
handle:headers():replace("content-type", "application/json")
handle:headers():replace("content-length", tostring(#body))
handle:body(true):setBytes(body)
end
end
# 注意:
# - 如果你的网关并非监听 1035(或多端口),请确认此过滤器是否应该扩大到所有端口(去掉 portNumber 条件)
# - 也可用本地速率限制本地拒绝时在本机生成 429,再由该 Lua 统一改写
---
# --------------------------------------------
# 4) 给 VirtualHost 注入 per-route 限流动作
# - 在指定的 Route(或整个 vhost)下配置 actions,从而生成与 ConfigMap 匹配的 descriptors
# - 这里使用两段 action:
# a) header_value_match:当 :path 以 /api 前缀命中时,写入 descriptor_value=path-api
# b) generic_key:再追加 descriptor_value=istio-limit-v1
# - 两段组合 => (key=header_match,value=path-api) + (key=generic_key,value=istio-limit-v1)
# 正好与 ConfigMap 对应,从而激活“1 秒 1 次”的限流
# --------------------------------------------
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: gateway-limit-descriptor-svc
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway # 作用范围限定在网关
configPatches:
- applyTo: HTTP_ROUTE
match:
context: GATEWAY
routeConfiguration:
vhost:
name: host:port # 注意此 vhost 名:通常为 "<host>:<port>"
patch:
operation: MERGE
value:
route:
rate_limits:
- actions:
- header_value_match:
headers:
- name: ":path" # 匹配伪首部 :path,基于前缀判断
prefix_match: "/api"
expect_match: true # 仅当匹配时才添加该描述符
descriptor_value: "path-api" # 对应 ConfigMap 顶层 key/value
- generic_key:
descriptor_value: "istio-limit-v1" # 对应 ConfigMap 二级 key/value