使用 `docker-compose` 模拟 Istio 的流量镜像(traffic mirroring)

解读

国内云原生面试中,“不用 Istio 也能实现流量镜像” 是高频追问,目的是考察候选人是否真正理解 “镜像=旁路复制” 的本质,而不是只会背 Istio CRD。
Docker Compose 虽然没有 VirtualServicemirror 字段,但可以通过 “双服务+七层代理” 的方案,在本地开发环境低成本复现生产级观测、灰度、压测场景。
面试官期待你给出 可一行行复现的 Compose 模板,并解释 镜像流量对业务零侵入、零返回 的关键细节。

知识点

  1. 流量镜像定义:将生产请求 完整复制一份 发到影子实例,影子响应被丢弃,不影响真实调用链。
  2. Compose 网络模型:同一 networks 下容器 DNS 互认,ingress 代理 可作为透明流量锚点。
  3. nginx 流量镜像:使用 mirror 模块(ngx_http_mirror_module)在 七层 完成复制,1:1 实时性 优于 tcpdump+replay。
  4. 零返回关键mirror 指令默认 忽略影子响应;若用 Envoy,需设置 shadow 集群 request_mirror_policyruntime_fraction=100% 并关闭 shadow_alpn
  5. 资源隔离:影子服务 单独 deployment(Compose 里即独立 service),避免 CPU 抢占导致基线失真。
  6. 可观测性:影子容器内 开启 DEBUG 日志 并挂载同一 promtail sidecar,实现 Grafana 实时对比(本地可用 grafana/agent 容器替代)。
  7. 国内镜像加速nginx:alpinehttpbin 镜像需加 registry.cn-hangzhou.aliyuncs.com 前缀,避免面试现场拉取超时。
  8. 安全合规:影子环境 禁止写库,通过 只读账号Mock 服务 兜底,满足国内金融客户 等保 要求。

答案

给出一份 单文件 docker-compose.yml,可在 2 分钟内拉起,真实请求 100% 镜像 到影子容器,且影子响应被丢弃。

目录结构

traffic-mirror/
├── docker-compose.yml
├── nginx.conf

docker-compose.yml

version: "3.9"

services:
  proxy:
    image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx:1.25-alpine
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "80:80"
    networks:
      - mesh
    depends_on:
      - primary
      - shadow

  primary:
    image: registry.cn-hangzhou.aliyuncs.com/google_containers/httpbin:latest
    networks:
      - mesh
    environment:
      - GUNICORN_CMD_ARGS="--access-logfile -"
    command: ["gunicorn", "-b", "0.0.0.0:80", "httpbin:app"]

  shadow:
    image: registry.cn-hangzhou.aliyuncs.com/google_containers/httpbin:latest
    networks:
      - mesh
    environment:
      - GUNICORN_CMD_ARGS="--access-logfile -"
    command: ["sh", "-c", "echo '*** SHADOW START ***' && gunicorn -b 0.0.0.0:80 httpbin:app"]

networks:
  mesh:
    driver: bridge

nginx.conf

events { worker_connections 1024; }
http {
    upstream primary { server primary:80; }
    upstream shadow   { server shadow:80; }

    server {
        listen 80;
        location / {
            mirror /shadow;
            proxy_pass http://primary;
        }
        location = /shadow {
            internal;
            proxy_pass http://shadow$request_uri;
            proxy_set_header Host $host;
            proxy_set_header X-Shadow-Request-ID $request_id;
        }
    }
}

启动与验证

docker compose up -d
# 发一条请求
curl localhost/get?foo=bar
# 观察 shadow 日志,出现相同请求但客户端只收到一次响应
docker compose logs -f shadow

面试现场加分话术
mirror 指令由 nginx 原生支持,无需 iptables,性能损耗 <1%;若后续迁到 K8s,只需把 nginx 替换成 Envoy,同一套 shadow 概念平移到 Istio VirtualService 即可。”

拓展思考

  1. 动态采样:通过 mirror_request_body off;map 变量实现 按 Header 灰度,例如只镜像带 X-Test: stress 的请求,模拟生产压测 而不影响全量流量。
  2. 响应对比:在 shadow 容器内 注入 diff sidecar,把真实响应与影子响应做 JSON 字段级对比零人工回归 发现兼容性问题。
  3. 出口流量镜像:若后端是 gRPC,可把 nginx 换成 Envoy 容器,用 envoy.yamlrequest_mirror_policy同一套 Compose 文件 只需换镜像即可。
  4. 资源限制:国内 4C8G 笔记本跑全量镜像容易 OOM,为 shadow 加 mem_limit: 512m,并用 cpus: 0.5 模拟 低配灰度节点,面试时展示 cgroup 限制 意识。
  5. 合规脱敏:镜像流量可能带 手机号、身份证,在 nginx 层加 sub_filterLua 脚本字段打码,满足 《个人信息保护法》 要求,体现 国内落地经验