Traffic mirroring, also called shadowing, sends a copy of live traffic from your production cluster to a staging cluster without affecting the primary request path. Use this technique to run stress tests or troubleshoot production issues without interrupting your services.
This guide shows how to configure the NGINX Ingress controller to mirror 100% of traffic from one Container Service for Kubernetes (ACK) cluster to another.
Prerequisites
Before you begin, ensure that you have:
Two ACK clusters — one for production (K8s Product Cluster) and one for staging (K8s Stage Cluster). See Create an ACK managed cluster
The NGINX Ingress controller v1.2.1 or later installed. See Manage the NGINX Ingress controller
kubectl configured with the kubeconfig file for each cluster. See Connect to ACK clusters by using kubectl
Use cases
Stress testing before release: Mirror production traffic to staging to simulate real-world workloads — including abnormal traffic — before releasing a new system. This gives you a more accurate load profile than synthetic benchmarks.
Troubleshooting production issues: When you can't locate a performance bottleneck in production, mirror traffic to staging to reproduce and diagnose the issue safely.
How it works
All requests destined for example.com on the production cluster are replicated and sent to example1.com on the staging cluster. The staging cluster receives the mirrored traffic without any changes to the production cluster's routing.
The NGINX Ingress controller uses the nginx.ingress.kubernetes.io/mirror-target annotation to duplicate requests to a specified destination. Use the mirror-host annotation to set the exact Host header value for the mirrored request.
Mirroring annotations
| Annotation | Type | Description |
|---|---|---|
nginx.ingress.kubernetes.io/mirror-target | string | Destination URL for mirrored traffic. Applies to HTTP and HTTPS only. See ingress-nginx mirror documentation. |
nginx.ingress.kubernetes.io/mirror-host | string | Overrides the Host header for the mirrored request. |
nginx.ingress.kubernetes.io/mirror-request-body | string | Set to "off" to exclude the request body from mirrored traffic. Delete this annotation to include the body. |
Step 1: Deploy an application in the staging cluster
Deploy a receiving application in K8s Stage Cluster. This deployment gives the mirrored traffic a destination. Don't change any production cluster configuration in this step.
Create
my-nginx.yamlwith the following content:apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6 imagePullPolicy: Always name: nginx ports: - containerPort: 80 protocol: TCP restartPolicy: Always --- apiVersion: v1 kind: Service metadata: name: nginx-service spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: NodePort --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-ingress spec: rules: - host: example1.com http: paths: - path: / backend: service: name: nginx-service port: number: 80 pathType: ImplementationSpecificDeploy the application:
kubectl apply -f my-nginx.yamlVerify the Ingress is assigned an external IP address:
kubectl get ing nginx-ingressExpected output:
NAME HOSTS ADDRESS PORTS AGE nginx-ingress example1.com 47.**.**.53 80 8mNote the
ADDRESSvalue (47.**.**.53). You'll use this IP address when configuring traffic mirroring in Step 2.Confirm the staging application is reachable:
curl http://example1.com
Step 2: Configure traffic mirroring in the production cluster
Deploy the application and Ingress in K8s Product Cluster, then add the mirroring annotations to redirect a copy of all traffic to the staging cluster.
Create
my-nginx.yamlwith the following content:apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6 imagePullPolicy: Always name: nginx ports: - containerPort: 80 protocol: TCP restartPolicy: Always --- apiVersion: v1 kind: Service metadata: name: nginx-service spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: NodePortDeploy the application:
kubectl apply -f my-nginx.yamlCreate
my-ingress.yamlwith the mirroring annotations. Replace47.**.**.53with theADDRESSfrom Step 1, andexample1.comwith the staging cluster'sHOSTSvalue:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-ingress annotations: nginx.ingress.kubernetes.io/mirror-target: "http://47.**.**.53$request_uri" nginx.ingress.kubernetes.io/mirror-request-body: "off" nginx.ingress.kubernetes.io/mirror-host: "example1.com" spec: rules: - host: example.com http: paths: - path: / backend: service: name: nginx-service port: number: 80 pathType: ImplementationSpecificDeploy the Ingress:
kubectl apply -f my-ingress.yamlVerify the production Ingress is active:
kubectl get ing nginx-ingressExpected output:
NAME HOSTS ADDRESS PORTS AGE nginx-ingress example.com 39.**.**.54 80 1mConfirm the production application is reachable:
curl http://example.com
Verify traffic mirroring
Send a request to the production domain and check the NGINX Ingress controller logs to confirm traffic is being duplicated to the staging cluster.
Send a request to the production application:
curl http://example.comCheck the NGINX Ingress controller logs in the
kube-systemnamespace of K8s Product Cluster:kubectl -n kube-system logs --tail=0 -f nginx-ingress-controller-674c96ffbc-9mc8nThe log output shows duplicate entries — one for the original request to
example.comand one for the mirrored request forwarded to the staging cluster.