All Products
Search
Document Center

Container Service for Kubernetes:Advanced usage of MSE Ingress

Last Updated:Mar 26, 2026

MSE Ingress is a Kubernetes Ingress object that manages external access to cluster services via Layer-7 load balancing. Configure advanced traffic governance features — canary releases, rate limiting, access control, header manipulation, and more — by adding annotations to your Ingress resources.

Annotation quick reference

All MSE Ingress features are controlled through Kubernetes annotations. The table below lists every supported annotation grouped by feature. Click the feature name to jump to the full configuration guide.

AnnotationFeatureType
nginx.ingress.kubernetes.io/canaryEnable canary release"true" or "false"
nginx.ingress.kubernetes.io/canary-by-headerHeader-based canary releasestring
nginx.ingress.kubernetes.io/canary-by-header-valueHeader-based canary release with exact valuestring
nginx.ingress.kubernetes.io/canary-by-cookieCookie-based canary releasestring
nginx.ingress.kubernetes.io/canary-weightWeight-based canary releaseinteger (0–100)
nginx.ingress.kubernetes.io/canary-weight-totalTotal weight denominator for weight-based canaryinteger (default: 100)
mse.ingress.kubernetes.io/canary-by-queryQuery parameter-based canary releasestring
mse.ingress.kubernetes.io/canary-by-query-valueQuery parameter-based canary release with exact valuestring
mse.ingress.kubernetes.io/service-subsetService subset routingstring
mse.ingress.kubernetes.io/subset-labelsCustom subset labels for service subsetstring
nginx.ingress.kubernetes.io/enable-corsEnable CORS"true" or "false"
nginx.ingress.kubernetes.io/cors-allow-originAllowed CORS originsstring (default: *)
nginx.ingress.kubernetes.io/cors-allow-methodsAllowed HTTP methods for CORSstring
nginx.ingress.kubernetes.io/cors-allow-headersAllowed request headers for CORSstring
nginx.ingress.kubernetes.io/cors-allow-credentialsAllow credentials in CORS requests"true" or "false"
nginx.ingress.kubernetes.io/cors-max-agePreflight cache duration for CORS (seconds)integer (default: 1728000)
nginx.ingress.kubernetes.io/use-regexEnable regex path matching"true"
nginx.ingress.kubernetes.io/rewrite-targetPath rewrite destinationstring
nginx.ingress.kubernetes.io/upstream-vhostHost rewrite destinationstring
nginx.ingress.kubernetes.io/ssl-redirectForce HTTP-to-HTTPS redirect"true" or "false"
nginx.ingress.kubernetes.io/force-ssl-redirectForce HTTP-to-HTTPS redirect"true" or "false"
nginx.ingress.kubernetes.io/permanent-redirectPermanent redirect URLstring
nginx.ingress.kubernetes.io/permanent-redirect-codePermanent redirect status codeinteger (default: 301)
nginx.ingress.kubernetes.io/temporal-redirectTemporary redirect URLstring
mse.ingress.kubernetes.io/request-header-control-addAdd request headersstring
mse.ingress.kubernetes.io/request-header-control-updateUpdate request headersstring
mse.ingress.kubernetes.io/request-header-control-removeRemove request headersstring
mse.ingress.kubernetes.io/response-header-control-addAdd response headersstring
mse.ingress.kubernetes.io/response-header-control-updateUpdate response headersstring
mse.ingress.kubernetes.io/response-header-control-removeRemove response headersstring
nginx.ingress.kubernetes.io/proxy-next-upstream-triesMax retry attemptsinteger (default: 3)
nginx.ingress.kubernetes.io/proxy-next-upstream-timeoutRetry timeout (seconds)integer
nginx.ingress.kubernetes.io/proxy-next-upstreamRetry conditionsstring (default: error,timeout)
nginx.ingress.kubernetes.io/whitelist-source-rangeIP whitelist (access control)CIDR/IP
mse.ingress.kubernetes.io/blacklist-source-rangeIP blacklist (access control)CIDR/IP
mse.ingress.kubernetes.io/domain-whitelist-source-rangeIP whitelist (access control)CIDR/IP
mse.ingress.kubernetes.io/domain-blacklist-source-rangeIP blacklist (access control)CIDR/IP
mse.ingress.kubernetes.io/route-limit-rpmMax requests per minute (single-gateway throttling)integer
mse.ingress.kubernetes.io/route-limit-rpsMax requests per second (single-gateway throttling)integer
mse.ingress.kubernetes.io/route-limit-burst-multiplierBurst multiplier for single-gateway throttlinginteger (default: 5)
mse.ingress.kubernetes.io/rate-limitGlobal RPS limit (global rate limiting)integer
mse.ingress.kubernetes.io/concurrency-limitGlobal concurrency limit (global concurrency control)integer
mse.ingress.kubernetes.io/mirror-target-serviceTraffic mirroring targetnamespace/name:port
mse.ingress.kubernetes.io/mirror-percentageMirrored traffic percentage (traffic mirroring)integer (0–100, default: 100)
nginx.ingress.kubernetes.io/backend-protocolBackend protocol"HTTPS" or "GRPC"
nginx.ingress.kubernetes.io/load-balanceLoad balancing algorithmstring (default: round_robin)
nginx.ingress.kubernetes.io/upstream-hash-byConsistent hashing keystring
mse.ingress.kubernetes.io/warmupService warmup duration (seconds)integer
nginx.ingress.kubernetes.io/affinitySession affinity type"cookie"
nginx.ingress.kubernetes.io/session-cookie-nameSession affinity cookie namestring (default: INGRESSCOOKIE)
nginx.ingress.kubernetes.io/session-cookie-max-ageSession affinity cookie expiry (seconds)integer
mse.ingress.kubernetes.io/connection-policy-tcp-max-connectionMax gateway-to-backend connections (connection pool)integer
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection-per-endpointMax connections per endpoint (connection pool)integer
mse.ingress.kubernetes.io/connection-policy-http-max-request-per-connectionMax requests per connection (connection pool)integer
mse.ingress.kubernetes.io/tls-min-protocol-versionMinimum TLS versionstring (default: TLSv1.0)
mse.ingress.kubernetes.io/tls-max-protocol-versionMaximum TLS versionstring (default: TLSv1.3)
nginx.ingress.kubernetes.io/ssl-cipherTLS cipher suitesstring
nginx.ingress.kubernetes.io/proxy-ssl-secretGateway client certificate for mTLSsecretNamespace/secretName

