本文介绍关于Nginx Ingress异常问题的诊断流程、排查思路、常见检查方法和解决方案。
本文目录
类别 | 内容 |
---|---|
诊断流程 | 诊断流程 |
排查思路 | 排查思路 |
常见排查方法 | |
常见问题及解决方案 |
|
背景信息
当前Kubernetes官方维护的是Nginx Ingress Controller,ACK基于社区版的Nginx Ingress Controller进行了优化。当在创建ACK集群时,您选择安装的Nginx Ingress Controller组件即为ACK定制版的Nginx Ingress Controller组件。
- Service是后端真实服务的抽象,一个Service可以代表多个相同的后端服务。
- Nginx Ingress是反向代理规则,用来规定HTTP/HTTPS请求应该被转发到哪个Service所对应的Pod上。例如根据请求中不同的Host和URL路径,让请求落到不同Service所对应的Pod上。
- Nginx Ingress Controller是一个反向代理程序,负责解析Nginx Ingress的反向代理规则。如果Nginx Ingress有增删改的变动,Nginx Ingress Controller会及时更新自己相应的转发规则,当Nginx Ingress Controller收到请求后就会根据这些规则将请求转发到对应Service的Pod上。
nginx -s load
重新加载Nginx)来生成新的路由转发规则。
诊断流程

排查思路
排查思路 | 问题现象 | 解决方案 |
---|---|---|
访问不通 | 集群内部Pod到Ingress访问不通 | 集群内访问集群LoadBalancer暴露的SLB地址不通 |
Ingress访问自己不通 | 无法访问Ingress Controller自己 | |
测试域名解析不到 | 通过控制台提供的测试域名无法访问到Ingress | |
无法访问TCP、UDP服务 | 添加TCP、UDP服务 | |
HTTPS访问出现问题 | 证书未更新或返回默认证书 | 集群中添加或修改了TLS证书,但是访问时还是默认证书或旧的证书 |
返回RX_RECORD_TOO_LONG/wrong version number |
HTTPS访问报SSL_ERROR_RX_RECORD_TOO_LONG错误 | |
添加Ingress资源时出现问题 | 报错failed calling webhook... | 创建Ingress资源时报错 "failed calling webhook" |
添加了Ingress,但是没有生效 | Ingress规则没有生效 | |
访问不符合预期 | 无法获得客户端源IP | Ingress Pod中无法保留源IP |
IP白名单不生效或不按预期生效 | ||
无法连接到通过Ingress暴露的gRPC服务 | 无法连接到通过Ingress暴露的gRPC服务 | |
灰度不生效 | 灰度规则不生效 | |
灰度规则错误或影响到别的流量 | 流量分发与灰度规则不一致或其它流量进入灰度服务 | |
出现The plain HTTP request was sent to HTTPS port |
无法连接到后端HTTPS服务 | |
出现502、503、413、499等错误 | 出现常见HTTP错误码 | |
加载页面时部分资源加载不出来 | 配置了rewrite-target ,资源访问时出现404
|
重写到根目录后部分资源无法加载或白屏 |
资源访问时出现net::ERR_FAILED 或net::ERR_HTTP2_SERVER_REFUSED_STREAM |
出现net::ERR_HTTP2_SERVER_REFUSED_STREAM错误 |
常见检查方法
使用Ingress诊断功能
通过日志服务SLS的Controller Pod查看访问日志
Ingress Controller访问日志格式可以在ConfigMap中看到(默认ConfigMap为kube-system命名空间下的nginx-configuration)。
$remote_addr - [$remote_addr] - $remote_user [$time_local]
"$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length
$request_time [$proxy_upstream_name] $upstream_addr $upstream_response_length
$upstream_response_time $upstream_status $req_id $host [$proxy_alternative_upstream_name]
日志服务控制台的Ingress Controller日志如下图所示。具体操作,请参见步骤四:查看日志。

