MSE Ingress provides Layer-7 load balancing for managing external access to services in a Kubernetes cluster. Configure annotation-based features on Ingress resources — from canary releases and rate limiting to TLS and traffic mirroring.
All examples include configurations for both Kubernetes v1.19+ (networking.k8s.io/v1) and earlier versions (networking.k8s.io/v1beta1).
Annotation quick reference
All annotations use either the nginx.ingress.kubernetes.io/ or mse.ingress.kubernetes.io/ prefix.
Annotation scope:
Route scope: The annotation applies only to the specific route (path + host) defined on that Ingress resource.
Domain scope: The annotation applies to all routes sharing the same host. Place domain-scoped annotations on any Ingress resource that declares the target host.
When the same host appears in multiple Ingress resources, a route-level annotation on one resource does not affect routes defined in other resources for that host. Domain-scoped annotations, however, apply across all resources that share the host.
| Annotation | Accepted values | Default | Scope |
|---|---|---|---|
nginx.ingress.kubernetes.io/canary | "true" | — | Route |
nginx.ingress.kubernetes.io/canary-by-header | string | — | Route |
nginx.ingress.kubernetes.io/canary-by-header-value | string | — | Route |
nginx.ingress.kubernetes.io/canary-by-cookie | string | — | Route |
nginx.ingress.kubernetes.io/canary-weight | integer (0–100 or 0–total) | — | Route |
nginx.ingress.kubernetes.io/canary-weight-total | integer | 100 | Route |
mse.ingress.kubernetes.io/canary-by-query | string | — | Route |
mse.ingress.kubernetes.io/canary-by-query-value | string | — | Route |
mse.ingress.kubernetes.io/service-subset | string | — | Route |
mse.ingress.kubernetes.io/subset-labels | key value | — | Route |
nginx.ingress.kubernetes.io/enable-cors | "true" / "false" | false | Route |
nginx.ingress.kubernetes.io/cors-allow-origin | comma-separated origins or * | * | Route |
nginx.ingress.kubernetes.io/cors-allow-methods | comma-separated HTTP methods or * | GET,PUT,POST,DELETE,PATCH,OPTIONS | Route |
nginx.ingress.kubernetes.io/cors-allow-headers | comma-separated headers or * | DNT,X-CustomHeader,... | Route |
nginx.ingress.kubernetes.io/cors-expose-headers | comma-separated headers | — | Route |
nginx.ingress.kubernetes.io/cors-allow-credentials | "true" / "false" | true | Route |
nginx.ingress.kubernetes.io/cors-max-age | integer (seconds) | 1728000 | Route |
nginx.ingress.kubernetes.io/use-regex | "true" / "false" | — | Route |
nginx.ingress.kubernetes.io/rewrite-target | path string | — | Route |
nginx.ingress.kubernetes.io/upstream-vhost | hostname | — | Route |
nginx.ingress.kubernetes.io/ssl-redirect | "true" / "false" | false | Route |
nginx.ingress.kubernetes.io/force-ssl-redirect | "true" / "false" | false | Route |
nginx.ingress.kubernetes.io/permanent-redirect | URL (with scheme) | — | Route |
nginx.ingress.kubernetes.io/permanent-redirect-code | HTTP status code | 301 | Route |
nginx.ingress.kubernetes.io/temporal-redirect | URL (with scheme) | — | Route |
mse.ingress.kubernetes.io/request-header-control-add | key value or YAML block | — | Route |
mse.ingress.kubernetes.io/request-header-control-update | key value or YAML block | — | Route |
mse.ingress.kubernetes.io/request-header-control-remove | comma-separated header names | — | Route |
mse.ingress.kubernetes.io/response-header-control-add | key value or YAML block | — | Route |
mse.ingress.kubernetes.io/response-header-control-update | key value or YAML block | — | Route |
mse.ingress.kubernetes.io/response-header-control-remove | comma-separated header names | — | Route |
nginx.ingress.kubernetes.io/proxy-next-upstream-tries | integer | 3 | Route |
nginx.ingress.kubernetes.io/proxy-next-upstream-timeout | integer (seconds) | no timeout | Route |
nginx.ingress.kubernetes.io/proxy-next-upstream | comma-separated conditions | error,timeout | Route |
nginx.ingress.kubernetes.io/whitelist-source-range | comma-separated IPs or CIDRs | — | Route |
mse.ingress.kubernetes.io/blacklist-source-range | comma-separated IPs or CIDRs | — | Route |
mse.ingress.kubernetes.io/domain-whitelist-source-range | comma-separated IPs or CIDRs | — | Domain |
mse.ingress.kubernetes.io/domain-blacklist-source-range | comma-separated IPs or CIDRs | — | Domain |
mse.ingress.kubernetes.io/route-limit-rpm | integer | — | Route |
mse.ingress.kubernetes.io/route-limit-rps | integer | — | Route |
mse.ingress.kubernetes.io/route-limit-burst-multiplier | integer | 5 | Route |
mse.ingress.kubernetes.io/rate-limit | integer (RPS) | — | Route |
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-code | HTTP status code | 429 | Route |
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body-type | text / json | text | Route |
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body | string | sentinel rate limited | Route |
mse.ingress.kubernetes.io/rate-limit-fallback-redirect-url | URL | — | Route |
mse.ingress.kubernetes.io/concurrency-limit | integer | — | Route |
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-code | HTTP status code | 429 | Route |
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-body-type | text / json | text | Route |
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-body | string | sentinel rate limited | Route |
mse.ingress.kubernetes.io/concurrency-limit-fallback-redirect-url | URL | — | Route |
mse.ingress.kubernetes.io/mirror-target-service | namespace/name:port | — | Route |
mse.ingress.kubernetes.io/mirror-percentage | integer (0–100) | 100 | Route |
nginx.ingress.kubernetes.io/backend-protocol | HTTPS / GRPC | — | Route |
nginx.ingress.kubernetes.io/load-balance | round_robin / least_conn / random | round_robin | Route |
nginx.ingress.kubernetes.io/upstream-hash-by | NGINX variable or expression | — | Route |
mse.ingress.kubernetes.io/warmup | integer (seconds) | disabled | Route |
nginx.ingress.kubernetes.io/affinity | cookie | — | Route |
nginx.ingress.kubernetes.io/affinity-mode | balanced | balanced | Route |
nginx.ingress.kubernetes.io/session-cookie-name | string | INGRESSCOOKIE | Route |
nginx.ingress.kubernetes.io/session-cookie-path | path string | / | Route |
nginx.ingress.kubernetes.io/session-cookie-max-age | integer (seconds) | session-scoped | Route |
nginx.ingress.kubernetes.io/session-cookie-expires | integer (seconds) | session-scoped | Route |
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection | integer | — | Route |
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection-per-endpoint | integer | — | Route |
mse.ingress.kubernetes.io/connection-policy-http-max-request-per-connection | integer | — | Route |
mse.ingress.kubernetes.io/tls-min-protocol-version | TLSv1.0 / TLSv1.1 / TLSv1.2 / TLSv1.3 | TLSv1.0 | Domain |
mse.ingress.kubernetes.io/tls-max-protocol-version | TLSv1.0 / TLSv1.1 / TLSv1.2 / TLSv1.3 | TLSv1.3 | Domain |
nginx.ingress.kubernetes.io/ssl-cipher | comma-separated cipher suites | see defaults | Domain |
nginx.ingress.kubernetes.io/proxy-ssl-secret | namespace/secretName | — | Route |
nginx.ingress.kubernetes.io/proxy-ssl-name | hostname | — | Route |
nginx.ingress.kubernetes.io/proxy-ssl-server-name | "on" / "off" | — | Route |
Canary release
MSE Ingress supports four canary release strategies. Enable canary on any Ingress resource by adding nginx.ingress.kubernetes.io/canary: "true", then apply one or more of the strategy-specific annotations below.
MSE Ingress supports more than two service versions in a single canary release, with no upper limit. NGINX Ingress and ALB Ingress support at most two versions.
When multiple strategies are configured simultaneously, MSE Ingress applies them in this precedence order:
Header-based or query parameter-based (highest priority)
Cookie-based
Weight-based (lowest priority)
Header-based canary release
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/canary-by-header | Routes requests to the canary version when the specified header is present and set to always. For any other value, the header is ignored and other canary rules apply by precedence. | — | Yes (for header-based canary) |
nginx.ingress.kubernetes.io/canary-by-header-value | Routes requests to the canary version when the header matches both the key (from canary-by-header) and this specific value. Has no effect if canary-by-header is not set. | — | No |
Example 1: Route by header presence
When the request header mse is set to always, requests go to demo-service-canary. All other requests go to demo-service.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "mse"
name: demo-canary
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service-canary
port:
number: 80
path: /hello
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /hello
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "mse"
name: demo-canary
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service-canary
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service
servicePort: 80Example 2: Route multiple canary versions by exact header value
When the header mse: v1 is present, requests go to demo-service-canary-v1. When mse: v2 is present, they go to demo-service-canary-v2. All other requests go to demo-service.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "mse"
nginx.ingress.kubernetes.io/canary-by-header-value: "v1"
name: demo-canary-v1
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service-canary-v1
port:
number: 80
path: /hello
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "mse"
nginx.ingress.kubernetes.io/canary-by-header-value: "v2"
name: demo-canary-v2
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service-canary-v2
port:
number: 80
path: /hello
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /hello
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "mse"
nginx.ingress.kubernetes.io/canary-by-header-value: "v1"
name: demo-canary-v1
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service-canary-v1
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "mse"
nginx.ingress.kubernetes.io/canary-by-header-value: "v2"
name: demo-canary-v2
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service-canary-v2
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service
servicePort: 80Query parameter-based canary release
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/canary-by-query | Routes requests to the canary version when the specified query parameter is present and set to always. | — | Yes (for query-based canary) |
mse.ingress.kubernetes.io/canary-by-query-value | Routes requests to the canary version when the query parameter matches both the key (from canary-by-query) and this specific value. Has no effect if canary-by-query is not set. | — | No |
Header-based and query parameter-based conditions can be combined. Requests are sent to the canary version only when both conditions match simultaneously.
Example 1: Route by query parameter value
When the URL contains canary=gray, requests go to demo-service-canary. All other requests go to demo-service.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
mse.ingress.kubernetes.io/canary-by-query: "canary"
mse.ingress.kubernetes.io/canary-by-query-value: "gray"
name: demo-canary
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service-canary
port:
number: 80
path: /hello
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /hello
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
mse.ingress.kubernetes.io/canary-by-query: "canary"
mse.ingress.kubernetes.io/canary-by-query-value: "gray"
name: demo-canary
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service-canary
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service
servicePort: 80Example 2: Combine query parameter with header conditions
When the URL contains canary=gray AND the request header contains x-user-id: test, requests go to demo-service-canary. Both conditions must match.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
mse.ingress.kubernetes.io/canary-by-query: "canary"
mse.ingress.kubernetes.io/canary-by-query-value: "gray"
nginx.ingress.kubernetes.io/canary-by-header: "x-user-id"
nginx.ingress.kubernetes.io/canary-by-header-value: "test"
name: demo-canary
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service-canary
port:
number: 80
path: /hello
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /hello
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
mse.ingress.kubernetes.io/canary-by-query: "canary"
mse.ingress.kubernetes.io/canary-by-query-value: "gray"
nginx.ingress.kubernetes.io/canary-by-header: "x-user-id"
nginx.ingress.kubernetes.io/canary-by-header-value: "test"
name: demo-canary
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service-canary
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service
servicePort: 80Cookie-based canary release
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/canary-by-cookie | Routes requests to the canary version when the specified cookie is set to always. Custom cookie values are not supported — the value must be always. | — | Yes (for cookie-based canary) |
Example: When the request cookie demo=always is present, requests go to demo-service-canary. All other requests go to demo-service.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "demo"
name: demo-canary
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service-canary
port:
number: 80
path: /hello
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /hello
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "demo"
name: demo-canary
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service-canary
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service
servicePort: 80Weight-based canary release
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/canary-weight | Percentage of requests sent to the canary version. Integer in the range 0–100 (or 0–canary-weight-total). | — | Yes (for weight-based canary) |
nginx.ingress.kubernetes.io/canary-weight-total | Total weight used as the denominator when calculating request distribution. | 100 | No |
Example: Distribute traffic across three versions — 30% to demo-service-canary-v1, 20% to demo-service-canary-v2, and 50% to demo-service.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "30"
name: demo-canary-v1
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service-canary-v1
port:
number: 80
path: /hello
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "20"
name: demo-canary-v2
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service-canary-v2
port:
number: 80
path: /hello
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /hello
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "30"
name: demo-canary-v1
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service-canary-v1
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "20"
name: demo-canary-v2
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service-canary-v2
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service
servicePort: 80Service subset
A service subset routes requests to a specific group of pods within a single Kubernetes Service — useful when one Service is backed by multiple Deployments running different versions. MSE Ingress provides two methods for defining subsets.
Use pod labels in MseIngressConfig
Use mse.ingress.kubernetes.io/service-subset to select pods by their OpenSergo canary labels:
""orbase: routes to pods without anopensergo.io/canarylabel prefix, or withopensergo.io/canary: "".Any other value (for example,
gray): routes to pods labeledopensergo.io/canary-{value}: {value}— for example,opensergo.io/canary-gray: gray.
Example: A Service named go-httpbin is backed by two Deployments. Base pods have no OpenSergo canary label. Gray pods have the label opensergo.io/canary-gray: gray.
Service and Deployment manifests:
# go-httpbin Service
apiVersion: v1
kind: Service
metadata:
name: go-httpbin
namespace: default
spec:
ports:
- port: 8080
protocol: TCP
selector:
app: go-httpbin
---
# Base Deployment — no OpenSergo canary label
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-httpbin-base
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: go-httpbin
template:
metadata:
labels:
app: go-httpbin
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/mse/go-httpbin
args:
- "--version=base"
imagePullPolicy: Always
name: go-httpbin
---
# Gray Deployment — has the OpenSergo canary label
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-httpbin-gray
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: go-httpbin
template:
metadata:
labels:
app: go-httpbin
opensergo.io/canary-gray: gray
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/mse/go-httpbin
args:
- "--version=gray"
imagePullPolicy: Always
name: go-httpbinIngress configuration — requests with x-user-id: test go to go-httpbin-gray; all others go to go-httpbin-base:
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "x-user-id"
nginx.ingress.kubernetes.io/canary-by-header-value: "test"
# Forward to pods labeled opensergo.io/canary-gray: gray
mse.ingress.kubernetes.io/service-subset: gray
name: demo-canary
namespace: default
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: go-httpbin
port:
number: 8080
path: /test
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
# Forward to pods without the opensergo.io/canary label prefix
mse.ingress.kubernetes.io/service-subset: ""
name: demo
namespace: default
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: go-httpbin
port:
number: 8080
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "x-user-id"
nginx.ingress.kubernetes.io/canary-by-header-value: "test"
# Forward to pods labeled opensergo.io/canary-gray: gray
mse.ingress.kubernetes.io/service-subset: gray
name: demo-canary
namespace: default
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /test
backend:
serviceName: go-httpbin
servicePort: 8080
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
# Forward to pods without the opensergo.io/canary label prefix
mse.ingress.kubernetes.io/service-subset: ""
name: demo
namespace: default
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /test
backend:
serviceName: go-httpbin
servicePort: 8080Use custom labels
Combine mse.ingress.kubernetes.io/service-subset with mse.ingress.kubernetes.io/subset-labels to define a subset by any pod label instead of the opensergo.io/canary prefix.
Whensubset-labelsis set, the subset is no longer mapped toopensergo.io/canary-prefixed labels.
Example: The gray Deployment has version: gray instead of an OpenSergo label.
Service and Deployment manifests:
# go-httpbin Service
apiVersion: v1
kind: Service
metadata:
name: go-httpbin
namespace: default
spec:
ports:
- port: 8080
protocol: TCP
selector:
app: go-httpbin
---
# Base Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-httpbin-base
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: go-httpbin
template:
metadata:
labels:
app: go-httpbin
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/mse/go-httpbin
args:
- "--version=base"
imagePullPolicy: Always
name: go-httpbin
---
# Gray Deployment — uses a custom label instead of opensergo.io/canary
apiVersion: apps/v1
kind: Deployment
metadata:
name: go-httpbin-gray
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: go-httpbin
template:
metadata:
labels:
app: go-httpbin
version: gray
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/mse/go-httpbin
args:
- "--version=gray"
imagePullPolicy: Always
name: go-httpbinIngress configuration — requests with x-user-id: test go to go-httpbin-gray; all others go to go-httpbin-base:
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "x-user-id"
nginx.ingress.kubernetes.io/canary-by-header-value: "test"
# Forward to pods labeled version: gray
mse.ingress.kubernetes.io/service-subset: gray
mse.ingress.kubernetes.io/subset-labels: version gray
name: demo-canary
namespace: default
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: go-httpbin
port:
number: 8080
path: /test
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/service-subset: ""
name: demo
namespace: default
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: go-httpbin
port:
number: 8080
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "x-user-id"
nginx.ingress.kubernetes.io/canary-by-header-value: "test"
# Forward to pods labeled version: gray
mse.ingress.kubernetes.io/service-subset: gray
mse.ingress.kubernetes.io/subset-labels: version gray
name: demo-canary
namespace: default
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /test
backend:
serviceName: go-httpbin
servicePort: 8080
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/service-subset: ""
name: demo
namespace: default
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /test
backend:
serviceName: go-httpbin
servicePort: 8080CORS
Cross-Origin Resource Sharing (CORS) lets web applications access resources on a different origin. For the CORS specification, see Cross-Origin Resource Sharing (CORS).
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/enable-cors | Enables CORS on this Ingress. | false | Yes (to enable CORS) |
nginx.ingress.kubernetes.io/cors-allow-origin | Allowed third-party origins. Accepts comma-separated values and wildcards (*). | * | No |
nginx.ingress.kubernetes.io/cors-allow-methods | Allowed HTTP methods. Accepts comma-separated values and wildcards (*). | GET,PUT,POST,DELETE,PATCH,OPTIONS | No |
nginx.ingress.kubernetes.io/cors-allow-headers | Allowed request headers. Accepts comma-separated values and wildcards (*). | DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization | No |
nginx.ingress.kubernetes.io/cors-expose-headers | Response headers exposed to the browser. Accepts comma-separated values. | — | No |
nginx.ingress.kubernetes.io/cors-allow-credentials | Whether credentials can be included in CORS requests. | true | No |
nginx.ingress.kubernetes.io/cors-max-age | Cache duration for preflight results, in seconds. | 1728000 | No |
Example: Allow example.com as the origin, restrict methods to GET and POST, allow the X-Foo-Bar request header, and disable credential passing.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "example.com"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET,POST"
nginx.ingress.kubernetes.io/cors-allow-headers: "X-Foo-Bar"
nginx.ingress.kubernetes.io/cors-allow-credentials: "false"
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /hello
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "example.com"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET,POST"
nginx.ingress.kubernetes.io/cors-allow-headers: "X-Foo-Bar"
nginx.ingress.kubernetes.io/cors-allow-credentials: "false"
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service
servicePort: 80Regular expression match
In addition to exact and prefix match, MSE Ingress supports regular expression matching. Set nginx.ingress.kubernetes.io/use-regex: "true" to treat the path defined in the Ingress spec as a regular expression.
Example: Forward requests to example.com whose paths start with /app or /test to the demo service.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/use-regex: 'true'
name: regex-match
namespace: default
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo
port:
number: 8080
path: /(app|test)/(.*)
pathType: PrefixKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/use-regex: 'true'
name: regex-match
namespace: default
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /(app|test)/(.*)
backend:
serviceName: demo
servicePort: 8080Path and host rewrite
Rewrite operations modify the path or host in a request before it reaches the backend service.
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/rewrite-target | Destination path. Supports capture groups from the Ingress path pattern. | — | Yes (for path rewrite) |
nginx.ingress.kubernetes.io/upstream-vhost | Destination host. | — | Yes (for host rewrite) |
Path rewrite
Example 1: Rewrite example.com/test to example.com/dev before forwarding to the backend.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/dev"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/dev"
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /test
pathType: Exact
backend:
serviceName: demo-service
servicePort: 80Example 2: Strip the /v1 prefix — rewrite example.com/v1/xxx to example.com/xxx.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/$1"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /v1/(.*)
pathType: PrefixKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/$1"
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /v1/(.*)
pathType: Prefix
backend:
serviceName: demo-service
servicePort: 80Example 3: Replace the /v1 prefix with /v2 — rewrite example.com/v1/xxx to example.com/v2/xxx.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/v2/$1"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /v1/(.*)
pathType: PrefixKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/v2/$1"
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /v1/(.*)
pathType: Prefix
backend:
serviceName: demo-service
servicePort: 80Host rewrite
Example: Rewrite the host from example.com to test.com before forwarding example.com/test to the backend.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/upstream-vhost: "test.com"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/upstream-vhost: "test.com"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Redirect
HTTP-to-HTTPS redirect
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/ssl-redirect | Forces HTTP requests to redirect to HTTPS. | false | Yes (to enable redirect) |
nginx.ingress.kubernetes.io/force-ssl-redirect | Forces HTTP requests to redirect to HTTPS. | false | Yes (alternative to ssl-redirect) |
MSE Ingress treats both ssl-redirect and force-ssl-redirect identically — both force HTTP-to-HTTPS redirection.
Example: Redirect http://example.com/test to https://example.com/test.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Permanent redirect
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/permanent-redirect | Destination URL for the permanent redirect. Must include the scheme (http:// or https://). | — | Yes (for permanent redirect) |
nginx.ingress.kubernetes.io/permanent-redirect-code | HTTP status code for the redirect. | 301 | No |
Example: Permanently redirect http://example.com/test to http://example.com/app.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/permanent-redirect: "http://example.com/app"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/permanent-redirect: "http://example.com/app"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Temporary redirect
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/temporal-redirect | Destination URL for the temporary redirect. Must include the scheme (http:// or https://). | — | Yes (for temporary redirect) |
Example: Temporarily redirect http://example.com/test to http://example.com/app.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/temporal-redirect: "http://example.com/app"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/temporal-redirect: "http://example.com/app"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Header control
Header control lets you add, modify, or remove request headers before MSE Ingress forwards a request to a backend service, and response headers before the response is returned to the client.
Request header control
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/request-header-control-add | Adds a header to the request. If the header already exists, the value is appended. For a single header, use a key value pair. For multiple headers, use a YAML block scalar (|) with one key value pair per line. | — | No |
mse.ingress.kubernetes.io/request-header-control-update | Modifies an existing request header. If the header already exists, the value overwrites the original. Same syntax as request-header-control-add. | — | No |
mse.ingress.kubernetes.io/request-header-control-remove | Removes a header from the request. Separate multiple header names with commas. | — | No |
Example 1: Add foo: bar and test: true to all requests to example.com/test.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/request-header-control-add: |
foo bar
test true
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/request-header-control-add: |
foo bar
test true
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Example 2: Combine header control with canary releases. When the request header is mse: v1, the request goes to demo-service-canary-v1 with stage: gray added. All other requests go to demo-service with stage: production added.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "mse"
nginx.ingress.kubernetes.io/canary-by-header-value: "v1"
mse.ingress.kubernetes.io/request-header-control-add: "stage gray"
name: demo-canary-v1
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service-canary-v1
port:
number: 80
path: /hello
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/request-header-control-add: "stage production"
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /hello
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "mse"
nginx.ingress.kubernetes.io/canary-by-header-value: "v1"
mse.ingress.kubernetes.io/request-header-control-add: "stage gray"
name: demo-canary-v1
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service-canary-v1
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/request-header-control-add: "stage production"
name: demo
spec:
ingressClassName: mse
rules:
- http:
paths:
- path: /hello
backend:
serviceName: demo-service
servicePort: 80Response header control
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/response-header-control-add | Adds a header to the response before forwarding to the client. If the header already exists, the value is appended. Same syntax as request header control. | — | No |
mse.ingress.kubernetes.io/response-header-control-update | Modifies an existing response header. If the header already exists, the value overwrites the original. Same syntax as request header control. | — | No |
mse.ingress.kubernetes.io/response-header-control-remove | Removes a response header before forwarding to the client. Separate multiple header names with commas. | — | No |
Example: Remove the req-cost-time header from responses to example.com/test.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/response-header-control-remove: "req-cost-time"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/response-header-control-remove: "req-cost-time"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Retry
MSE Ingress provides route-level automatic retry for failed requests. Configure retry conditions, limits, and timeouts with the following annotations.
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/proxy-next-upstream-tries | Maximum number of retries. | 3 | No |
nginx.ingress.kubernetes.io/proxy-next-upstream-timeout | Timeout for all retry attempts combined, in seconds. | No timeout | No |
nginx.ingress.kubernetes.io/proxy-next-upstream | Retry conditions, comma-separated. Valid values: error (connection failure or 5xx), timeout (connection timeout or 5xx), invalid_header (request error or 5xx), http_xxx (specific status code, e.g., http_502), non_idempotent (enable retries for POST and PATCH), off (disable retries). | error,timeout | No |
By default, MSE Ingress does not retry non-idempotent requests (POST, PATCH) even when other retry conditions are met. Add non_idempotent to proxy-next-upstream to enable retries for these methods.
Example: For example.com/test, set a maximum of 2 retries with a 5-second timeout, trigger retries only on HTTP 502, and enable retries for non-idempotent requests.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-next-upstream-tries: "2"
nginx.ingress.kubernetes.io/proxy-next-upstream-timeout: "5"
nginx.ingress.kubernetes.io/proxy-next-upstream: "http_502,non_idempotent"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-next-upstream-tries: "2"
nginx.ingress.kubernetes.io/proxy-next-upstream-timeout: "5"
nginx.ingress.kubernetes.io/proxy-next-upstream: "http_502,non_idempotent"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80IP address allowlists (whitelists) and blocklists (blacklists)
MSE Ingress supports IP address allowlists (whitelists) and blocklists (blacklists) at both the route level and the domain level. Route-level rules take precedence over domain-level rules.
Route-level IP control
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/whitelist-source-range | IP addresses or CIDR blocks allowed for this route. Comma-separated. | — | No |
mse.ingress.kubernetes.io/blacklist-source-range | IP addresses or CIDR blocks blocked for this route. Comma-separated. | — | No |
Example 1: Allow access to example.com/test only from 1.1.X.X.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: 1.1.X.X
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: 1.1.X.X
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Example 2: Block access to example.com/test from 2.2.2.2.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/blacklist-source-range: 2.2.2.2
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/blacklist-source-range: 2.2.2.2
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Domain-level IP control
Domain-scoped annotations apply to all routes sharing the same host. A route-level allowlist or blocklist overrides the domain-level rule for that specific route.
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/domain-whitelist-source-range | IP addresses or CIDR blocks allowed for all routes of a domain. Route-level allowlists take precedence. Comma-separated. | — | No |
mse.ingress.kubernetes.io/domain-blacklist-source-range | IP addresses or CIDR blocks blocked for all routes of a domain. Route-level blocklists take precedence. Comma-separated. | — | No |
Example 1: Allow access to all routes of example.com from 1.1.X.X and 2.2.2.2.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/domain-whitelist-source-range: 1.1.X.X,2.2.2.2
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: Exact
- backend:
service:
name: app-service
port:
number: 80
path: /app
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/domain-whitelist-source-range: 1.1.X.X,2.2.2.2
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80
- path: /app
backend:
serviceName: app-service
servicePort: 80Example 2: Allow all routes of example.com from 1.1.X.X and 2.2.2.2, but restrict /order to only 3.3.X.X. The route-level allowlist on /order overrides the domain-level allowlist for that route.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/domain-whitelist-source-range: 1.1.X.X,2.2.2.2
name: demo-domain
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: Exact
- backend:
service:
name: app-service
port:
number: 80
path: /app
pathType: Exact
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: 3.3.X.X
name: demo-route
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /order
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/domain-whitelist-source-range: 1.1.X.X,2.2.2.2
name: demo-domain
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80
- path: /app
backend:
serviceName: app-service
servicePort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: 3.3.X.X
name: demo-route
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /order
backend:
serviceName: demo-service
servicePort: 80Single-gateway throttling
Single-gateway throttling limits the request rate on a route per gateway replica. Use this for per-instance rate control. For cluster-wide rate control, see Global throttling control.
Rate limits apply per gateway replica. If your gateway runs multiple replicas or uses a horizontal pod autoscaler (HPA), the effective cluster-wide rate is the configured limit multiplied by the number of replicas. When using HPA, the effective rate becomes dynamic as the replica count changes.
MSE Ingress uses a token bucket model for burst control. The route-limit-rpm or route-limit-rps annotation sets the sustained rate — how fast the token bucket refills. The route-limit-burst-multiplier annotation sets the burst capacity as a multiple of that rate: burst limit = rate × multiplier. Requests that exceed the burst capacity are rejected with local_rate_limited in the response body.
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/route-limit-rpm | Maximum requests per minute (RPM) per gateway replica. Burst limit = RPM × route-limit-burst-multiplier. Response code on throttle: 503 (gateway < v1.2.23) or 429 (gateway >= v1.2.23). | — | No |
mse.ingress.kubernetes.io/route-limit-rps | Maximum requests per second (RPS) per gateway replica. Burst limit = RPS × route-limit-burst-multiplier. Same response codes as RPM. | — | No |
mse.ingress.kubernetes.io/route-limit-burst-multiplier | Burst capacity multiplier applied to the configured RPM or RPS limit. Burst limit = rate × multiplier. | 5 | No |
Example 1: Limit example.com/test to 100 RPM with a burst limit of 200 (multiplier = 2).
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/route-limit-rpm: "100"
mse.ingress.kubernetes.io/route-limit-burst-multiplier: "2"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/route-limit-rpm: "100"
mse.ingress.kubernetes.io/route-limit-burst-multiplier: "2"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Example 2: Limit example.com/test to 10 RPS with the default burst limit of 50 (multiplier = 5).
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/route-limit-rps: "10"
# Default burst multiplier is 5, giving a burst limit of 50 RPS
# mse.ingress.kubernetes.io/route-limit-burst-multiplier: "5"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/route-limit-rps: "10"
# Default burst multiplier is 5, giving a burst limit of 50 RPS
# mse.ingress.kubernetes.io/route-limit-burst-multiplier: "5"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Global throttling control
MSE Ingress integrates with Sentinel to enforce a global RPS limit across all replicas of a gateway cluster at the route level. When throttling is triggered, the default response code is 429 and the response body is sentinel rate limited.
Global throttling control requires MSE Ingress gateway version 1.2.25 or later.
Configure the cluster-wide rate limit with mse.ingress.kubernetes.io/rate-limit. To customize the throttled response, use either custom response or redirect — only one approach can be active at a time.
Custom response
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/rate-limit | Maximum RPS for this route across the entire gateway cluster. | — | Yes |
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-code | HTTP response code returned when throttling is triggered. | 429 | No |
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body-type | Response body content type. text sets Content-Type: text/plain; charset=UTF-8. json sets Content-Type: application/json; charset=UTF-8. | text | No |
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body | Response body content when throttling is triggered. | sentinel rate limited | No |
Example 1: Limit example.com/test to 100 RPS cluster-wide with the default response (HTTP 429, sentinel rate limited).
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/rate-limit: "100"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/rate-limit: "100"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Example 2: Limit example.com/test to 100 RPS cluster-wide. When throttled, return HTTP 503 with the body server is overload.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/rate-limit: "100"
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-code: 503
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body: "server is overload"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/rate-limit: "100"
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-code: 503
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body: "server is overload"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Redirect
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/rate-limit-fallback-redirect-url | URL to redirect the client to when throttling is triggered. | — | No |
Example: Limit example.com/test to 100 RPS cluster-wide. When throttled, redirect to example.com/fallback.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/rate-limit: "100"
mse.ingress.kubernetes.io/rate-limit-fallback-redirect-url: "example.com/fallback"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/rate-limit: "100"
mse.ingress.kubernetes.io/rate-limit-fallback-redirect-url: "example.com/fallback"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Global concurrency control
MSE Ingress integrates with Sentinel to limit the number of in-flight requests on a route across the entire gateway cluster. When the limit is exceeded, the default response code is 429 and the response body is sentinel rate limited.
Global concurrency control requires MSE Ingress gateway version 1.2.25 or later.
Configure the cluster-wide concurrency limit with mse.ingress.kubernetes.io/concurrency-limit. To customize the response when the limit is exceeded, use either custom response or redirect — only one approach can be active at a time.
Custom response
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/concurrency-limit | Maximum number of in-flight requests for this route across the gateway cluster. | — | Yes |
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-code | HTTP response code when concurrency control is triggered. | 429 | No |
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-body-type | Response body content type. text sets Content-Type: text/plain; charset=UTF-8. json sets Content-Type: application/json; charset=UTF-8. | text | No |
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-body | Response body content when concurrency control is triggered. | sentinel rate limited | No |
Example 1: Limit concurrent in-flight requests to example.com/test to 1,000 cluster-wide, with the default response.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/concurrency-limit: "1000"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/concurrency-limit: "1000"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Example 2: Limit concurrent in-flight requests to example.com/test to 1,000 cluster-wide. When the limit is exceeded, return HTTP 503 with the body server is overload.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/concurrency-limit: "1000"
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-code: 503
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-body: "server is overload"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/concurrency-limit: "1000"
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-code: 503
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-body: "server is overload"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Redirect
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/concurrency-limit-fallback-redirect-url | URL to redirect the client to when concurrency control is triggered. | — | No |
Example: Limit concurrent in-flight requests to example.com/test to 1,000 cluster-wide. When the limit is exceeded, redirect to example.com/fallback.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/concurrency-limit: "1000"
mse.ingress.kubernetes.io/concurrency-limit-fallback-redirect-url: "example.com/fallback"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/concurrency-limit: "1000"
mse.ingress.kubernetes.io/concurrency-limit-fallback-redirect-url: "example.com/fallback"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Traffic mirroring
Traffic mirroring copies live requests to a secondary service without affecting the original response. Use it for auditing, testing, or debugging traffic against a shadow environment.
The mirrored request is processed synchronously with the original. A slow or unresponsive mirror backend will throttle the original request. Size your mirror backend to handle the mirrored traffic volume before enabling mirroring in production.
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/mirror-target-service | Destination service for mirrored traffic. Format: namespace/name:port. namespace defaults to the gateway namespace if omitted. port defaults to the first port of the Service if omitted. | — | Yes (to enable mirroring) |
mse.ingress.kubernetes.io/mirror-percentage | Percentage of traffic to mirror. Valid range: 0–100. | 100 | No |
When mirrored traffic is forwarded to the destination service, the -shadow suffix is automatically appended to the Host header. For example, example.com becomes example.com-shadow.
Example 1: Mirror 100% of requests to example.com/test to test/app:8080.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/mirror-target-service: test/app:8080
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/mirror-target-service: test/app:8080
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Example 2: Mirror 10% of requests to example.com/test to test/app:8080.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/mirror-target-service: test/app:8080
mse.ingress.kubernetes.io/mirror-percentage: 10
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/mirror-target-service: test/app:8080
mse.ingress.kubernetes.io/mirror-percentage: 10
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Backend service protocols: HTTPS and gRPC
By default, MSE Ingress uses HTTP to forward requests to backend containers. Use nginx.ingress.kubernetes.io/backend-protocol to switch to HTTPS or gRPC.
If the Kubernetes Service resource for your backend has a port namedgrpcorhttp2, MSE Ingress automatically uses the corresponding protocol without requiring thebackend-protocolannotation. This differs from standard NGINX Ingress behavior.
Example 1: Forward requests to a backend over HTTPS.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Example 2: Forward requests to a gRPC backend. Two methods are available.
Method 1 — use the backend-protocol annotation:
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Method 2 — name the Service port grpc so MSE Ingress auto-detects the protocol:
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /order
pathType: Exact
---
apiVersion: v1
kind: Service
metadata:
name: demo-service
spec:
ports:
- name: grpc
port: 80
protocol: TCP
selector:
app: demo-serviceKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80
---
apiVersion: v1
kind: Service
metadata:
name: demo-service
spec:
ports:
- name: grpc
port: 80
protocol: TCP
selector:
app: demo-serviceLoad balancing algorithms
MSE Ingress supports several load balancing algorithms for distributing requests to backend pods. Choose based on your traffic distribution and session requirements:
| Algorithm | Annotation value | Description | Use when |
|---|---|---|---|
| Round robin | round_robin | Distributes requests evenly across pods in rotation. | Default; suitable for stateless, evenly performing backends. |
| Least connections | least_conn | Routes each request to the pod with the fewest active connections. | Backends with variable request durations. |
| Random | random | Routes requests to a randomly selected pod. | Simple even distribution without state. |
| Consistent hashing | See below | Routes requests with the same hash key to the same pod. | Session affinity by IP, header, or query parameter. |
The exponentially weighted moving average (EWMA) algorithm is not supported. If configured, it falls back to round robin.
Common load balancing algorithms
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/load-balance | Load balancing algorithm. Valid values: round_robin, least_conn, random. | round_robin | No |
Example: Use least connections for demo-service.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/load-balance: "least_conn"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /order
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/load-balance: "least_conn"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Consistent hashing
Consistent hashing routes requests with the same hash key to the same backend pod. MSE Ingress supports hashing by NGINX variables, request headers, or query parameters.
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/upstream-hash-by | Hash key expression. Supported values: NGINX variables (e.g., $remote_addr, $host, $request_uri), request headers ($http_<header-name>), query parameters ($arg_<param-name>). | — | Yes (for consistent hashing) |
Example 1: Hash by client IP — requests from the same IP always reach the same pod.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Example 2: Hash by the X-Stage request header — requests with the same X-Stage value always reach the same pod.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/upstream-hash-by: "$http_x-stage"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/upstream-hash-by: "$http_x-stage"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Example 3: Hash by the x-stage query parameter — requests with the same x-stage value always reach the same pod.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/upstream-hash-by: "$arg_x-stage"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/upstream-hash-by: "$arg_x-stage"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Warm-up (graceful start)
The warm-up feature gradually ramps up traffic to a newly started pod over a specified time window, preventing a cold pod from receiving full load immediately. Only the round robin and least connections algorithms support warm-up.
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/warmup | Warm-up window duration in seconds. When a new pod starts, traffic increases gradually over this period. | Warm-up disabled | No |
Example: Enable a 30-second warm-up window for demo-service.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/warmup: "30"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/warmup: "30"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Cookie affinity (session persistence)
Cookie affinity pins a client to the same backend pod across requests using a gateway-generated cookie. On the first request, MSE Ingress sets a cookie in the response. Subsequent requests from the same client include that cookie and are routed to the same pod.
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/affinity | Enables cookie affinity. The only valid value is cookie. | — | Yes (to enable cookie affinity) |
nginx.ingress.kubernetes.io/affinity-mode | Affinity mode. The only valid value is balanced. | balanced | No |
nginx.ingress.kubernetes.io/session-cookie-name | Name of the cookie used as the hash key. | INGRESSCOOKIE | No |
nginx.ingress.kubernetes.io/session-cookie-path | Path attribute of the generated cookie. | / | No |
nginx.ingress.kubernetes.io/session-cookie-max-age | Expiration time of the generated cookie, in seconds. | Session-scoped | No |
nginx.ingress.kubernetes.io/session-cookie-expires | Expiration time of the generated cookie, in seconds. | Session-scoped | No |
Example 1: Enable cookie affinity with defaults — cookie name INGRESSCOOKIE, path /, session-scoped lifetime.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Example 2: Enable cookie affinity with a custom cookie named test, path /, and a 10-second expiration.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "test"
nginx.ingress.kubernetes.io/session-cookie-max-age: "10"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "test"
nginx.ingress.kubernetes.io/session-cookie-max-age: "10"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Connection pool between a gateway and a backend service
Configure a connection pool to control the number of connections between the gateway and a backend service. This prevents the backend from being overloaded during traffic spikes.
Connection pool configuration requires MSE Ingress gateway version 1.2.23 or later.
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection | Maximum total TCP connections between the gateway and the backend service. | — | No |
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection-per-endpoint | Maximum TCP connections between the gateway and a single pod of the backend service. | — | No |
mse.ingress.kubernetes.io/connection-policy-http-max-request-per-connection | Maximum HTTP requests per connection between the gateway and the backend service. | — | No |
Example: For demo-service, set a maximum of 10 total connections and 2 connections per pod.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection: 10
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection-per-endpoint: 2
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection: 10
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection-per-endpoint: 2
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80TLS versions and cipher suites
The default TLS version range for MSE Ingress is TLSv1.0 (earliest) to TLSv1.3 (latest). The default cipher suites are:
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-AES128-SHA
ECDHE-RSA-AES128-SHA
AES128-GCM-SHA256
AES128-SHA
ECDHE-ECDSA-AES256-GCM-SHA384
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-ECDSA-AES256-SHA
ECDHE-RSA-AES256-SHA
AES256-GCM-SHA384
AES256-SHA
Use the following annotations to configure TLS settings per domain name.
| Annotation | Description | Default | Required |
|---|---|---|---|
mse.ingress.kubernetes.io/tls-min-protocol-version | Earliest TLS version accepted. Valid values: TLSv1.0, TLSv1.1, TLSv1.2, TLSv1.3. | TLSv1.0 | No |
mse.ingress.kubernetes.io/tls-max-protocol-version | Latest TLS version accepted. | TLSv1.3 | No |
nginx.ingress.kubernetes.io/ssl-cipher | TLS cipher suites, comma-separated. Takes effect only for TLS versions 1.0–1.2. | See default list above | No |
Example: Restrict example.com to TLSv1.2 only.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/tls-min-protocol-version: "TLSv1.2"
mse.ingress.kubernetes.io/tls-max-protocol-version: "TLSv1.2"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
mse.ingress.kubernetes.io/tls-min-protocol-version: "TLSv1.2"
mse.ingress.kubernetes.io/tls-max-protocol-version: "TLSv1.2"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80Mutual TLS (mTLS) between a gateway and a backend service
By default, MSE Ingress uses HTTP to forward requests to backend containers. When nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" is set, MSE Ingress uses one-way TLS: it authenticates the backend's certificate, which must be issued by a well-known certificate authority (CA).
For mutual TLS (mTLS), both the gateway and the backend service authenticate each other's certificates.
| Annotation | Description | Default | Required |
|---|---|---|---|
nginx.ingress.kubernetes.io/proxy-ssl-secret | Client certificate used by the gateway to authenticate to the backend. Format: secretNamespace/secretName. | — | Yes (for mTLS) |
nginx.ingress.kubernetes.io/proxy-ssl-name | Server Name Indication (SNI) value used during the TLS handshake. | — | No |
nginx.ingress.kubernetes.io/proxy-ssl-server-name | Enables or disables SNI during the TLS handshake. Valid values: "on", "off". | — | No |
Example: Configure mTLS between the gateway and demo-service using gateway-cert in the default namespace.
Kubernetes v1.19+:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-ssl-secret: "default/gateway-cert"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- backend:
service:
name: demo-service
port:
number: 80
path: /test
pathType: ExactKubernetes earlier than v1.19:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-ssl-secret: "default/gateway-cert"
name: demo
spec:
ingressClassName: mse
rules:
- host: example.com
http:
paths:
- path: /test
backend:
serviceName: demo-service
servicePort: 80