Deploying Gateway#
This guide covers production deployment configuration for the AIBrix gateway components.
Configuring Resources and Replica Count#
For production deployments, we recommend tuning replica counts and resource allocations for both the Gateway Plugin and the Envoy Proxy data plane.
Gateway Plugin#
The gateway plugin (gatewayPlugin) handles request routing logic and external processing.
Set replicaCount and container resources in your values.yaml override:
gatewayPlugin:
replicaCount: 3
container:
resources:
limits:
cpu: "16"
memory: 32Gi
requests:
cpu: "16"
memory: 32Gi
Gateway Plugin Kubernetes API Throttling#
Configure the gateway plugin’s API server request rate using container arguments
in config/gateway/gateway-plugin/gateway-plugin.yaml:
containers:
- name: gateway-plugin
args:
- --kube-api-qps=5
- --kube-api-burst=10
--kube-api-qps defaults to rest.DefaultQPS (5 requests per second), and
--kube-api-burst defaults to rest.DefaultBurst (10 requests). Both must be
greater than zero; QPS must also be finite and remain positive when represented
as a float32. Invalid values cause the plugin to exit during startup.
The plugin applies these values to its shared Kubernetes REST configuration before creating the core Kubernetes and Gateway API clients. Each client uses the same settings with its own rate limiter; this is not a combined request budget. This configuration is also used when initializing the plugin’s Kubernetes caches. These flags control API server traffic, not inference request QPS.
Gateway Plugin Model Discovery and Listing#
The plugin can omit Kubernetes resource types that it does not serve. The following options keep Pod discovery and select a list containing only models with a ready Pod:
containers:
- name: gateway-plugin
args:
- --watch-model-adapters=false
- --watch-model-claims=false
- --model-list-mode=ready-pods
Adapter and ModelClaim watching both default to true. Disabling adapter
watching avoids listing or watching its CRD and removes it from required cache
sync. Disabling claim watching also ignores ModelClaim runtime annotations on
Pods when building the model cache. These options do not remove either feature
from deployments that leave it enabled.
--model-list-mode defaults to known, which retains the existing cached
model-name list. ready-pods includes a name when at least one associated
Pod has an IP, is Ready, and is neither terminating nor draining. This Pod
check does not verify an adapter’s load status, HTTPRoute acceptance, or a
complete prefill/decode pair. An empty cache returns an empty list.
To require a recent Kubernetes discovery snapshot before returning the list,
set a positive --model-list-discovery-max-age duration. For example:
containers:
- name: gateway-plugin
args:
- --model-list-mode=ready-pods
- --model-list-discovery-max-age=5m
The duration is the maximum age of a successful verification, not a polling
interval; zero (the default) preserves the existing behavior. The first list
request, and the first request after that age expires, obtains a current,
paginated Kubernetes LIST of Pods and enabled ModelAdapters and compares it
with events already applied to the gateway cache. Only one verification runs
at a time. A failed or mismatched LIST, a request timeout, or a reported watch
error invalidates the previous proof. The endpoint returns HTTP 503 with a
service_unavailable error until a later verification succeeds; retries
after failure are limited to once every five seconds. A healthy installation
with no models still returns HTTP 200 with an empty list. Each gateway replica
performs its own verification, so choose the duration with API-server load in
mind. The verification request has a ten-second timeout.
With verification enabled, the plugin opens its HTTP listener before initial discovery completes and returns the same 503 while its cache is unavailable. This only covers requests that reach the plugin; when no gateway process or ready Service endpoint is reachable, the front proxy controls the response.
The gateway plugin serves GET /v1/models on its HTTP port. The standard
Kubernetes Envoy route still sends this path to the metadata service; route
it to the plugin HTTP port if clients should receive the plugin’s list. For
the default Kustomize installation, this optional HTTPRoute sends the exact
path to the plugin Service on port 8080. The exact match takes precedence over
the existing metadata route’s prefix match, while /v1/files and
/v1/batches keep their existing destination:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: gateway-plugin-model-list
namespace: aibrix-system
spec:
parentRefs:
- name: aibrix-eg
rules:
- matches:
- path:
type: Exact
value: /v1/models
backendRefs:
- name: aibrix-gateway-plugins
port: 8080
Apply the route only when you intend to expose the plugin’s list. Confirm its
Accepted and ResolvedRefs conditions before relying on it. The route
does not change whether the plugin returns known or ready-pods; that
choice comes from --model-list-mode.
Envoy Proxy#
The Envoy proxy (gateway.envoyProxy) is the data-plane component managed by Envoy Gateway.
Set replicas and per-container resources as follows:
gateway:
envoyProxy:
replicas: 3
container:
envoy:
resources:
limits:
cpu: "8"
memory: 16Gi
requests:
cpu: "8"
memory: 16Gi
Enabling Redis for Multi-Replica Deployments#
When running more than one gateway plugin replica, shared state is required so that all instances agree on routing decisions (e.g. prefix-cache block assignments, rate-limit counters). Two settings must both be configured:
Connect to Redis — the gateway plugin reads the
REDIS_HOSTenvironment variable at startup. If the variable is unset or Redis is unreachable, each replica operates with in-process state only, which causes inconsistent routing across pods.Enable cross-replica state sync — setting
AIBRIX_STATESYNC_ENABLED=trueactivates the Redis-backed delta-sync mechanism that propagates prefix-cache state across replicas. Without this flag, the gateway connects to Redis for other purposes (e.g. rate limiting) but does not synchronize prefix-cache routing state between pods, so multi-replicaprefix-cacherouting will still produce inconsistent decisions.
Enable both by updating your values.yaml override:
gatewayPlugin:
dependencies:
redis:
host: "" # leave empty to use the chart-managed Redis (aibrix-redis-master)
port: 6379
container:
envs:
AIBRIX_STATESYNC_ENABLED: "true"
The Helm chart sets REDIS_HOST automatically from gatewayPlugin.dependencies.redis.host,
defaulting to <release-name>-redis-master when the field is empty. For an external Redis
cluster, set host to the service hostname or IP of your Redis endpoint.
Note
AIBRIX_STATESYNC_ENABLED defaults to false. It must be explicitly set to true
for cross-replica state sync to activate. Omitting this flag is the most common cause of
inconsistent prefix-cache routing when scaling the gateway plugin beyond one replica.
Sizing Redis#
The bundled Redis instance is deployed under metadata.redis. For production workloads with
multiple gateway plugin replicas, increase its CPU, memory, and (if using persistence)
storage from the defaults:
metadata:
redis:
replicas: 1
container:
resources:
requests:
cpu: "1"
memory: 2Gi
limits:
cpu: "2"
memory: 4Gi
The right sizing depends on request throughput and the number of distinct prefix-cache keys
in flight. As a starting point, allocate roughly 1 GiB of memory per 1 000 concurrent
requests and increase CPU if Redis becomes a latency bottleneck (monitor redis_commands_duration_seconds).
Note
If you are using an externally managed Redis (e.g. AWS ElastiCache, Google Memorystore),
set gatewayPlugin.dependencies.redis.host to the external endpoint and remove the
metadata.redis block from your override — the chart will not deploy its own Redis when
a custom host is provided.
Disabling Gateway Rate Limiting#
Set AIBRIX_DISABLE_RATE_LIMITING=true on the gateway plugin to disable AIBrix user
RPM/TPM and model RPS quota enforcement. The setting defaults to false. When disabled,
the gateway skips AIBrix user lookup and does not use the user header as routing identity,
but it forwards the header unchanged.
gatewayPlugin:
container:
envs:
AIBRIX_DISABLE_RATE_LIMITING: "true"
The setting does not disable the per-replica requestsInflight guard or disconnect Redis.
Keep Redis configured when session affinity, asynchronous jobs, state synchronization, or other
gateway features require it. Because disabled mode leaves routing user identity empty,
asynchronous video jobs use the shared ownership scope. The unauthenticated user header
does not isolate one caller’s video jobs from another caller’s jobs in this mode.
Configuring Buffer Limits, Connections, and QPS#
AIBrix exposes three policy knobs under gateway to control how traffic flows between
clients, the Envoy proxy, and backend pods.
Client Traffic Policy#
clientTrafficPolicy governs connections and request sizes arriving from external clients:
bufferLimit — maximum bytes buffered per request/response body (input/output size). The default
4194304is 4 MiB. Increase this if your workloads send large prompts or receive large completions.connectionLimit — maximum simultaneous TCP connections accepted by the proxy.
http2.maxConcurrentStreams — maximum concurrent HTTP/2 streams per connection from a client.
gateway:
clientTrafficPolicy:
connection:
bufferLimit: 4194304 # bytes; 4 MiB default
connectionLimit:
value: 1024
http2:
maxConcurrentStreams: 1024
Backend Traffic Policy#
backendTrafficPolicy controls how Envoy distributes load across backend pods and
limits the blast radius of a single slow or failing pod:
circuitBreaker.maxConnections — maximum TCP connections to a single backend pod.
circuitBreaker.maxParallelRequests — maximum in-flight requests to a single backend pod (effective QPS cap when combined with latency).
circuitBreaker.maxPendingRequests — maximum requests queued waiting for a connection to a backend pod.
circuitBreaker.maxParallelRetries — maximum concurrent retries to a backend pod.
circuitBreaker.maxRequestsPerConnection — maximum requests served on a single connection before it is recycled.
http2.maxConcurrentStreams — maximum concurrent HTTP/2 streams per connection to a backend pod.
gateway:
backendTrafficPolicy:
circuitBreaker:
maxConnections: 1024
maxParallelRequests: 1024
maxParallelRetries: 1024
maxPendingRequests: 1024
maxRequestsPerConnection: 1024
http2:
maxConcurrentStreams: 1024
Envoy Patch Policy#
envoyPatchPolicy provides lower-level overrides applied directly to the Envoy xDS
configuration, covering route timeouts and the limits for the original-destination cluster:
route.timeout — maximum duration Envoy waits for a backend response. Increase this for long-running inference requests.
route.connectTimeout — maximum time to establish a TCP connection to a backend pod.
circuitBreakers.maxConnections / maxRequests / maxPendingRequests — same semantics as the backend traffic policy above but applied at the Envoy cluster level.
gateway:
envoyPatchPolicy:
route:
timeout: 120s
connectTimeout: 6s
circuitBreakers:
maxConnections: 1024
maxRequests: 1024
maxPendingRequests: 1024
Choosing a Routing Strategy#
If no routing-strategy header is provided, the gateway defaults to random routing.
External decision services#
For production external routing, run at least two decision-service replicas
behind a stable Kubernetes Service, budget its synchronous latency within the
Gateway request path, and alert on timeout, fallback, and circuit-open outcomes.
Use HTTPS or an appropriate cluster NetworkPolicy and store bearer tokens in a
mounted Secret file. Test Authoritative denial and service unavailability before
enabling fail-closed traffic. External business-policy state is owned by the
service; Gateway bulkhead and circuit state is local to each Gateway replica.
See External Replica Routing.
# No routing-strategy header — gateway picks a random ready pod
curl -v http://${ENDPOINT}/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "your-model-name",
"messages": [{"role": "user", "content": "Hello!"}],
"temperature": 0.7
}'
For production workloads we recommend selecting a strategy based on your traffic pattern:
Multi-turn conversations or workloads with prompt prefix overlap — use prefix-cache
When requests share a common prompt prefix (e.g. a system prompt, few-shot examples, or
conversation history), prefix-cache routes each request to the pod that already holds the
matching KV-cache blocks in GPU memory, reducing redundant computation and improving latency.
See prefix cache routing details
for algorithm internals and configuration options.
curl -v http://${ENDPOINT}/v1/chat/completions \
-H "routing-strategy: prefix-cache" \
-H "Content-Type: application/json" \
-d '{
"model": "your-model-name",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"}
],
"temperature": 0.7
}'
Independent requests with no prefix overlap — use least-request
When each request has a unique prompt and there is no KV-cache reuse benefit, least-request
distributes load evenly by always routing to the pod with the fewest in-flight requests.
curl -v http://${ENDPOINT}/v1/chat/completions \
-H "routing-strategy: least-request" \
-H "Content-Type: application/json" \
-d '{
"model": "your-model-name",
"messages": [{"role": "user", "content": "Summarize this document: ..."}],
"temperature": 0.7
}'
High-throughput workloads requiring compute separation — use pd
Prefill-Decode (PD) disaggregation splits the two phases of LLM inference across dedicated pods: prefill pods process the prompt and decode pods generate tokens. This allows each pod type to be sized and scaled independently, improving GPU utilization at high request volumes.
curl -v http://${ENDPOINT}/v1/chat/completions \
-H "routing-strategy: pd" \
-H "Content-Type: application/json" \
-d '{
"model": "your-model-name",
"messages": [{"role": "user", "content": "Explain quantum entanglement."}],
"temperature": 0.7
}'
See prefill-decode disaggregation details for deployment requirements and configuration options.
Note
random is suitable for testing and low-traffic scenarios where routing quality is not
critical. For any production deployment, explicitly set routing-strategy to avoid
relying on the default.
Draining Pods#
The gateway excludes Pods annotated with aibrix.ai/draining=true from its
ready-pod routing candidates. RoleSet and PodSet controllers set this annotation
before deleting serving Pods when a role configures
drain.timeoutSeconds > 0. This gives the gateway time to stop assigning new
requests before the controller removes the Pod.
The gateway treats the drain annotation as a routing signal only:
RoleSet/PodSet controller
-> patch Pod: aibrix.ai/draining=true
-> patch Pod: aibrix.ai/drain-start-time=<RFC3339 UTC>
-> patch Pod: aibrix.ai/drain-reason=scale-in|rollout
-> patch Pod: aibrix.ai/drain-target-action=delete
Gateway pod cache
-> observes the Pod update
-> filters the Pod out of ready routing candidates
RoleSet/PodSet controller
-> waits for drain.timeoutSeconds
-> deletes the Pod
The controller owns the timeout and deletion decision. The gateway does not
parse drain-start-time and does not emit drain lifecycle events.
Per-Model Routing Configuration#
When a single gateway deployment serves multiple models, you may need different routing
strategies per model — for example, prefix-cache for a chat model and pd for a
batch-inference model. AIBrix supports this through Model Config Profiles, which let you
attach a routing configuration directly to each model’s pods via an annotation and select a
profile at request time using the config-profile header.
# Select the "low-latency" profile for this request
curl -v http://${ENDPOINT}/v1/chat/completions \
-H "config-profile: low-latency" \
-H "Content-Type: application/json" \
-d '{
"model": "your-model-name",
"messages": [{"role": "user", "content": "Hello!"}],
"temperature": 0.7
}'
If the config-profile header is omitted, the model’s defaultProfile is used.
This allows the same gateway to enforce different routing strategies, prompt-length bucketing,
and PD modes per model without deploying separate gateway instances.
For config profile setup and the full annotation schema see Config Profiles in the Gateway Routing guide. For production guidance including RPS limiting see Production Model Deployments.
Production Model Deployments: deploy models behind this gateway
Observability: gateway metrics and dashboards
Prefill-Decode Disaggregation (PD): split prefill from decode
AIBrix Gateway: how routing decisions are made