字段 | 说明 |
---|---|
remote_addr/client_ip |
客户端的真实IP。 |
request/(method+url+version) |
请求的信息。包括请求的方法、URL以及HTTP版本。 |
request_time |
本次请求的时间。从接收客户端请求起,到发送完响应数据的总时间。该值可能会受到客户端网络条件等因素的影响,无法代表请求真实的处理速度。 |
upstream_addr |
后端upstream的地址,如果该请求没有到后端,则该值为空。当后端因为失败请求多个upstream时,该值为半角逗号(,)分隔列表。 |
upstream_status |
后端upstream返回的http code。如果该值为正常http status code,代表该值由后端upstream返回。当没有后端可以访问时,该值为502。有多个值时由半角逗号(,)分开。 |
upstream_response_time |
后端upstream的响应时间,单位为秒。 |
proxy_upstream_name |
后端upstream的名称。命名规则为<命名空间>-<服务名称>-<端口号> 。
|
proxy_alternative_upstream_name |
后端alternative upstream的名称。当该请求转发到alternative upstream(例如使用Canary设置的灰度服务)时,该值不为空。 |
kubectl logs <controller pod name> -n <namespace> | less
42.11.**.** - [42.11.**.**]--[25/Nov/2021:11:40:30 +0800]"GET / HTTP/1.1" 200 615 "_" "curl/7.64.1" 76 0.001 [default-nginx-svc-80] 172.16.254.208:80 615 0.000 200 46b79dkahflhakjhdhfkah**** 47.11.**.**[]
42.11.**.** - [42.11.**.**]--[25/Nov/2021:11:40:31 +0800]"GET / HTTP/1.1" 200 615 "_" "curl/7.64.1" 76 0.001 [default-nginx-svc-80] 172.16.254.208:80 615 0.000 200 fadgrerthflhakjhdhfkah**** 47.11.**.**[]
检查Controller Pod中错误日志
您可以根据Ingress Controller Pod中的日志,进一步缩小问题范围。Controller Pod中错误日志分为以下两种:
- Controller错误日志:一般在Ingress配置错误时产生,可以执行以下命令过滤出Controller错误日志。
kubectl logs <controller pod name> -n <namespace> | grep -E ^[WE]
说明 Ingress Controller在启动时会产生若干条W(Warning)等级错误,属于正常现象。例如未指定kubeConfig或未指定Ingress Class等Warning信息,这些Warning信息不影响Ingress Controller的正常运行,因此可以忽略。 - Nginx错误日志:一般在处理请求出现错误时产生,可以执行以下命令过滤出Nginx错误日志。
kubectl logs <controller pod name> -n <namespace> | grep error
在Controller Pod中手动访问Ingress和后端Pod
抓包
当无法定位问题时,需要抓包进行辅助诊断。
集群内访问集群LoadBalancer暴露的SLB地址不通
问题现象
在Kubernetes集群中有部分节点能访问集群暴露出去的Local类型SLB,但是也有部分节点不能访问。
问题原因
SLB设置了externalTrafficPolicy: Local
类型,这种类型的SLB地址只有在Node中部署了对应的后端Pod,才能被访问。因为SLB的地址是集群外使用,如果集群节点和Pod不能直接访问,请求不会到SLB,会被当作Service的扩展IP地址,被kube-proxy的iptables或ipvs转发。
如果刚好集群节点或者Pod所在的节点上没有相应的后端服务Pod,就会发生网络不通的问题,而如果有相应的后端服务Pod,是可以正常访问。有关external-lb的更多信息,请参见kube-proxy将external-lb的地址添加到节点本地iptables规则。
解决方案
- (推荐)在Kubernetes集群内通过ClusterIP或者Ingress的服务名去访问。
其中Ingress的服务名为
nginx-ingress-lb.kube-system
。 - 执行
kubectl edit svc nginx-ingress-lb -n kube-system
命令,修改Ingress的服务。将LoadBalancer的Service中externalTrafficPolicy
修改为Cluster
,但应用中会丢失源IP。 - 如果是Terway的ENI或者ENI多IP的集群,将LoadBalancer的Service中
externalTrafficPolicy
修改为Cluster
,并且添加ENI直通的Annotation,可以保留源IP,并且集群内访问也没有问题。示例如下:apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/backend-type: eni #直通ENI。 labels: app: nginx-ingress-lb name: nginx-ingress-lb namespace: kube-system spec: externalTrafficPolicy: Cluster
关于Service的Annotation的更多信息,请参见通过Annotation配置负载均衡。
无法访问Ingress Controller自己
问题现象
对于Flannel集群,在Ingress Pod中通过域名、SLB IP、Cluster IP访问Ingress自己时,出现部分请求或全部请求不成功的情况。
问题原因
Flannel目前的默认配置不允许回环访问。
解决方案
- (推荐)如果条件允许,建议您重建集群,并使用Terway的网络插件,将现有集群业务迁移至Terway模式集群中。
- 如果没有重建集群的条件,可以通过修改Flannel配置,开启
hairpinMode
解决。配置修改完成后,重建Flannel Pod使修改生效。- 执行以下命令,编辑Flannel。
kubectl edit cm kube-flannel-cfg -n kube-system
- 在返回结果cni-config.json中的
delegate
增加"hairpinMode": true
。示例如下:cni-conf.json: | { "name": "cb0", "cniVersion":"0.3.1", "type": "flannel", "delegate": { "isDefaultGateway": true, "hairpinMode": true } }
- 执行以下命令,重启Flannel。
kubectl delete pod -n kube-system -l app=flannel
- 删除并重新创建Pod。
- 执行以下命令,编辑Flannel。
集群中添加或修改了TLS证书,但是访问时还是默认证书或旧的证书
问题现象
您已经在集群中添加或修改Secret并在Ingress中指定secretName后,访问集群仍使用了默认的证书(Kubernetes Ingress Controller Fake Certificate)或旧的证书。
问题原因
- 证书不是由集群内Ingress Controller返回的。
- 证书无效,未能被Controller正确加载。
- Ingress Controller根据SNI来返回对应证书,TLS握手时可能未携带SNI。
解决方案
- 通过以下任一方式,确认建立TLS连接时是否携带了SNI字段:
- 使用支持SNI的较新版本浏览器。
- 使用
openssl s_client
命令测试证书时,携带-servername
参数。 - 使用
curl
命令时,添加hosts或使用--resolve
参数映射域名,而不是使用IP+Host请求头的方式。
- 确认WAF、WAF透明接入或SLB七层监听上没有设置TLS证书,TLS证书应该由集群内Ingress Controller返回的。
- 在智能运维控制台进行Ingress诊断,观察是否存在配置错误和错误日志。具体操作,请参见使用Ingress诊断功能。
- 执行以下命令,手动查看Ingress Pod错误日志,根据错误日志中相关提示进行修改。
kubectl logs <ingress pod name> -n <pod namespace> | grep -E ^[EW]
通过控制台提供的测试域名无法访问到Ingress
问题现象
通过容器服务控制台提供的测试域名(*.cxxxxxxxxxxx.xxx.alicontainer.com)无法访问到Ingress。
问题原因
域名未正确解析到Ingress服务,可能原因如下:
- 服务不是kube-system命名空间下的nginx-ingress-lb。
- 服务的外部IP在创建Ingress后出现变动。
解决方案
- 将正确的IP绑定在kube-system命名空间下的nginx-ingress-lb服务上。
- 在容器服务管理控制台对应集群的集群信息页面,单击基本信息页签,然后单击重新绑定域名。
无法连接到通过Ingress暴露的gRPC服务
问题现象
通过Ingress无法访问到其后的gRPC服务。
问题原因
- 未在Ingress资源中设置Annotation,指定后端协议类型。
- gRPC服务只能通过TLS端口进行访问。
解决方案
- 在对应Ingress资源中设置Annotation:
nginx.ingress.kubernetes.io/backend-protocol:"GRPC"
。 - 确认客户端发送请求时使用的是TLS端口,并且将流量加密。
无法连接到后端HTTPS服务
问题现象
- 通过Ingress无法访问到其后的HTTPS服务。
- 访问时回复可能为400,并提示
The plain HTTP request was sent to HTTPS port
。
问题原因
Ingress Controller到后端Pod请求使用了默认的HTTP请求。
解决方案
在Ingress资源中设置Annotation:nginx.ingress.kubernetes.io/backend-protocol:"HTTPS"
。
Ingress Pod中无法保留源IP
问题现象
Ingress Pod中无法保留真实客户端IP,显示为节点IP或100.XX.XX.XX网段或其它地址。
问题原因
- Ingress所使用的Service中
externalTrafficPolicy
设为了Cluster
。 - SLB上使用了七层代理。
- 使用了WAF接入或WAF透明接入服务。
解决方案
- 对于设置
externalTrafficPolicy
为Cluster
,且前端使用了四层SLB的情况。可以将
externalTrafficPolicy
改为Local
。但可能会导致集群内部使用SLB IP访问Ingress不通,具体解决方案,请参见集群内访问集群LoadBalancer暴露的SLB地址不通。 - 对于使用了七层代理(七层SLB、WAF、透明WAF)的情况,可以按以下步骤解决:
- 确保使用的七层代理且开启了X-Forwarded-For请求头。
- 在Ingress Controller的ConfigMap中(默认为kube-system命名空间下的nginx-configuration)添加
enable-real-ip: "true"
。 - 观察日志,验证是否可以获取到源IP。
- 对于链路较长,存在多次转发的情况(例如在Ingress Controller前额外配置了反向代理服务),可以在开启
enable-real-ip
时通过观察日志中remote_addr
的值,来确定真实IP是否是以X-Forwarded-For请求头传递到Ingress容器中。若不是,请在请求到达Ingress Controller之前利用X-Forwarded-For等方式携带客户端真实IP。
灰度规则不生效
问题现象
在集群内设置了灰度,但是灰度规则不生效。
问题原因
可能原因有两种:
- 在使用
canary-*
相关Annotation时,未设置nginx.ingress.kubernetes.io/canary: "true"
。 - 在使用
canary-*
相关Annotation时,0.47.0版本前的Nginx Ingress Controller,需要Host字段填写您的业务域名,不能为空。
解决方案
- 根据上述原因,修改
nginx.ingress.kubernetes.io/canary: "true"
或Host字段。 - 如果上述情况不符合,请参见流量分发与灰度规则不一致或其它流量进入灰度服务。
流量分发与灰度规则不一致或其它流量进入灰度服务
问题现象
设置了灰度规则,但是流量没有按照灰度规则进行分发,或者有其它正常Ingress的流量进入灰度服务。
问题原因
Nginx Ingress Controller中,灰度规则不是应用单个Ingress上,而是会应用在所有使用同一个Service的Ingress上。
关于产生该问题的详情,请参见带有灰度规则的Ingress将影响所有具有相同Service的Ingress。
解决方案
针对需要开启灰度的Ingress(包括使用service-match和canary-*
相关Annotation),创建独立的Service(包括正式和灰度两个Service)指向原有的Pod,然后再针对该Ingress启用灰度。
创建Ingress资源时报错 "failed calling webhook"
问题现象
添加Ingress资源时显示"Internal error occurred: failed calling webhook...",如下图所示。

