如何在 Istio 中为 Nginx 应用正确注入 Sidecar?

来源:站长素材作者:仓本头衔:网络博主
导读:本期聚焦于仓本创作的《如何在 Istio 中为 Nginx 应用正确注入 Sidecar?》,敬请观看详情。把 Nginx 作为服务网格入口或业务反向代理时,直接套用默认 Istio 注入配置,常出现端口冲突、健康检查失败或流量被 sidecar 拦截后无法回环等问题。本文围绕 Nginx 与 Istio Sidecar 的配合,梳理注入开关、容器端口规划、探针调整和流量验证步骤,帮助你在不破坏 Nginx 原有转发逻辑的前提下平稳接入服务网格。文中会通过实际 Deployment 配置和命令行操作,说明如何避开常见的 sidecar 抢占流量、Pod 无法就绪等坑,并验证 Nginx 转发路径经过 sidecar 后的可观测性。

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

如何在 Istio 中为 Nginx 应用正确注入 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_ANYREGISTRY_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

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。