本文介绍关于Nginx Ingress异常问题的诊断流程、排查思路、常见检查方法和解决方案。

本文目录

类别 内容
诊断流程 诊断流程
排查思路 排查思路
常见排查方法
常见问题及解决方案

背景信息

当前Kubernetes官方维护的是Nginx Ingress Controller,ACK基于社区版的Nginx Ingress Controller进行了优化。ACK的Nginx Ingress Controller与社区Nginx Ingress Controller完全兼容,支持社区所有的Annonation。当在创建ACK集群时,您选择安装的Nginx Ingress Controller组件即为ACK定制版的Nginx Ingress Controller组件。

为了使得Nginx Ingress资源正常工作,集群中必须要有个Nginx Ingress Controller来解析Nginx Ingress的转发规则。Nginx Ingress Controller收到请求,匹配Nginx Ingress转发规则转发到后端Service所对应的Pod,由Pod处理请求。Kubernetes中Service、Nginx Ingress与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 Ingress Controller通过API Server获取Ingress资源的变化,动态地生成Load Balancer(例如Nginx)所需的配置文件(例如 nginx.conf ),然后重新加载Load Balancer(例如执行 nginx -s load 重新加载Nginx)来生成新的路由转发规则。 S2

诊断流程

诊断流程Ingress.png
  1. 按照以下步骤,检查是否是由于Ingress所导致的问题,确保Ingress Controller的配置正确。
    1. 在Controller Pod中确认访问是否符合预期。具体操作,请参见 在Controller Pod中手动访问Ingress和后端Pod
    2. 确认Nginx Ingress Controller使用方法正确。具体操作,请参见 Nginx Ingress社区使用文档
  2. 使用Ingress诊断功能检查Ingress和组件配置,并且根据相关提示进行修改。关于Ingress诊断功能具体操作,请参见 使用Ingress诊断功能
  3. 按照 排查思路 ,确认相关问题及解决方案。
  4. 如果以上排查无果,请按照以下步骤排查:
    • 针对HTTPS证书问题:
      1. 检查域名上是否启用了WAF接入或WAF透明接入。
        • 如果启用了,请确认WAF或透明WAF没有设置TLS证书。
        • 如果没启用,请执行下一步。
      2. 检查SLB是否为七层监听。
        • 如果是,请确认SLB七层监听上没有设置TLS证书。
        • 如果不是,请执行下一步。
    • 非HTTPS证书问题,检查Controller Pod中错误日志。具体操作,请参见 检查Controller Pod中错误日志
  5. 如果以上排查无果,请在Controller Pod和对应后端的业务Pod中进行抓包,确认问题。具体操作,请参见 抓包
  6. 如果以上排查无果,请 提交工单 排查。

排查思路

排查思路 问题现象 解决方案
访问不通 集群内部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诊断功能

  1. 登录 容器服务管理控制台
  2. 在控制台左侧导航栏,单击 集群
  3. 集群列表 页面,选择目标集群,并在目标集群右侧的 操作 列,选择 更多 > 集群检查
  4. 在容器智能运维控制台左侧导航栏,选择 检查 > 故障诊断
  5. 故障诊断 页面,单击 Ingress诊断
  6. Ingress诊断 面板,输入出现问题的URL,例如 https://www.example.com 。选中 我已知晓并同意 ,然后单击 发起诊断
    诊断完成后,根据诊断结果解决问题。

通过日志服务SLS的Controller Pod查看访问日志

Ingress Controller访问日志格式可以在ConfigMap中看到(默认ConfigMap为kube-system命名空间下的nginx-configuration)。

ACK Ingress Controller默认的日志格式为:
$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]
重要 改动日志格式后,SLS的日志收集规则也需要做相应改动,否则无法在SLS日志控制台看到正确日志信息,请您谨慎修改日志格式。

日志服务控制台 的Ingress Controller日志如下图所示。具体操作,请参见 步骤四:查看日志

SLS日志.png
日志服务控制台 的日志和实际日志字段名称会有部分不同,已在下表列出,字段解释如下表所示。
字段 说明
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

  1. 执行以下命令,进入Controller Pod。
    kubectl exec <controller pod name> -n <namespace> -it -- bash
  2. Pod中已预装好了curl、OpenSSL等工具,您可以通过该工具测试连通性、证书配置的正确性等。
    • 执行以下命令,测试能否通过Ingress访问到后端。
      # 请将your.domain.com替换为实际要测试的域名。
      curl -H "Host: your.domain.com" http://127.0.**.**/ # for http
      curl --resolve your.domain.com:443:127.0.0.1 https://127.0.0.1/ # for https
    • 执行以下命令,验证证书信息。
      openssl s_client -servername your.domain.com -connect 127.0.0.1:443
    • 访问后端Pod测试的正确性。
      说明 Ingress Controller不会通过Service Cluster IP的形式来访问后端Pod,而是直接访问后端Pod IP。
      1. 执行以下命令,通过kubectl获得后端Pod IP。
        kubectl get pod -n <namespace> <pod name> -o wide
        预期输出:
        NAME                      READY    STATUS    RESTARTS   AGE    IP            NODE                        NOMINATED NODE    READINESS GATES
        nginx-dp-7f5fcc7f-****    1/1      Running   0          23h    10.71.0.146   cn-beijing.192.168.**.**    <none>            <none>

        由预期输出获得,后端Pod IP为10.71.0.146。

      2. 执行以下命令,在Controller Pod中访问该Pod,确认Controller Pod到后端Pod能够正常连通。
        curl http://<your pod ip>:<port>/path