Canary release

MSE Ingress supports canary releases based on request headers, query parameters, cookies, or weights. All methods require the nginx.ingress.kubernetes.io/canary: "true" annotation on the canary Ingress resource. MSE Ingress supports an unlimited number of simultaneous canary versions, unlike NGINX Ingress and ALB Ingress, which support at most two service versions during a canary release.

Matching method precedence — when multiple methods are configured simultaneously, MSE Ingress applies them in this order:

PriorityMethodAnnotation
1 (highest)Header-basedcanary-by-header
1 (highest)Query parameter-basedcanary-by-query
2Cookie-basedcanary-by-cookie
3 (lowest)Weight-basedcanary-weight

Header-based canary release

Choose between two header matching modes:

ModeAnnotationsBehavior
Key-onlycanary-by-header onlyRoutes to canary when the header value is always. All other values go to the base version.
Key + exact valuecanary-by-header + canary-by-header-valueRoutes to canary only when both the header key and value match exactly. All other values go to the base version.

Example 1: Route to canary when `mse: always`

Requests with header mse: always go to demo-service-canary. All others go to demo-service.

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "mse"  # Route to canary when mse: always
  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: Exact

Kubernetes 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: 80

Example 2: Route to multiple canary versions by header value

Requests with mse: v1 go to demo-service-canary-v1, mse: v2 go to demo-service-canary-v2, and all others go to demo-service.

Kubernetes v1.19 or later:

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"  # Exact match: routes when mse=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"  # Exact match: routes when mse=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: Exact

Kubernetes 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: 80

Query parameter-based canary release

Choose between two query parameter matching modes:

ModeAnnotationsBehavior
Key-onlycanary-by-query onlyRoutes to canary when the query parameter key matches and its value is always.
Key + exact valuecanary-by-query + canary-by-query-valueRoutes to canary only when both the query parameter key and value match exactly.

Header-based and query parameter-based canary releases can be combined. When both are configured, a request must satisfy both conditions to reach the canary version.

Example 1: Route to canary when query parameter `canary=gray`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    mse.ingress.kubernetes.io/canary-by-query: "canary"        # Query param name
    mse.ingress.kubernetes.io/canary-by-query-value: "gray"    # Exact value to match
  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: Exact

Kubernetes 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: 80

Example 2: Combine query parameter and header conditions

Requests with query parameter canary=gray AND header x-user-id: test go to the canary version. All others go to the base version.

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    mse.ingress.kubernetes.io/canary-by-query: "canary"         # Both conditions must match
    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: Exact