问题原因
在添加Ingress资源时,需要通过服务(默认为ingress-nginx-controller-admission)验证Ingress资源的合法性。如果链路出现问题,(例如服务被删除,Ingress controller被删除时),会导致验证失败,拒绝添加Ingress资源。
解决方案
- 按照Webhook链路检查资源是否均存在且正常工作,链路为ValidatingWebhookConfiguration->Service->Pod。
- 确认Ingress Controller Pod的admission功能已打开,且能够正常从外部访问到该Pod。
- 如果Ingress Controller已被删除或不需要Webhook功能,可以直接将ValidatingWebhookConfiguration资源删除。
HTTPS访问报SSL_ERROR_RX_RECORD_TOO_LONG错误
问题现象
访问HTTPS时报错SSL_ERROR_RX_RECORD_TOO_LONG
或routines:CONNECT_CR_SRVR_HELLO:wrong version number
。
问题原因
HTTPS请求访问到了非HTTPS端口,例如HTTP端口。
- SLB的443端口绑定了Ingress Pod的80端口。
- Ingress Controller所对应服务的Service 443端口映射到了Ingress Pod的80端口。
解决方案
根据实际情况修改SLB设置或Service设置,使得HTTPS能够访问到正确的端口。
出现常见HTTP错误码
问题现象
请求出现非2xx、非3xx错误,例如502、503、413、499等错误。
问题原因及解决方案
查看日志,判断是否为Ingress Controller返回的错误。具体方法,请参见通过日志服务SLS的Controller Pod查看访问日志。若是,请参考以下解决方案:
- 413错误
- 问题原因:请求大小超过了最大限制。
- 解决方案:在ConfigMap中调大proxy-body-size的值(组件默认为1 M,ACK Ingress Controller中默认设置了20 M)
- 499错误
- 问题原因:客户端由于某些原因提前断开了连接,不一定是组件或者后端业务问题。
- 解决方案:
- 有少量499错误时,取决于业务,可能为正常现象,可以忽略。
- 有大量499错误时,请检查后端业务处理时间和前端请求超时时间是否符合预期。
- 502错误
- 问题原因:Ingress Controller无法正常连接到后端。
- 解决方案:
- 偶发情况
- 检查后端业务负载是否正常,若负载过高,尝试对后端业务进行扩容。
- Ingress Controller默认使用HTTP1.1请求访问后端服务,且keepalive默认开启,确认配置的后端keepalive的连接超时时间大于Ingress Controller的连接超时时间(默认60s)。
- 必现情况
- 检查后端Service端口配置是否正确,能否在Controller Pod中手动访问到。
- 在容器智能运维控制台,选择故障诊断页面,单击网络诊断,检查网络连通性。 ,在
- 以上方法都无法确定问题的情况下,请进行抓包分析,并提交工单处理。
- 偶发情况
- 503错误
- 问题原因:Ingress Controller没有找到后端Pod,或所有Pod均无法访问。
- 解决方案:
- 偶发情况
- 查看502错误解决方案。
- 检查后端业务就绪状态,配置合理健康检查。
- 必现情况
检查后端Service配置是否正确,是否存在Endpoint。
- 以上方法都无法确定问题的情况下,请提交工单处理。
- 偶发情况
出现net::ERR_HTTP2_SERVER_REFUSED_STREAM错误
问题现象
访问网页时,部分资源无法正确加载,控制台中有net::ERR_HTTP2_SERVER_REFUSED_STREAM
或net::ERR_FAILED
报错。
问题原因
资源并行请求数较多,达到HTTP2最大流数限制。
解决方案
- (推荐)在ConfigMap中根据实际需要,调整
http2-max-concurrent-streams
至更大值(默认128)。具体操作,请参见http2-max-concurrent-streams。 - 在ConfigMap中直接关闭HTTP2支持,设置
use-http2
为false
。具体操作,请参见use-http2。
出现报错“The param of ServerGroupName is illegal”
问题原因
ServerGroupName的生成格式是namespace+svcName+port
。服务器组名称为长度为2~128个字符,必须以大小写字母或中文开头,可包含数字、半角句号(.)、下划线(_)和短划线(-)。
解决方案
按照服务器组名称的格式要求修改。
创建Ingress时报错“certificate signed by unknown authority”

