把 Nginx 部署到 Istio 服务网格里,并不是简单加一个注解就能完成。Nginx 作为代理或负载均衡器,其工作模型与普通业务服务不同:它对下游端口监听、上游主动发起连接、健康检查行为都有特殊要求,而这些恰好会与 Istio 注入的 Sidecar 产生交互。本文会从注入原理、部署配置、探针调整到流量验证,完整走一遍 Nginx + Istio Sidecar 的实践流程。

Istio Sidecar 注入机制与 Nginx 的关系
Istio 的 Sidecar 通常通过 Kubernetes 的准入控制器自动注入到 Pod 中。默认情况下,只要命名空间带有 istio-injection=enabled 标签,或者 Deployment 上显式添加 sidecar.istio.io/inject=true 注解,创建 Pod 时就会多出一个 istio-proxy 容器。该容器由 Envoy 实现,它会通过 iptables 规则截获进出应用容器的流量,以此实现流量治理、安全策略和可观测性。
Nginx 的角色很常见:它可能是网格入口处的反向代理,把外部请求转发给内部服务;也可能是业务 Pod 前面的本地代理,负责静态资源、缓存或负载均衡。无论哪种情况,一旦注入 Sidecar,Nginx 容器就不再直接与外部或上游服务通信,而是先经过 Envoy。这个差异会导致几个问题:Nginx 监听的端口是否会被 Envoy 劫持?Nginx 主动连接上游时,Envoy 是否能正确识别目标?健康检查是走 TCP 还是 HTTP,是否被 iptables 规则干扰?理解这些交互是后续配置的基础。
从数据流来看,注入 Sidecar 后,入站流量先到达 Pod 的网络命名空间,被 iptables 重定向到 Envoy 的入站端口 15006,再由 Envoy 转发给 Nginx 容器。出站方向同样被重定向到 Envoy 的出站端口 15001,由 Envoy 根据服务发现和路由规则选择目标。因此,Nginx 自身的 listen 配置、proxy_pass 的目标地址,以及连接建立方式都必须与 Envoy 的端口约定兼容,否则容易出现连接拒绝、超时或无限重定向。
准备 Nginx 应用并启用 Sidecar 注入
先准备一个简单的 Nginx Deployment。这里使用 nginx:1.24 镜像,启动一个监听 8080 端口的服务,并通过 ConfigMap 挂载一段基础配置。需要注意的是,Nginx 默认监听 80 端口,但在 Istio 中建议显式指定非特权端口,避免与 Envoy 或 Kubernetes 探针默认端口混淆。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-with-sidecar
labels:
app: nginx-with-sidecar
spec:
replicas: 1
selector:
matchLabels:
app: nginx-with-sidecar
template:
metadata:
labels:
app: nginx-with-sidecar
annotations:
sidecar.istio.io/inject: "true"
spec:
containers:
- name: nginx
image: nginx:1.24
ports:
- containerPort: 8080
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/conf.d
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
volumes:
- name: nginx-config
configMap:
name: nginx-config
---
apiVersion: v1
kind: Service
metadata:
name: nginx-with-sidecar
spec:
selector:
app: nginx-with-sidecar
ports:
- port: 8080
targetPort: 8080
name: http
上面这个清单中,注解 sidecar.istio.io/inject=true 保证了 Deployment 创建出的 Pod 一定会被注入 sidecar。Service 定义了 8080 端口的访问入口。接下来创建 ConfigMap,其中 Nginx 监听 8080 端口,并提供一个 /healthz 端点用于探针。
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
default.conf: |
server {
listen 8080;
server_name _;
location /healthz {
return 200 'ok';
add_header Content-Type text/plain;
}
location / {
proxy_pass http://backend-service.ns.svc.cluster.local:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
注意 proxy_pass 指向的是一个 Kubernetes 服务域名。在 Sidecar 注入后,Nginx 发起的这个出站请求会被 Envoy 截获。Envoy 会解析该域名并根据 Istio 的服务注册信息将流量转发到后端 Pod 的 Sidecar,而不是直接连到后端 Pod 的 IP。这样才能享受 mTLS、重试、熔断等网格能力。如果 proxy_pass 直接写 IP 地址或 localhost,Envoy 可能无法按预期处理,甚至会被当作外部流量。
处理 Nginx 容器与 Sidecar 的网络和探针问题
注入 Sidecar 后最常见的问题是 Pod 一直处于未就绪状态。原因通常是 Nginx 的 readiness 探针被 Envoy 拦截后没有正确转发,或者探针端口与 Envoy 的端口冲突。虽然 Istio 默认会识别 Kubernetes 的 HTTP 探针并改写 iptables 规则以保证探针请求不被劫持,但这依赖于探针的端口和路径在 Pod spec 中显式声明。如果 Nginx 容器没有在 ports 中列出探针端口,Envoy 可能无法识别,导致探针请求被重定向到 15006 端口而失败。
因此,在 Nginx 容器中必须显式声明 containerPort,并且探针要使用该端口。对于 HTTP 探针,Istio 会向 Envoy 注入一个特殊的探针过滤器,使 kubelet 发出的探针请求绕过 iptables 规则直接到达 Nginx。对于 TCP 探针,也可以正常工作,但建议优先使用 HTTP 探针,因为 Envoy 可以更准确地判断应用是否真正可服务。
另一个常见问题是 Nginx 配置中的 listen 地址。如果 Nginx 只监听 127.0.0.1:8080,那么来自 Envoy 的入站流量无法到达,因为 Envoy 注入流量时目标地址是 Pod IP 的 8080 端口,而不是回环地址。务必让 Nginx 监听 0.0.0.0:8080 或直接不指定 IP。默认 Nginx 的 listen 8080; 等价于监听所有地址,所以可以接受。
另外,如果 Nginx 同时承担了 TCP/UDP 代理,例如 stream 模块,需要确认 Istio 是否支持这些协议。标准 Istio 默认针对 HTTP/HTTPS/TCP 有较好支持,但对于 UDP 需要额外配置。多数 Nginx + Sidecar 实践集中在 HTTP 层,因此本文以 HTTP 为主。
验证流量经过 Sidecar 并查看网格数据
应用 Pod 进入 Running 且就绪后,可以先从集群内访问 Nginx Service,确认转发链路的有效性。使用临时 Pod 或直接通过 kubectl exec 进入已有 Pod 发送请求。以下命令从 Nginx Pod 内请求自身服务:
kubectl exec -it nginx-with-sidecar-xxx -c nginx -- curl -v http://localhost:8080/healthz
如果返回 200 和 ok,说明 Nginx 容器本身工作正常。接着验证外部进入网格的流量:从网格内另一个 Pod 访问 nginx-with-sidecar:8080。正确情况下,请求会先到达 nginx Pod 的 Envoy 入站监听 15006,然后由 Envoy 转发给 Nginx 容器。Nginx 再通过 proxy_pass 访问后端服务,出站请求同样经过 Envoy 出站监听 15001。这样整条链路都被网格接管。
要确认流量确实经过 Envoy,可以在 Nginx 容器内执行 curl 访问后端服务,然后在 Kiali 或 Grafana 中查看该服务的调用图。也可以使用 istioctl proxy-config routes 查看 Envoy 生成的路由,确认入站和出站监听器的端口与配置正确。
istioctl proxy-config routes nginx-with-sidecar-xxx -n default istioctl proxy-config listeners nginx-with-sidecar-xxx -n default --port 8080
如果后端服务不是网格内服务,而是外部域名,Nginx 的 proxy_pass 需要让 Envoy 知道这是外部流量。默认情况下 Istio 使用 ALLOW_ANY 或 REGISTRY_ONLY 模式。在 REGISTRY_ONLY 模式下,需要创建 ServiceEntry 来声明外部服务,否则出站请求会被 Envoy 拒绝。对于内部 Kubernetes 服务,只要该服务在网格中且命名空间有注入,Envoy 就能自动发现。
常见排错思路与优化建议
如果遇到 Nginx 访问后端超时,可以优先检查后端服务是否也注入了 Sidecar。只有双方都注入 sidecar 并属于同一网格,才能建立 mTLS 加密通道。如果后端没有注入,Nginx 通过 Envoy 出站到后端的普通 Pod,可能因为 Envoy 期望 mTLS 而失败。可以通过 PeerAuthentication 策略调整为 PERMISSIVE 模式,或给后端也注入 Sidecar。更推荐后者,因为这样才能完整获得网格能力。
另一个容易被忽略的细节是 Nginx 的连接复用与 Envoy 的连接池设置。Nginx 默认使用 HTTP/1.1 与上游通信,并且会保持长连接。Envoy 对上游连接也有连接池和超时配置。如果后端响应较慢或连接数不足,可能出现 503 错误。此时可以调整 Nginx 的 keepalive 参数,以及 Envoy 的 DestinationRule 中的 connectionPool 配置,使两者匹配。
最后,建议在生产环境中将 Nginx 的访问日志输出到 stdout,这样 kubectl logs 可以直接查看,也方便接入日志采集系统。同时利用 Istio 的 Sidecar 资源限制 Envoy 的监听范围,避免不必要的出站流量劫持,尤其是在大型集群中。对于性能敏感的场景,可以为 Nginx 容器请求合理的 CPU 和内存,避免 Envoy 与 Nginx 争抢资源导致延迟抖动。
通过以上步骤,Nginx 可以作为网格中的普通服务接入,同时保留自身强大的代理和负载均衡能力。关键点在于显式声明端口、适配探针、正确设置 proxy_pass 目标、并理解 Envoy 对进出站流量的接管方式。掌握这些,就能在 Istio 中稳定运行 Nginx + Sidecar 的组合。
NginxIstio Sidecar服务网格修改时间:2026-08-22 10:14:05