Kubernetes 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: 80

Cookie-based canary release

Use nginx.ingress.kubernetes.io/canary-by-cookie to route based on cookies. Requests go to the canary version only when the cookie value is always.

Custom cookie values are not supported. The cookie value must be always.

Example: Route to canary when `demo=always`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-cookie: "demo"  # Routes when cookie demo=always
  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: Exact

Kubernetes 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: 80

Weight-based canary release

AnnotationDescription
nginx.ingress.kubernetes.io/canary-weightPercentage of requests sent to the canary version. Integer from 0 to 100.
nginx.ingress.kubernetes.io/canary-weight-totalTotal weight denominator. Default: 100.

Example: Split traffic across two canary versions and a base version

demo-service-canary-v1 receives 30%, demo-service-canary-v2 receives 20%, and demo-service receives the remaining 50%.

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "30"  # 30% of traffic
  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"  # 20% of traffic
  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: Exact

Kubernetes 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: 80

Service subset

A service subset routes requests to a specific subset of Pods within a single Kubernetes Service — useful when one Service spans multiple Deployments (for example, a base version and a canary version).

Use pod labels in MseIngressConfig

Use the mse.ingress.kubernetes.io/service-subset annotation. By default, MSE Ingress maps this to the Pod label prefix opensergo.io/canary:

  • Setting the annotation to "" or base routes requests to Pods whose labels do not have the opensergo.io/canary prefix (base Pods).

  • Setting it to any other value (for example, gray) routes requests to Pods with the label opensergo.io/canary-gray: gray.

Example: Route by user ID header to different pod subsets

The go-httpbin Service is backed by two Deployments — go-httpbin-base (no canary label) and go-httpbin-gray (label opensergo.io/canary-gray: gray). Requests with header x-user-id: test go to the gray Pods; all others go to the base Pods.

Service and Deployment definitions:

# go-httpbin Kubernetes Service
apiVersion: v1
kind: Service
metadata:
  name: go-httpbin
  namespace: default
spec:
  ports:
    - port: 8080
      protocol: TCP
  selector:
    app: go-httpbin
---
# Base deployment (no 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 (canary label: opensergo.io/canary-gray: gray)
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-httpbin

Ingress configurations — Kubernetes v1.19 or later:

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"
    mse.ingress.kubernetes.io/service-subset: gray  # Route to pods with label opensergo.io/canary-gray: 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: ""  # Route to pods without the opensergo.io/canary prefix
  name: demo
  namespace: default
spec:
  ingressClassName: mse
  rules:
    - http:
        paths:
          - backend:
              service:
                name: go-httpbin
                port:
                  number: 8080
            path: /test
            pathType: Exact

Kubernetes 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"
    mse.ingress.kubernetes.io/service-subset: gray  # Route to pods with label opensergo.io/canary-gray: 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: ""  # Route to pods without the opensergo.io/canary prefix
  name: demo
  namespace: default
spec:
  ingressClassName: mse
  rules:
    - http:
        paths:
          - path: /test
            backend:
              serviceName: go-httpbin
              servicePort: 8080

Use custom labels

Combine mse.ingress.kubernetes.io/service-subset with mse.ingress.kubernetes.io/subset-labels to route based on any custom Pod label — not just the opensergo.io/canary prefix.

When subset-labels is set, the subset is no longer mapped to the opensergo.io/canary label prefix.

Example: Route by custom `version` label

The gray Deployment has the label version: gray. Requests with header x-user-id: test go to the gray Pods; all others go to the base Pods.

Service and Deployment definitions:

# go-httpbin Kubernetes 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 (custom label: version: gray)
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-httpbin

Ingress configurations — Kubernetes v1.19 or later:

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"
    mse.ingress.kubernetes.io/service-subset: gray         # Subset name
    mse.ingress.kubernetes.io/subset-labels: version gray  # Map subset name to pod label 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: Exact

Kubernetes 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"
    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: 8080

CORS

Cross-Origin Resource Sharing (CORS) allows web applications to access resources from a different origin. For background, see Cross-Origin Resource Sharing (CORS).

