排查 Azure Kubernetes 服务 节点上的 SNAT 端口耗尽问题

本文可帮助你查找并排查遇到源网络地址转换(SNAT)端口耗尽的Azure Kubernetes 服务(AKS)节点的问题。

注意

  • 若要对运行 Kubernetes 作业的 AKS 群集中的 AKS 节点上的 SNAT 端口耗尽进行故障排除,请仅在作业在 AKS 节点上主动运行时执行以下步骤。
  • 若要详细了解 SNAT 端口及其每个虚拟机的分配,请参阅 什么是 SNAT 端口

步骤 1:找到遇到 SNAT 端口耗尽的节点

  1. 获取 AKS 节点的 IP 地址,该节点在Azure 门户中遇到活动 SNAT 端口耗尽。

    为此,请导航到Azure 门户中的 AKS 群集,然后选择“诊断并解决连接问题 SNAT 连接和端口分配问题>>”。 SNAT 连接和端口分配 选项卡显示体验 SNAT 端口耗尽的 AKS 节点的专用 IP 地址。

    “诊断和解决问题”窗格的屏幕截图。

    “连接问题”窗格的屏幕截图。

  2. 连接到 AKS 群集并使用节点 IP 地址通过 kubectl 运行以下命令获取节点名称:

    kubectl get nodes -o wide | grep <node IP>
    

步骤 2:找到具有高出站连接的 Linux Pod

