Rate limiting и JWT-маршрутизация в APISIX
Published: 2026-03-03
Главное преимущество Apache APISIX перед ingress-контроллерами на базе nginx — система плагинов. Там, где nginx требует Lua-модулей и сложной правки конфигурации, APISIX маршрутизирует, ограничивает и трансформирует запросы несколькими строками YAML через Kubernetes CRD. Вот как мы используем это на практике.
ApisixRoute: базовая единица
yamlapiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: api-route
namespace: app
spec:
http:
- name: main
match:
hosts:
- api.example.com
paths:
- /*
backends:
- serviceName: my-api-service
servicePort: 80
plugins:
- name: redirect
enable: true
config:
http_to_https: true
Маршруты задаются на уровне spec.http. Несколько записей в одном ApisixRoute или несколько ApisixRoute на один хост — оба варианта работают.
Rate limiting по JWT-клейму agency-id
Наш паттерн: извлекаем клейм из JWT и берём его как ключ rate limit — так разные клиенты получают разные лимиты.
yamlplugins:
# 1. Глобальный лимит (все клиенты вместе)
- name: limit-count
enable: true
config:
count: 17
time_window: 1
rejected_code: 429
key_type: constant
# 2. Извлечение agency-id из JWT через serverless-функцию
- name: serverless-pre-function
enable: true
config:
phase: rewrite
functions:
- |-
return function(conf, ctx)
local core = require("apisix.core")
local jwt = require("resty.jwt")
local token = core.request.header(ctx, "Authorization")
if token then
local _, _, t = string.find(token, "Bearer%s+(.+)")
if t then
local obj = jwt:load_jwt(t)
if obj.valid then
local agency = obj.payload["agency-id"]
core.request.set_header(ctx, "X-Agency-Id", agency)
end
end
end
end
Lua-функция выполняется в фазе rewrite — до проксирования запроса. Она читает JWT, извлекает agency-id и выставляет заголовок, по которому работают последующие плагины.
Лимит по agency
yaml - name: limit-count
enable: true
config:
count: 100
time_window: 60
rejected_code: 429
key_type: var
key: http_x_agency_id
group: agency-rate-limit
Каждое уникальное значение X-Agency-Id получает свой счётчик. VIP-агентства можно исключить, проверив значение в Lua-функции.
Маршрутизация по regex-пути
yamlspec:
http:
- name: airshopping
match:
hosts: [api.example.com]
paths: [/*]
exprs:
- subject:
scope: Path
op: RegexMatchCaseInsensitive
value: "^/api/order/(airshopping|offerprice)$"
backends:
- serviceName: search-service
servicePort: 80
- name: booking
match:
hosts: [api.example.com]
paths: [/api/order/createorder]
backends:
- serviceName: booking-service
servicePort: 80
- name: fallback
match:
hosts: [api.example.com]
paths: [/*]
priority: -1
backends:
- serviceName: default-service
servicePort: 80
exprs — предикатное сопоставление по пути, заголовкам или query-параметрам. priority определяет приоритет при совпадении нескольких правил.
ApisixUpstream: healthcheck и балансировка
yamlapiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
name: my-api-upstream
namespace: app
spec:
loadbalancer:
type: roundrobin
healthCheck:
active:
type: http
httpPath: /healthz
interval: 10
timeout: 2
successThreshold: 1
failureThreshold: 3
httpStatusCode: [200]
externalNodes:
- type: Service
name: my-api-service
port: 80
weight: 100
Активный healthcheck опрашивает /healthz каждые 10 секунд. После трёх неудач подряд upstream помечается как нездоровый. APISIX обрабатывает это в data plane без участия Kubernetes.
Canary-деплой через traffic splitting
yamlbackends:
- serviceName: api-stable
servicePort: 80
weight: 90
- serviceName: api-canary
servicePort: 80
weight: 10
10% трафика уходит в canary. Никаких дополнительных инструментов — только соотношение весов. Регулируйте через GitOps или kubectl patch.
Key-auth плагин для доступа по API-ключу
yamlplugins:
- name: key-auth
enable: true
config:
header: "X-API-Key"
query: "apikey"
Создайте ApisixConsumer с допустимым ключом:
yamlapiVersion: apisix.apache.org/v2
kind: ApisixConsumer
metadata:
name: my-client
namespace: app
spec:
authParameter:
keyAuth:
value:
key: "my-secret-api-key"
Запросы без корректного X-API-Key получают 401 на шлюзе — до upstream неаутентифицированный трафик не доходит.
Трансформация запросов
yamlplugins:
- name: proxy-rewrite
enable: true
config:
headers:
remove:
- Authorization
- X-Agency-Id
add:
X-Forwarded-Service: "api-gateway"
regex_uri:
- "^/api/v1/(.*)"
- "/internal/$1"
Отладка маршрутов
bashkubectl get apisixroute -n app
kubectl describe apisixroute api-route -n app
# Маршруты через admin API
kubectl port-forward -n ingress-apisix svc/apisix-admin 9080:9080
curl -s http://localhost:9080/apisix/admin/routes | jq '[.list[] | {name: .value.name, uri: .value.uri}]'