proxy-mirror
The proxy-mirror plugin copies incoming requests to a secondary upstream while the gateway sends the original requests to their configured upstream. It can mirror every request or sample a portion of traffic for troubleshooting, security inspection, testing, and analytics. The gateway ignores responses from the mirror upstream.
Examples
Mirroring requires a secondary upstream that the gateway can reach. The following examples use NGINX as that upstream and then configure the timeouts that govern mirrored requests.
Mirror Partial Traffic
The following example mirrors approximately 50% of the requests to a secondary NGINX service while all requests continue to the route's original upstream.
Start a sample NGINX server for receiving mirrored traffic:
Set GATEWAY_CONTAINER to the name of the running APISIX or API7 Gateway container. Create a dedicated network and connect the gateway to it:
export GATEWAY_CONTAINER=replace-with-gateway-container-name
docker network create gateway-mirror-net
docker network connect gateway-mirror-net "$GATEWAY_CONTAINER"Start NGINX on the same network:
docker run -d --name mirror-receiver \
--network gateway-mirror-net \
-p 127.0.0.1:8081:80 \
nginx:1.30.5-alpineWait for NGINX to become available:
until curl -fsS "http://127.0.0.1:8081" > /dev/null; do
sleep 1
doneSet the mirror receiver URL used by the Admin API and ADC examples:
export MIRROR_RECEIVER_URL=http://mirror-receiverCreate a Kubernetes manifest for the NGINX deployment and service:
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: aic
name: mirror-receiver
spec:
replicas: 1
selector:
matchLabels:
app: mirror-receiver
template:
metadata:
labels:
app: mirror-receiver
spec:
containers:
- name: nginx
image: nginx:1.30.5-alpine
ports:
- containerPort: 80
readinessProbe:
httpGet:
path: /
port: 80
---
apiVersion: v1
kind: Service
metadata:
namespace: aic
name: mirror-receiver
spec:
selector:
app: mirror-receiver
ports:
- name: http
port: 80
targetPort: 80Apply the manifest to your cluster:
kubectl apply -f mirror-receiver.yamlWait for NGINX to become available:
kubectl rollout status -n aic deployment/mirror-receiverSet the mirror receiver URL used by the Admin API and ADC examples:
export MIRROR_RECEIVER_URL=http://mirror-receiver.aic.svcCreate a route with proxy-mirror:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d @- <<EOF
{
"id": "traffic-mirror-route",
"uri": "/get",
"plugins": {
"proxy-mirror": {
"host": "$MIRROR_RECEIVER_URL",
"sample_ratio": 0.5
}
},
"upstream": {
"nodes": {
"httpbin.org": 1
},
"type": "roundrobin"
}
}
EOFservices:
- name: proxy-mirror-service
labels:
docs-example: proxy-mirror
routes:
- name: traffic-mirror-route
uris:
- /get
plugins:
proxy-mirror:
host: "${MIRROR_RECEIVER_URL}"
sample_ratio: 0.5
upstream:
type: roundrobin
nodes:
- host: httpbin.org
port: 80
weight: 1Preview changes owned by this example and confirm that the diff contains no unintended updates or deletions:
adc diff -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=proxy-mirrorSynchronize the reviewed service configuration:
adc sync -f adc.yaml \
--include-resource-type service \
--label-selector docs-example=proxy-mirrorapiVersion: v1
kind: Service
metadata:
namespace: aic
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: aic
name: proxy-mirror-plugin-config
spec:
plugins:
- name: proxy-mirror
config:
host: "http://mirror-receiver.aic.svc"
sample_ratio: 0.5
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: aic
name: traffic-mirror-route
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /get
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: proxy-mirror-plugin-config
backendRefs:
- name: httpbin-external-domain
port: 80apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: aic
name: httpbin-external-domain
spec:
ingressClassName: apisix
externalNodes:
- type: Domain
name: httpbin.org
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: aic
name: traffic-mirror-route
spec:
ingressClassName: apisix
http:
- name: traffic-mirror-route
match:
paths:
- /get
upstreams:
- name: httpbin-external-domain
plugins:
- name: proxy-mirror
enable: true
config:
host: "http://mirror-receiver.aic.svc"
sample_ratio: 0.5Apply the configuration to your cluster:
kubectl apply -f proxy-mirror-ic.yaml❶ host: configure the scheme and address of the upstream that receives mirrored requests.
❷ sample_ratio: configure the sampling ratio to 0.5 to mirror 50% of the traffic.
Send 20 requests to the route:
for i in $(seq 1 20); do
curl -fsS "http://127.0.0.1:9080/get" > /dev/null || exit 1
doneAll 20 requests to the original upstream should succeed. The command exits early if any request returns an error.
Inspect the NGINX access logs:
docker logs mirror-receiver 2>&1 | grep '"GET /get HTTP/1.1" 404'kubectl logs -n aic deployment/mirror-receiver | grep '"GET /get HTTP/1.1" 404'The logs should contain approximately 10 requests. The exact number varies because each request is sampled independently. NGINX returns 404 for mirrored requests because its default configuration does not define /get; this response is ignored and does not affect the response from the original upstream.
Configure Mirroring Timeouts
The following example updates the connect, read, and send timeouts used for mirrored requests. Shorter timeouts bound how long requests to the mirror upstream hold connections and consume gateway resources when that upstream is slow or unavailable.
The default connect, read, and send timeouts are 60 seconds. Configure the gateway static settings to change them:
Add or update this section in the gateway configuration file:
plugin_attr:
proxy-mirror:
timeout:
connect: 2000ms
read: 2000ms
send: 2000msReload the gateway for changes to take effect.
For Helm deployments, update the chart values that render plugin_attr.proxy-mirror. Keep the rest of your values file unchanged.
For the APISIX Helm chart, set the following values:
apisix:
pluginAttrs:
proxy-mirror:
timeout:
connect: 2000ms
read: 2000ms
send: 2000msFor the API7 Gateway Helm chart, set the following values:
pluginAttrs:
proxy-mirror:
timeout:
connect: 2000ms
read: 2000ms
send: 2000msThen apply the values file with the chart used for this gateway release:
helm upgrade <release-name> <chart-name> -n <namespace> -f values.yaml