Ingress Nginx连接上游超时但仍返回正常结果问题求助
问题描述
遇到Ingress Nginx间歇性报错:Intermittent ingress nginx upstream timed out (110: Operation timed out) while connecting to upstream,具体情况如下:
- 此错误并非
while reading response header from upstream,且上游服务器响应无延迟。 - 执行
curl https://knotfree.net/api1/getGiantPassword会出现5秒延迟,而curl http://knotfree.io/api1/getGiantPassword无延迟,符合预期。 - 重启Ingress Nginx Pod后,首次请求可正常完成;后续执行上述HTTPS请求时,Nginx会等待5秒后记录超时错误日志:
2024/07/06 18:35:06 [error] 26#26: *556202 upstream timed out (110: Operation timed out) while connecting to upstream, client: 10.3.96.7, server: knotfree.net, request: "GET /api1/getGiantPassword HTTP/2.0", upstream: "http://[fd10:1ba:6d2c:1000:3a5b:26d5:2b5f:56b6]:8085/api1/getGiantPassword", host: "knotfree.net"
- 超时后Nginx会将请求发送至上游,上游服务器记录请求并在毫秒级响应,随后Nginx记录200响应日志:
10.3.96.7 - - [06/Jul/2024:18:45:10 +0000] "GET /api1/getGiantPassword HTTP/2.0" 200 79 "-" "curl/8.6.0" 46 5.002 [knotspace-knotfreeaide-80] [] [fd10:1ba:6d2c:1000:3a5b:26d5:2b5f:56b6]:8085, 10.244.183.182:8085 0, 79 5.000, 0.002 504, 200 6e1e1ab19b8964722f112dc49e642238
最终curl可获取正确输出(随机数)。
疑问
- 为何Nginx既记录连接上游超时错误,又能返回正确的200响应?
- 为何请求有时能完全正常执行?
- “无法连接上游”意味着什么?是否需要配置健康检查?
环境与配置
- 运行环境:Vultr Kubernetes
- Ingress负责HTTPS终止,非安全端点
curl http://knotfree.io/api1/getGiantPassword始终正常 - Ingress配置:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx external-dns.alpha.kubernetes.io/hostname: "knotfree.net" nginx.ingress.kubernetes.io/ssl-redirect: "true" certmanager.k8s.io/issuer: "letsencrypt-prod" certmanager.k8s.io/acme-challenge-type: dns01 certmanager.k8s.io/acme-dns01-provider: vultr name: nginx-ingress spec: rules: - host: "knotfree.net" http: paths: - backend: service: name: knotfreeaide port: number: 80 path: / pathType: Prefix - host: "*.knotfree.net" http: paths: - backend: service: name: knotfreeaide port: number: 80 path: / pathType: Prefix tls: - hosts: - "knotfree.net" - "*.knotfree.net" secretName: wildcard-tls
问题解答
1. 为何Nginx既记录连接上游超时错误,又能返回正确的200响应?
从日志可以明确看到,Nginx首先尝试连接IPv6地址[fd10:1ba:6d2c:1000:3a5b:26d5:2b5f:56b6]:8085时触发了5秒连接超时,因此记录了错误日志。随后Nginx会尝试Service对应的其他后端端点(此处为IPv4地址10.244.183.182:8085),该连接成功且上游毫秒级响应,最终Nginx将200结果返回给客户端。错误日志仅记录首次连接失败事件,后续重试/切换端点成功的流程不会覆盖该错误记录。
2. 为何请求有时能完全正常执行?
重启Ingress Pod后首次请求正常,是因为此时Nginx的上游端点缓存、连接池为空,可能优先选择了可用的IPv4端点,或该时段IPv6端点临时连通。后续请求出现超时,是因为Nginx尝试复用之前的IPv6连接,或通过轮询策略选中了存在连通性问题的IPv6端点,直到切换到IPv4端点才完成请求。
另外,Kubernetes Service的端点列表可能同时包含IPv4和IPv6地址,Nginx默认轮询策略会轮流选择这些端点:选中IPv4时请求正常,选中IPv6时触发连接超时,直到重试或切换端点。
3. “无法连接上游”意味着什么?是否需要配置健康检查?
“无法连接上游”表示Nginx在指定超时时间内,无法与目标上游端点建立TCP连接(并非上游响应缓慢)。结合日志中的IPv6地址,大概率是集群内IPv6网络存在连通性问题,比如Pod IPv6地址不可达、网络策略限制、CNI插件IPv6配置异常等。
需要配置健康检查:默认情况下,Ingress Nginx仅依赖Kubernetes Service的端点状态(仅检查Pod是否Running),无法识别端点的实际连通性。建议通过Ingress Annotation配置Nginx主动健康检查,自动剔除不可达的上游端点:
nginx.ingress.kubernetes.io/upstream-healthcheck-path: "/api1/health" nginx.ingress.kubernetes.io/upstream-healthcheck-port: "8085" nginx.ingress.kubernetes.io/healthcheck-interval: "10s" nginx.ingress.kubernetes.io/healthcheck-timeout: "5s"
此外,也可排查集群IPv6配置是否正常,或通过Service配置强制使用IPv4(若无需IPv6):在Service的spec中设置ipFamilyPolicy: SingleStack和ipFamilies: ["IPv4"]。
内容的提问来源于stack exchange,提问作者Alan Wootton