当无法定位问题时,需要抓包进行辅助诊断。

  1. 根据初步问题定位结果,简单判断网络问题出现在Ingress Pod还是业务Pod。如果信息不足,可以两方的包都进行抓取。
  2. 登录出现异常的业务Pod或Ingress Pod所在节点。
  3. 在ECS(非容器内)执行以下命令,可以将Ingress流量信息抓取到文件中。
    tcpdump -i any host <业务Pod IP或Ingress Pod IP> -C 20 -W 200 -w /tmp/ingress.pcap
  4. 观察日志,当出现预期错误时,结束抓包。
  5. 结合业务日志的报错,定位到精准的报错时间的报文信息。
    说明
    • 在正常情况下,抓包对业务无影响,仅会增加小部分的CPU负载和磁盘写入。
    • 以上命令会对抓取到的包进行rotate,最多可以写200个20 MB的 .pcap 文件。

集群内访问集群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使修改生效。
    1. 执行以下命令,编辑Flannel。
      kubectl edit cm kube-flannel-cfg -n kube-system
    2. 在返回结果 cni-config.json 中的 delegate 增加 "hairpinMode": true
      示例如下:
      cni-conf.json: |
            "name": "cb0",
            "cniVersion":"0.3.1",
            "type": "flannel",
            "delegate": {
              "isDefaultGateway": true,
              "hairpinMode": true
          }
    3. 执行以下命令,重启Flannel。
      kubectl delete pod -n kube-system -l app=flannel   
    4. 删除并重新创建Pod。

集群中添加或修改了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 FAQ 测试域名

无法连接到通过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)的情况,可以按以下步骤解决:
    1. 确保使用的七层代理且开启了X-Forwarded-For请求头。
    2. 在Ingress Controller的ConfigMap中(默认为kube-system命名空间下的nginx-configuration)添加 enable-real-ip: "true"
    3. 观察日志,验证是否可以获取到源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,需要在Ingress规则里的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 FAQ.png

问题原因

在添加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,而各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服务

  1. 在对应ConfigMap中(默认为kube-system命名空间下的tcp-services和udp-services)添加对应条目。

    例如default空间下example-go的8080端口映射到9000端口,示例如下。

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: tcp-services
      namespace: ingress-nginx
    data:
      9000: "default/example-go:8080"  #8080端口映射到9000端口。
  2. 在Ingress Deployment中(默认为kube-system命名空间下的nginx-ingress-controller)添加所映射的端口。
  3. 在Ingress对应的Service中添加所映射的端口。
    示例如下:
    apiVersion: v1
    kind: Service
    metadata:
      name: ingress-nginx
      namespace: ingress-nginx
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    spec:
      type: LoadBalancer
      ports:
        - name: http
          port: 80
          targetPort: 80
          protocol: TCP
        - name: https
          port: 443
          targetPort: 443
          protocol: TCP
        - name: proxied-tcp-9000
          port: 9000
          targetPort: 9000
          protocol: TCP
      selector:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx

    关于添加TCP和UDP服务的更多信息,请参见 暴露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 配置。

  1. 更新 nginx-configuration configmap
    • 如果您没有修改过 nginx-configuration configmap ,保存以下内容为 nginx-configuration.yaml , 然后执行 kubectl apply -f nginx-configuration.yaml 命令进行部署。
      apiVersion: v1
      kind: ConfigMap
      data:
        allow-backend-server-header: "true"
        enable-underscores-in-headers: "true"
        generate-request-id: "true"
        ignore-invalid-headers: "true"
        log-format-upstream: $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]
        max-worker-connections: "65536"
        proxy-body-size: 20m
        proxy-connect-timeout: "10"
        reuse-port: "true"
        server-tokens: "false"
        ssl-redirect: "false"
        upstream-keepalive-timeout: "900"
        worker-cpu-affinity: auto
      metadata:
        labels:
          app: ingress-nginx
        name: nginx-configuration
        namespace: kube-system
    • 如果您修改过 nginx-configuration configmap ,为了避免覆盖您的配置,执行以下命令进行修复:
      kubectl edit configmap nginx-configuration -n kube-system

    log-format-upstream 字段末尾,添加 [$proxy_alternative_upstream_name] , 然后保存退出。

  2. 更新 k8s-nginx-ingress 配置。
    将以下内容保存为 k8s-nginx-ingress.yaml 文件,然后执行 kubectl apply -f k8s-nginx-ingress.yaml 命令进行部署。
    apiVersion: log.alibabacloud.com/v1alpha1
    kind: AliyunLogConfig
    metadata:
        namespace: kube-system
      # your config name, must be unique in you k8s cluster
      name: k8s-nginx-ingress
    spec:
      # logstore name to upload log
      logstore: nginx-ingress
      # product code, only for k8s nginx ingress
      productCode: k8s-nginx-ingress
      # logtail config detail
      logtailConfig:
        inputType: plugin
        # logtail config name, should be same with [metadata.name]
        configName: k8s-nginx-ingress
        inputDetail:
          plugin:
            inputs:
            - type: service_docker_stdout
              detail:
                IncludeLabel:
                  io.kubernetes.container.name: nginx-ingress-controller
                Stderr: false
                Stdout: true
            processors:
            - type: processor_regex
              detail:
                KeepSource: false
                Keys:
                - client_ip
                - x_forward_for
                - remote_user
                - time
                - method
                - url
                - version
                - 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
                NoKeyError: true
                NoMatchError: true
                Regex: ^(\S+)\s-\s\[([^]]+)]\s-\s(\S+)\s\[(\S+)\s\S+\s"(\w+)\s(\S+)\s([^"]+)"\s(\d+)\s(\d+)\s"([^"]*)"\s"([^"]*)"\s(\S+)\s(\S+)+\s\[([^]]*)]\s(\S+)\s(\S+)\s(\S+)\s(\S+)\s(\S+)\s*(\S*)\s*\[*([^]]*)\]*.*
                SourceKey: content