AnnotationDescription
nginx.ingress.kubernetes.io/enable-corsEnable CORS.
nginx.ingress.kubernetes.io/cors-allow-originAllowed third-party origins, comma-separated. Wildcards (*) supported. Default: * (all origins).
nginx.ingress.kubernetes.io/cors-allow-methodsAllowed HTTP methods, comma-separated. Wildcards supported. Default: GET,PUT,POST,DELETE,PATCH,OPTIONS.
nginx.ingress.kubernetes.io/cors-allow-headersAllowed request headers, comma-separated. Wildcards supported. Default: DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization.
nginx.ingress.kubernetes.io/cors-expose-headersResponse headers exposed to the browser, comma-separated.
nginx.ingress.kubernetes.io/cors-allow-credentialsAllow credentials in CORS requests. Default: false.
nginx.ingress.kubernetes.io/cors-max-agePreflight result cache duration in seconds. Default: 1728000.

Example: Allow CORS from `example.com` with restricted methods and no credentials

Kubernetes v1.19 or later:

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"   # Restrict to specific origin
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET,POST"     # Only allow GET and POST
    nginx.ingress.kubernetes.io/cors-allow-headers: "X-Foo-Bar"
    nginx.ingress.kubernetes.io/cors-allow-credentials: "false"    # No credentials
  name: demo
spec:
  ingressClassName: mse
  rules:
    - http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /hello
            pathType: Exact

Kubernetes 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: 80

Regular expression match

In addition to the standard Exact and Prefix path types, MSE Ingress supports regular expression matching. Set nginx.ingress.kubernetes.io/use-regex: 'true' to enable it.

Example: Route paths starting with `/app` or `/test`

Kubernetes v1.19 or later:

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: Prefix

Kubernetes 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: 8080

Path and host rewrite

Rewrite the path or host in a request before MSE Ingress forwards it to the backend service.

AnnotationDescription
nginx.ingress.kubernetes.io/rewrite-targetDestination path for the rewrite. Capture groups are supported.
nginx.ingress.kubernetes.io/upstream-vhostDestination host for the rewrite.

Path rewrite

Example 1: Rewrite `/test` to `/dev`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: "/dev"  # Rewrite destination
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Example 2: Strip the `/v1` prefix (rewrite `/v1/xxx` to `/xxx`)

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: "/$1"  # $1 captures the path after /v1/
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /v1/(.*)
            pathType: Prefix

Kubernetes 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: 80

Example 3: Replace the `/v1` prefix with `/v2` (rewrite `/v1/xxx` to `/v2/xxx`)

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: "/v2/$1"  # Prepend /v2 to the captured path
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /v1/(.*)
            pathType: Prefix

Kubernetes 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: 80

Host rewrite

Example: Rewrite `example.com/test` host to `test.com`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/upstream-vhost: "test.com"  # Rewrite the Host header to test.com
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Redirect

HTTP-to-HTTPS redirect

AnnotationDescription
nginx.ingress.kubernetes.io/ssl-redirectForce redirect of HTTP requests to HTTPS.
nginx.ingress.kubernetes.io/force-ssl-redirectForce redirect of HTTP requests to HTTPS.

MSE Ingress treats both annotations identically — both unconditionally redirect HTTP to HTTPS.

Example: Redirect `http://example.com/test` to `https://example.com/test`

Kubernetes v1.19 or later:

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: Exact

Kubernetes 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: 80

Permanent redirect

AnnotationDescription
nginx.ingress.kubernetes.io/permanent-redirectDestination URL for a permanent redirect. Must include the scheme (HTTP or HTTPS).
nginx.ingress.kubernetes.io/permanent-redirect-codeHTTP status code for the redirect. Default: 301.

Example: Permanently redirect `http://example.com/test` to `http://example.com/app`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/permanent-redirect: "http://example.com/app"  # Must include scheme
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Temporary redirect

Use nginx.ingress.kubernetes.io/temporal-redirect to specify the destination URL for a temporary redirect. The URL must include the scheme (HTTP or HTTPS).

Example: Temporarily redirect `http://example.com/test` to `http://example.com/app`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/temporal-redirect: "http://example.com/app"  # Must include scheme
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Header control

Add, update, or remove request and response headers before MSE Ingress forwards traffic.

Request header control

AnnotationDescription
mse.ingress.kubernetes.io/request-header-control-addAdd a header to forwarded requests. If the header already exists, the new value is appended. Single header: key-value pair. Multiple headers: use the YAML `` block scalar, one key-value pair per line.
mse.ingress.kubernetes.io/request-header-control-updateUpdate a header in forwarded requests. If the header already exists, the new value overwrites it. Single header: key-value pair. Multiple headers: use the YAML `` block scalar, one key-value pair per line.
mse.ingress.kubernetes.io/request-header-control-removeRemove a header from forwarded requests. Single header: key name. Multiple headers: comma-separated key names.