问题原因
创建Ingress时,出现上图报错,原因是布置了多套Ingress,而各Ingress之间使用了相同的资源 (可能包括Secret、服务、Webhook配置等),导致Webhook执行时与后端服务通信时使用的SSL证书不一致,从而出现错误。
解决方案
重新部署两套Ingress,两套Ingress包含的资源不能重复。关于Ingress中包含的资源信息,请参见在ACK组件管理中升级Nginx Ingress Controller组件时,系统所做的更新是什么?。
Ingress Pod健康检查失败导致重启
问题现象
Controller Pod出现健康检查失败导致Pod重启。
问题原因
- Ingress Pod或所在节点负载较高,导致健康检查失败。
- 集群节点上设置了
tcp_tw_reuse
或tcp_tw_timestamps
内核参数,可能会导致健康检查失败。
解决方案
- 对Ingress Pod进行扩容,观察是否还有该现象。具体操作,请参见部署高可靠的Ingress接入层。
- 关闭
tcp_tw_reuse
或设置为2,且同时关闭tcp_tw_timestamps
,观察是否还有该现象。
添加TCP、UDP服务
Ingress规则没有生效
问题现象
添加或修改了Ingress规则,但是没有生效。
问题原因
- Ingress配置出现错误,导致新的Ingress规则无法被正确加载。
- Ingress资源配置错误,与预期配置不相符。
- Ingress Controller的权限出现问题,导致无法正常监视Ingress资源变动。
- 旧的Ingress使用了
server-alias
配置了域名,与新的Ingress冲突,导致规则被忽略。
- 使用智能运维控制台的Ingress诊断工具进行诊断,并按照提示进行操作。具体操作,请参见使用Ingress诊断功能。
- 检查旧的Ingress有无配置错误或配置冲突问题:
- 针对非
rewrite-target
,且路径中使用了正则表达式的情况,确认Annotation中配置了nginx.ingress.kubernetes.io/use-regex: "true"
。 - 检查PathType是否与预期相符(
ImplementationSpecific
默认与Prefix
作用相同)。
- 针对非
- 确认与Ingress Controller相关联的ClusterRole、ClusterRoleBinding、Role、RoleBinding、ServiceAccount都存在。默认名称均为ingress-nginx。
- 进入Controller Pod容器,查看nginx.conf文件中已添加了规则。
- 执行以下命令,手动查看容器日志,确定问题。
kubectl logs <ingress pod name> -n <pod namespace> | grep -E ^[EW]
重写到根目录后部分资源无法加载或白屏
问题现象
通过Ingress rewrite-target
annotation重写访问后,页面部分资源无法加载,或出现白屏。
问题原因
rewrite-target
可能没有使用正则表达式进行配置。- 业务中请求资源路径写死在根目录。
解决方案
- 检查
rewrite-target
是否配合正则表达式以及捕获组一起使用。具体操作,请参见Rewrite。 - 检查前端请求是否访问到了正确的路径。
当版本升级后SLS解析日志不正常怎样修复
问题现象
ingress-nginx-controller组件当前主要有0.20和0.30两个版本,当通过控制台的组件管理从0.20升级到0.30版本后 ,在使用Ingress的灰度或蓝绿发布功能时,Ingress Dashboard会出现无法正确展示实际后端服务访问的情况。
问题原因
由于0.20和0.30默认输出格式不同,在使用Ingress的灰度或蓝绿发布功能时,Ingress Dashboard会出现无法正确展示实际后端服务访问的情况。
解决方案
执行以下操作步骤进行修复,更新nginx-configuration configmap
和k8s-nginx-ingress
配置。