注意

  • Tcptracer 是 Linux 节点上预安装的 BPF 编译器集合 (BCC) 工具之一。 它允许跟踪 TCP 建立的连接(connect()accept()close())。 可以使用它从 Pod 的源 IP 地址和网络命名空间(netns)查找高出站连接。
  • 若要访问 BCC 工具,请仅使用 kubectl node-shell
  • 本部分中的所有命令都作为已安装 BCC 工具的 Linux 节点上的根用户运行。
  1. 在遇到 SNAT 端口耗尽的 Linux 节点上,安装 kubectl node-shell

    curl -LO https://github.com/kvaps/kubectl-node-shell/raw/master/kubectl-node_shell
    chmod +x ./kubectl-node_shell
    sudo mv ./kubectl-node_shell /usr/local/bin/kubectl-node_shell
    
  2. 使用 SSH 连接到体验 SNAT 端口耗尽的节点,并用于 tcptracer 跟踪 TCP 建立的连接:

    kubectl node-shell <node name>
    cd /usr/share/bcc/tools
    /usr/share/bcc/tools# python3 tcptracer -t4v
    

    下面是命令输出示例:

    Tracing TCP established connections. Ctrl-C to end.
    TIME(ns)     TYPE         PID   COMM             IP SADDR            DADDR            SPORT  DPORT  NETNS
    0           connect      18627  curl             4  1.2.3.4           5.6.7.8          53746  80     4026532785
    3xxx9       close        18627  curl             4  1.2.3.4           5.6.7.8          53746  80     4026532785
    1xxxx4      connect      18629  curl             4  1.2.3.4           9.10.11.12       35686  80     4026532785
    2xxxx9      close        18629  curl             4  1.2.3.4           9.10.11.12       35686  80     4026532785
    4xxxx5      connect      18631  curl             4  1.2.3.4           9.10.11.12       35688  80     4026532785
    4xxxx8      close        18631  curl             4  1.2.3.4           9.10.11.12       35688  80     4026532785
    7xxxx3      connect      18633  curl             4  1.2.3.4           13.14.15.16      35690  80     4026532785
    9xxxx7      close        18633  curl             4  1.2.3.4           13.14.15.16      35690  80     4026532785
    
  3. 将上一个命令输出写入日志文件,然后对输出进行排序,以查看高连接列表:

    python3 tcptracer -t4v > log
    head -n +2 log | tail -n 1 | awk '{print "Count",$6,$10}'; awk '{print $6,$10}' log | sort | uniq -c | sort -nrk 1 | column -t
    

    下面是命令输出示例:

    Count SADDR        NETNS
    387   1.2.3.4      4026532785
    8     11.22.33.44  4026532184
    8     55.66.77.88  4026531992
    
  4. 将具有上一个输出中最多连接的 IP 地址映射到 Pod。 如果不起作用,可以继续操作。

  5. SADDR请注意具有上一个输出中大多数连接的或NETNS值,然后运行以下 lsns 命令将其映射到 PID。 Lsns 是一种 Linux 工具,用于列出命名空间并将命名空间映射到 Linux 进程树中的 PID。

    lsns -t net
    

    下面是命令输出示例:

    NS         TYPE NPROCS PID   USER  COMMAND
    4026532785 net  3      19832 root  bash
    
  6. 使用 pstree 将以前的 PID 映射到容器进程。 Pstree 是一种 Linux 工具,它以树格式列出进程以便可读性。

    pstree -aps 19832
    

    下面是命令输出示例:

    systemd,1
      `-containerd-shim,20946 -namespace k8s.io -id 2xxxf...
    

    请注意命令输出中容器 -id 的前五个字符。 它将在步骤 7 中使用。

  7. 使用 crictl 将以前的容器-id值映射到 POD ID。 Crictl 为与 CRI 兼容的容器运行时提供 CLI。

    crictl ps -a
    

    下面是命令输出示例:

    CONTAINER   IMAGE     CREATED      STATE     NAME    ATTEMPT    POD ID        POD
    6b5xxxxb    fbxxxxx1  6 hours ago  Running   ubuntu  0          2xxxxxxxxf    nginx
    

    使用上一容器 -id 值的前五个字符来匹配 POD ID。

  8. 获取节点上运行的所有 Pod,并使用以前的 POD ID 来匹配命令输出中具有高出站连接的 Pod:

    kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=<nodename>
    

步骤 3:查找应用程序建立的所有出站网络连接

  1. 使用以下命令之一,执行到在步骤 2标识为具有高出站连接的 Pod:

    • kubectl exec -it <pod name> -n <namespace> /bin/bash
      
    • kubectl exec -it <pod name> -n <namespace> /bin/sh
      
  2. 运行以下命令,在 Pod 中安装 netstat 命令行工具。 Netstat 是仅限管理员的网络故障排除工具。

    • 在 Debian、Ubuntu 或 Linux Mint 上

      apt update
      apt install net-tools  
      
    • 在 RHEL、CentOS、Fedora、AlmaLinux 或 Rocky Linux 上

      yum update
      yum install net-tools      
      
    • 在 Gentoo Linux 上

      emerge -a sys-apps/net-tools  
      
    • 在 Alpine Linux 上

      apk add net-tools    
      
    • 在 Arch Linux 上

      pacman -S net-tools
      
    • 在 OpenSUSE 上

      zypper install net-tools
      
  3. 在 Pod 中安装 netstat 后,运行以下命令:

    netstat -ptn | grep -i established
    

    下面是命令输出示例:

    tcp        0      0 10.x.x.x:xxxx        20.x.x.x:443       ESTABLISHED xxxxx3/telnet
    

在命令输出中,本地地址是 Pod 的 IP 地址,外地址是应用程序连接到的 IP。 状态中的 ESTABLISHED 公共 IP 连接是使用 SNAT 的连接。 确保仅对状态中的 ESTABLISHED 公共 IP 地址的连接进行计数,并忽略状态中 ESTABLISHED 与专用 IP 地址的任何连接。

对节点上运行的其他所有 Pod 重复本部分中的步骤。 与公共 IP 地址建立最多连接的 ESTABLISHED Pod 托管导致节点上 SNAT 端口耗尽的应用程序。 与应用程序开发人员协作,使用设计连接高效应用程序中所述的建议优化应用程序以提高网络性能。 实施建议后,请验证是否看到较少的 SNAT 端口耗尽。

联系我们寻求帮助

如果你有任何疑问或需要帮助,请创建支持请求联系 Azure 社区支持。 你还可以将产品反馈提交到 Azure 反馈社区