Example 1: Add `foo: bar` and `test: true` to all requests to `example.com/test`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/request-header-control-add: |  # Block scalar for multiple headers
      foo bar    # Adds header foo: bar
      test true  # Adds header test: true
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Example 2: Add a stage header to identify canary traffic

When the request header is mse: v1, the request goes to the canary version demo-service-canary-v1 with stage: gray added. All other requests go to demo-service with stage: production added.

Kubernetes v1.19 or later:

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"  # Adds 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"  # Adds stage: production
  name: demo
spec:
  ingressClassName: mse
  rules:
    - http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /hello
            pathType: Exact

Kubernetes 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:
    - host: example.com
      http:
        paths:
          - path: /hello
            backend:
              serviceName: demo-service
              servicePort: 80

Response header control

AnnotationDescription
mse.ingress.kubernetes.io/response-header-control-addAdd a header to responses before forwarding to the client. If the header already exists, the new value is appended. Single header: key-value pair. Multiple headers: use the YAML `` block scalar, one key-value pair per line.
mse.ingress.kubernetes.io/response-header-control-updateUpdate a header in responses before forwarding to the client. If the header already exists, the new value overwrites it. Single header: key-value pair. Multiple headers: use the YAML `` block scalar, one key-value pair per line.
mse.ingress.kubernetes.io/response-header-control-removeRemove a header from responses before forwarding to the client. Single header: key name. Multiple headers: comma-separated key names.

Example: Remove the `req-cost-time` header from responses to `example.com/test`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/response-header-control-remove: "req-cost-time"  # Removes this response header
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Retry

MSE Ingress supports route-level automatic retries. Configure retry conditions based on your backend's error patterns.

AnnotationDescription
nginx.ingress.kubernetes.io/proxy-next-upstream-triesMaximum number of retry attempts. Default: 3.
nginx.ingress.kubernetes.io/proxy-next-upstream-timeoutRetry timeout in seconds. Default: no timeout.
nginx.ingress.kubernetes.io/proxy-next-upstreamRetry conditions, comma-separated. Default: error,timeout. 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, http_403), non_idempotent (retry non-idempotent requests such as POST and PATCH), off (disable retries).

By default, MSE Ingress does not retry non-idempotent requests (POST, PATCH). Set proxy-next-upstream to non_idempotent to enable retries for these request types.

Example: Retry on 502 with a 5-second timeout, including non-idempotent requests

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-next-upstream-tries: "2"               # Retry up to 2 times
    nginx.ingress.kubernetes.io/proxy-next-upstream-timeout: "5"             # Abort retries after 5s
    nginx.ingress.kubernetes.io/proxy-next-upstream: "http_502,non_idempotent"  # Retry on 502 and POST/PATCH
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Access control based on IP whitelists and blacklists

MSE Ingress supports IP-based access control at two levels:

  • Route level takes precedence over domain-name level.

  • Domain-name level applies to all routes under a domain.

Route-level IP whitelist and blacklist

AnnotationDescription
nginx.ingress.kubernetes.io/whitelist-source-rangeIP whitelist for a specific route. Accepts IP addresses and CIDR blocks, comma-separated.
mse.ingress.kubernetes.io/blacklist-source-rangeIP blacklist for a specific route. Accepts IP addresses and CIDR blocks, comma-separated.

Example 1: Allow access to `example.com/test` only from `1.1.xx.xx`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/whitelist-source-range: 1.1.X.X  # Only allow this IP
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Example 2: Block access to `example.com/test` from `2.2.xx.xx`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/blacklist-source-range: 2.2.2.2  # Block this IP
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Domain-level IP whitelist and blacklist

AnnotationDescription
mse.ingress.kubernetes.io/domain-whitelist-source-rangeIP whitelist applied to all routes under a domain. Route-level whitelists take precedence. Accepts IP addresses and CIDR blocks, comma-separated.
mse.ingress.kubernetes.io/domain-blacklist-source-rangeIP blacklist applied to all routes under a domain. Route-level blacklists take precedence. Accepts IP addresses and CIDR blocks, comma-separated.

Example 1: Allow all routes under `example.com` from `1.1.xx.xx` and `2.2.xx.xx`

Kubernetes v1.19 or later:

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  # Domain-level: applies to all routes
  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: Exact

Kubernetes 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: 80

Example 2: Combine domain-level and route-level whitelists

Allow all routes under example.com from 1.1.xx.xx and 2.2.xx.xx, but restrict the /order route to 3.3.xx.xx only.