常见Controller错误日志

问题现象

通过 检查Controller Pod中错误日志 中所述方法发现Pod内存在Controller错误日志。类似如下:
User "system:serviceaccount:kube-system:ingress-nginx" cannot list/get/update resource "xxx" in API group "xxx" at the cluster scope/ in the namespace "kube-system"

问题原因

Nginx Ingress Controller缺少对应权限更新对应资源。

解决方案

  • 根据日志确认问题是由于ClusteRole还是Role产生的。
    • 日志中包含 at the cluster scope ,问题则产生自ClusterRole(ingress-nginx)。
    • 日志中包含 in the namespace "kube-system" ,问题则产生自Role(kube-system/ingrerss-nginx)。
  • 确认对应权限以及权限绑定是否完整。
    • 对于ClusterRole:
      • 确保ClusterRole ingress-nginx 以及ClusterRoleBinding ingress-nginx 存在。若不存在,可以考虑自行新建恢复、卸载组件重装或者 提交工单 寻求帮助。
      • 确保ClusterRole ingress-nginx 中包含日志中所对应的权限(图例中为networking.k8s.io/ingresses的List权限)。若权限不存在,可以手动添加至ClusterRole中。 77
    • 对于Role:
      • 确认Role kube-system/ingress-nginx 以及RoleBinding kube-system/ingress-nginx 存在。若不存在,可以考虑自行新建恢复、卸载组件重装或者 提交工单 寻求帮助。
      • 确认Role ingress-nginx 中包含日志中所对应权限(图例中为ConfigMap ingress-controller-leader-nginx 的Update权限)。若权限不存在,可以手动添加至Role中。 78

问题现象

通过 检查Controller Pod中错误日志 中所述方法发现Pod内存在Controller错误日志。类似如下:
requeuing……nginx: configuration file xxx test failed(多行内容)

问题原因

配置错误,导致Nginx配置reload失败,一般为Ingress规则或ConfigMap中插入的Snippet语法错误导致的。

解决方案

  • 查看日志中错误提示(warn等级的提示可忽略),大体定位问题位置。若错误提示不够清晰,可以根据错误提示中文件的行数,进入Pod中查看对应文件。以下图为例,文件为/tmp/nginx/nginx-cfg2825306115的第449行。 95

    执行如下命令,查看对应行附近的配置有无错误。

    # 进入Pod执行命令。
    kubectl exec -n <namespace> <controller pod name> -it -- bash
    # 带行数信息查看出错的文件,在输出中查看对应行附近的配置有无错误。
    cat -n /tmp/nginx/nginx-cfg2825306115
  • 根据错误提示和配置文件,根据自身实际配置,定位错误原因并修复。

问题现象

通过 检查Controller Pod中错误日志 中所述方法发现Pod内存在Controller错误日志。类似如下:
Unexpected error validating SSL certificate "xxx" for server "xxx"
94

问题原因

证书配置错误,常见的原因有证书所包含域名与Ingress中配置域名不一致。部分Warning等级日志不会影响到证书的正常使用(如证书中未携带SAN扩展等),请根据实际情况判断是否出现问题。

解决方案

根据错误内容检查集群中证书问题。
  • 证书的cert和key格式和内容是否正确。
  • 证书所包含域名与Ingress中所配置域名是否一致。
  • 证书有无过期。