Kubernetes v1.19 or later:

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  # Domain-level: /test and /app
  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  # Route-level takes precedence for /order
  name: demo-route
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /order
            pathType: Exact

Kubernetes 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: 80

Single-gateway throttling

Important

Throttling is applied per gateway replica, not across the entire gateway cluster. To throttle traffic cluster-wide, use global rate limiting instead.

When the request rate exceeds the threshold on a single gateway instance, MSE Ingress returns local_rate_limited.

Response status codes when throttling is triggered:

  • Gateway version earlier than v1.2.23: 503

  • Gateway version v1.2.23 or later: 429

The burst limit formula: burst limit = rate × `route-limit-burst-multiplier` (default multiplier: 5).

AnnotationDescription
mse.ingress.kubernetes.io/route-limit-rpmMaximum requests per minute (RPM) per gateway replica. Burst limit = value × route-limit-burst-multiplier.
mse.ingress.kubernetes.io/route-limit-rpsMaximum requests per second (RPS) per gateway replica. Burst limit = value × route-limit-burst-multiplier.
mse.ingress.kubernetes.io/route-limit-burst-multiplierBurst multiplier for RPM and RPS limits. Default: 5.

Example 1: Limit to 100 RPM with a burst of 200

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/route-limit-rpm: "100"           # 100 requests per minute
    mse.ingress.kubernetes.io/route-limit-burst-multiplier: "2"  # Burst = 100 × 2 = 200
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Example 2: Limit to 10 RPS with the default burst multiplier of 5 (burst: 50)

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/route-limit-rps: "10"
    # Burst multiplier defaults to 5; burst limit = 10 × 5 = 50
    # 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: Exact

Kubernetes earlier than v1.19:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/route-limit-rps: "10"
    # Burst multiplier defaults to 5; burst limit = 10 × 5 = 50
    # 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: 80

Global rate limiting

MSE Ingress integrates with Sentinel to enforce cluster-wide rate limits at the route level. Use mse.ingress.kubernetes.io/rate-limit to set the maximum RPS across the entire gateway cluster.

Important

Global rate limiting requires MSE Ingress gateway version 1.2.25 or later.

When the rate limit is triggered, the default response is:

  • Response code: 429

  • Response body: sentinel rate limited

Configure the throttling behavior using one of two methods: custom response or redirect. Only one method can be active at a time.

Custom response

AnnotationDescription
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-codeResponse code when rate limiting is triggered. Default: 429.
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-body-typeResponse body type. Default: text. Setting to text sets Content-Type: text/plain; charset=UTF-8. Setting to json sets Content-Type: application/json; charset=UTF-8.
mse.ingress.kubernetes.io/rate-limit-fallback-custom-response-bodyResponse body when rate limiting is triggered. Default: sentinel rate limited.

Example 1: Limit to 100 RPS with default response

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/rate-limit: "100"  # Cluster-wide: max 100 RPS across all replicas
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Example 2: Limit to 100 RPS with custom response code and body

Kubernetes v1.19 or later:

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      # Return 503 instead of 429
    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: Exact

Kubernetes 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: 80

Redirect

Use mse.ingress.kubernetes.io/rate-limit-fallback-redirect-url to specify a redirect URL when the rate limit is triggered.

Example: Limit to 100 RPS, redirect to `example.com/fallback` when triggered

Kubernetes v1.19 or later:

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"  # Redirect on limit
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Global concurrency control

MSE Ingress integrates with Sentinel to enforce cluster-wide concurrency limits at the route level. Use mse.ingress.kubernetes.io/concurrency-limit to set the maximum number of requests being processed simultaneously on a route across the gateway cluster.

Important

Global concurrency control requires MSE Ingress gateway version 1.2.25 or later.

When the concurrency limit is triggered, the default response is:

  • Response code: 429

  • Response body: sentinel rate limited

Configure the behavior using one of two methods: custom response or redirect. Only one method can be active at a time.

Custom response

AnnotationDescription
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-codeResponse code when concurrency control is triggered. Default: 429.
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-body-typeResponse body type. Default: text. Setting to text sets Content-Type: text/plain; charset=UTF-8. Setting to json sets Content-Type: application/json; charset=UTF-8.
mse.ingress.kubernetes.io/concurrency-limit-fallback-custom-response-bodyResponse body when concurrency control is triggered.

Example 1: Limit to 1,000 concurrent requests with default response

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/concurrency-limit: "1000"  # Max 1000 in-flight requests cluster-wide
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Example 2: Limit to 1,000 concurrent requests with custom response

Kubernetes v1.19 or later:

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: Exact

Kubernetes 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: 80

Redirect

Use mse.ingress.kubernetes.io/concurrency-limit-fallback-redirect-url to specify a redirect URL when concurrency control is triggered.

Example: Limit to 1,000 concurrent requests, redirect to `example.com/fallback` when triggered

Kubernetes v1.19 or later:

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: Exact

Kubernetes 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: 80

Traffic mirroring

Traffic mirroring copies incoming requests and forwards them to a secondary service in parallel. The original request continues to its primary backend unaffected, making traffic mirroring useful for operational auditing and shadow testing without impacting production traffic.

When mirrored traffic is forwarded, MSE Ingress automatically appends -shadow to the Host header. For example, a request originally destined for example.com reaches the mirror target with the host example.com-shadow.

AnnotationDescription
mse.ingress.kubernetes.io/mirror-target-serviceDestination service for mirrored traffic. Format: namespace/name:port. namespace is optional (defaults to the Ingress gateway namespace). name is required. port is optional (defaults to the first port).
mse.ingress.kubernetes.io/mirror-percentagePercentage of traffic to mirror. Valid values: 0–100. Default: 100.
Important

If mirror-percentage is omitted, 100% of traffic is mirrored. Confirm your target service can handle the full request volume before enabling mirroring in production.

Example 1: Mirror all traffic to `test/app:8080`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/mirror-target-service: test/app:8080  # namespace/name:port
    # mirror-percentage defaults to 100 — mirrors all traffic
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Example 2: Mirror 10% of traffic to `test/app:8080`

Kubernetes v1.19 or later:

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  # Mirror 10% of traffic
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Backend service protocols: HTTPS and gRPC

By default, MSE Ingress forwards requests to backend containers over HTTP. Use the nginx.ingress.kubernetes.io/backend-protocol annotation to switch to HTTPS or gRPC.

If the Kubernetes Service resource defines a port named grpc or http2, MSE Ingress automatically uses gRPC or HTTP/2 to forward requests — no annotation required. This differs from NGINX Ingress behavior.

Example 1: Forward to a backend over HTTPS

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"  # Use HTTPS to reach the backend
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /
            pathType: Exact

Kubernetes 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: 80

Example 2: Forward to a backend over gRPC

Two methods are available:

Method 1 — Use an annotation:

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/backend-protocol: "GRPC"  # Use gRPC to reach the backend
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Method 2 — Name the Service port grpc:

Kubernetes v1.19 or later:

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   # MSE Ingress auto-detects gRPC when the port is named "grpc"
      port: 80
      protocol: TCP
  selector:
    app: demo-service

Kubernetes 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-service

Load balancing algorithms

Common load balancing algorithms

Use nginx.ingress.kubernetes.io/load-balance to set the algorithm. Default: round_robin.

Valid values:

  • round_robin — distributes requests in rotation

  • least_conn — routes to the backend with the fewest active connections

  • random — distributes requests randomly

Important

Cloud-native gateways do not support the exponentially weighted moving average (EWMA) algorithm. If EWMA is configured, the gateway falls back to round-robin.

Example: Use least connections for `demo-service`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/load-balance: "least_conn"  # Route to backend with fewest connections
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /order
            pathType: Exact

Kubernetes 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: 80

Consistent hashing

Consistent hashing routes requests with the same hash key to the same backend node. Use nginx.ingress.kubernetes.io/upstream-hash-by to set the hash key.

Supported hash key types:

  • NGINX variables: $request_uri (path + query), $host, $remote_addr (client IP)

  • Request headers: $http_<header-name> (for example, $http_x-stage)

  • Query parameters: $arg_<param-name> (for example, $arg_x-stage)

Example 1: Hash by client IP address

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr"  # Hash on client IP
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Example 2: Hash by the `X-Stage` request header

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/upstream-hash-by: "$http_x-stage"  # Hash on X-Stage header value
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Example 3: Hash by the `X-Stage` query parameter

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/upstream-hash-by: "$arg_x-stage"  # Hash on x-stage query parameter value
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Service warmup

The service warmup feature gradually increases the traffic sent to a newly started backend node over a specified time window, reducing the risk of overloading a cold node.

Use mse.ingress.kubernetes.io/warmup to set the warmup duration in seconds. Service warmup is disabled by default.

Service warmup is supported only with the round-robin and least-connections load balancing algorithms.

Example: Enable a 30-second warmup for `demo-service`

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/warmup: "30"  # Ramp up traffic to this backend over 30 seconds
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Cookie affinity (session persistence)

Cookie affinity routes requests from the same client to the same backend node. On the first request, MSE Ingress generates a cookie and returns it to the client. Subsequent requests carrying that cookie are always routed to the same node.

AnnotationDescription
nginx.ingress.kubernetes.io/affinityAffinity type. The only valid value is cookie.
nginx.ingress.kubernetes.io/affinity-modeAffinity mode. The default and only valid value is balanced.
nginx.ingress.kubernetes.io/session-cookie-nameCookie name used as the hash key. Default: INGRESSCOOKIE.
nginx.ingress.kubernetes.io/session-cookie-pathCookie path set when the cookie does not exist. Default: /.
nginx.ingress.kubernetes.io/session-cookie-max-ageCookie expiry in seconds. Default: session-scoped (no explicit expiry).
nginx.ingress.kubernetes.io/session-cookie-expiresCookie expiry in seconds. Default: session-scoped.

Example 1: Enable cookie affinity with default settings

Cookie name: INGRESSCOOKIE, path: /, lifecycle: session-scoped.

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/affinity: "cookie"  # Only supported type
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Example 2: Enable cookie affinity with a custom cookie name and 10-second expiry

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "test"        # Custom cookie name
    nginx.ingress.kubernetes.io/session-cookie-max-age: "10"       # 10-second expiry
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Connection pool between a gateway and a backend service

Configure a connection pool to cap the number of connections between the gateway and a backend service. This prevents backend overload and improves stability.

AnnotationDescription
mse.ingress.kubernetes.io/connection-policy-tcp-max-connectionMaximum total connections between the gateway and the backend service.
mse.ingress.kubernetes.io/connection-policy-tcp-max-connection-per-endpointMaximum connections between the gateway and a single backend endpoint (Pod).
mse.ingress.kubernetes.io/connection-policy-http-max-request-per-connectionMaximum requests on a single connection between the gateway and the backend service.

Example: Set max connections to 10 total, 2 per endpoint

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/connection-policy-tcp-max-connection: 10           # Total connection cap
    mse.ingress.kubernetes.io/connection-policy-tcp-max-connection-per-endpoint: 2  # Per-pod connection cap
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

TLS versions and cipher suites

By default, MSE Ingress supports TLS versions from TLSv1.0 to TLSv1.3. 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 restrict TLS versions and cipher suites per domain:

AnnotationDescription
mse.ingress.kubernetes.io/tls-min-protocol-versionMinimum TLS version. Default: TLSv1.0. Valid values: TLSv1.0, TLSv1.1, TLSv1.2, TLSv1.3.
mse.ingress.kubernetes.io/tls-max-protocol-versionMaximum TLS version. Default: TLSv1.3.
nginx.ingress.kubernetes.io/ssl-cipherComma-separated TLS cipher suites. Applies only to TLS handshakes using TLSv1.0–1.2.

Example: Restrict `example.com` to TLSv1.2 only

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    mse.ingress.kubernetes.io/tls-min-protocol-version: "TLSv1.2"  # Set both min and max to TLSv1.2
    mse.ingress.kubernetes.io/tls-max-protocol-version: "TLSv1.2"  # to enforce TLSv1.2 only
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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: 80

Mutual TLS between gateways and backend services

By default, MSE Ingress uses HTTP to forward requests to backend services. When nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" is set, MSE Ingress uses one-way TLS — the gateway validates the backend's certificate, which must be issued by a trusted certificate authority (CA).

For mutual TLS (mTLS), both parties authenticate each other: the gateway validates the backend's certificate, and the backend validates the gateway's certificate.

AnnotationDescription
nginx.ingress.kubernetes.io/proxy-ssl-secretClient certificate used by the gateway for the backend to authenticate it. Format: secretNamespace/secretName.
nginx.ingress.kubernetes.io/proxy-ssl-nameServer Name Indication (SNI) used during the TLS handshake.
nginx.ingress.kubernetes.io/proxy-ssl-server-nameEnable or disable SNI during the TLS handshake.

Example: Configure mTLS with a gateway certificate from a Kubernetes secret

Kubernetes v1.19 or later:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-ssl-secret: "default/gateway-cert"  # secretNamespace/secretName
  name: demo
spec:
  ingressClassName: mse
  rules:
    - host: example.com
      http:
        paths:
          - backend:
              service:
                name: demo-service
                port:
                  number: 80
            path: /test
            pathType: Exact

Kubernetes 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