你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

排查 AKS 群集中的网络问题

新安装的 Kubernetes 或增加 Kubernetes 负载时,可能会出现网络问题。 还可能出现与网络问题相关的其他问题。 请始终检查 AKS 故障排除 指南,查看问题是否在其中描述。 本文从网络故障排除角度介绍其他详细信息和注意事项,以及可能出现的特定问题。

客户端无法访问 API 服务器

这些错误涉及无法通过 Kubernetes 群集命令行工具(kubectl)或任何其他工具(如 REST API)通过编程语言访问 Azure Kubernetes 服务(AKS)群集 API 服务器时发生的连接问题。

错误

你可能会看到如下所示的错误:

Unable to connect to the server: dial tcp <API-server-IP>:443: i/o timeout 
Unable to connect to the server: dial tcp <API-server-IP>:443: connectex: A connection attempt
failed because the connected party did not properly respond after a period, or established 
connection failed because connected host has failed to respond. 

原因 1

API 服务器授权的 IP 范围可能在群集的 API 服务器上启用,但客户端的 IP 地址不包括在这些 IP 范围中。 若要确定是否启用了 IP 范围,请使用 az aks show Azure CLI 中的以下命令。 如果启用 IP 范围,该命令将生成 IP 范围列表。

az aks show --resource-group <cluster-resource-group> \ 
    --name <cluster-name> \ 
    --query apiServerAccessProfile.authorizedIpRanges 

解决方案 1

确保客户端的 IP 地址在群集 API 服务器授权的范围内:

  1. 查找本地 IP 地址。 有关如何在 Windows 和 Linux 上查找它的信息,请参阅 如何查找我的 IP

  2. 使用 az aks update Azure CLI 中的命令更新 API 服务器授权的范围。 授权客户端的 IP 地址。 有关说明,请参阅 更新群集的 API 服务器授权 IP 范围

原因 2

如果 AKS 群集是专用群集,则 API 服务器终结点没有公共 IP 地址。 需要使用对 AKS 群集虚拟网络具有网络访问权限的 VM。

解决方案 2

有关如何解决此问题的信息,请参阅 用于连接到专用群集的选项

Pod 无法分配 IP 地址

错误

Pod 停滞在 ContainerCreating 状态中,其事件报告错误 Failed to allocate address

Normal   SandboxChanged          5m (x74 over 8m)    kubelet, k8s-agentpool-00011101-0 Pod sandbox
changed, it will be killed and re-created. 

  Warning  FailedCreatePodSandBox  21s (x204 over 8m)  kubelet, k8s-agentpool-00011101-0 Failed 
create pod sandbox: rpc error: code = Unknown desc = NetworkPlugin cni failed to set up pod 
"deployment-azuredisk6-874857994-487td_default" network: Failed to allocate address: Failed to 
delegate: Failed to allocate address: No available addresses 

not enough IPs available 错误:

Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox 
'ac1b1354613465324654c1588ac64f1a756aa32f14732246ac4132133ba21364': plugin type='azure-vnet' 
failed (add): IPAM Invoker Add failed with error: Failed to get IP address from CNS with error: 
%w: AllocateIPConfig failed: not enough IPs available for 9c6a7f37-dd43-4f7c-a01f-1ff41653609c, 
waiting on Azure CNS to allocate more with NC Status: , IP config request is [IPConfigRequest: 
DesiredIPAddress , PodInterfaceID a1876957-eth0, InfraContainerID 
a1231464635654a123646565456cc146841c1313546a515432161a45a5316541, OrchestratorContext 
{'PodName':'a_podname','PodNamespace':'my_namespace'}]

检查插件 IPAM 存储中分配的 IP 地址。 你可能会发现所有 IP 地址都已被分配,但数量远低于正在运行的 Pod 数量:

如果使用 kubenet

# Kubenet, for example. The actual path of the IPAM store file depends on network plugin implementation. 
chroot /host/
ls -la "/var/lib/cni/networks/$(ls /var/lib/cni/networks/ | grep -e "k8s-pod-network" -e "kubenet")" | grep -v -e "lock\|last\|total" -e '\.$' | wc -l
244

注释

对于没有 Calico 的 kubenet,路径是 /var/lib/cni/networks/kubenet。 对于具有 Calico 的 kubenet,路径是 /var/lib/cni/networks/k8s-pod-network。 执行命令时,上述脚本将自动选择路径。

# Check running Pod IPs
kubectl get pods --field-selector spec.nodeName=<your_node_name>,status.phase=Running -A -o json | jq -r '.items[] | select(.spec.hostNetwork != 'true').status.podIP' | wc -l
7 

如果使用 Azure CNI 进行动态 IP 分配

kubectl get nnc -n kube-system -o wide
NAME                               REQUESTED IPS  ALLOCATED IPS  SUBNET  SUBNET CIDR   NC ID                                 NC MODE  NC TYPE  NC VERSION
aks-agentpool-12345678-vmss000000  32             32             subnet  10.18.0.0/15  559e239d-f744-4f84-bbe0-c7c6fd12ec17  dynamic  vnet     1
# Check running Pod IPs
kubectl get pods --field-selector spec.nodeName=aks-agentpool-12345678-vmss000000,status.phase=Running -A -o json | jq -r '.items[] | select(.spec.hostNetwork != 'true').status.podIP' | wc -l
21

原因 1

此错误可能是由网络插件中的 bug 引起的。 当 Pod 终止时,该插件可能无法解除分配 IP 地址。

解决方案 1

请联系 Microsoft 以获取修补程序或解决方法。

原因 2

Pod 创建速度比终止的 Pod 的垃圾回收速度要快得多。

解决方案 2

为 kubelet 配置快速垃圾回收。 有关说明,请参阅 Kubernetes 垃圾回收文档

服务无法在 Pod 内访问

解决此问题的第一步是检查是否已为服务自动创建终结点:

kubectl get endpoints <service-name> 

如果结果为空,则服务的标签选择器可能不正确。 确认标签正确:

# Query Service LabelSelector. 
kubectl get svc <service-name> -o jsonpath='{.spec.selector}' 

# Get Pods matching the LabelSelector and check whether they're running. 
kubectl get pods -l key1=value1,key2=value2 

如果前面的步骤返回预期值:

  • 检查 Pod containerPort 是否与服务 containerPort相同。

  • 检查是否 podIP:containerPort 正常工作:

    # Testing via cURL. 
    curl -v telnet ://<Pod-IP>:<containerPort>
    
    # Testing via Telnet. 
    telnet <Pod-IP>:<containerPort> 
    

以下是服务问题的一些其他潜在原因:

  • 容器不侦听指定的 containerPort。 (查看 Pod 说明。)
  • 发生 CNI 插件错误或网络路由错误。
  • kube-proxy 未运行,或者未正确配置 iptables 规则。
  • 网络策略正在删除流量。 有关应用和测试网络策略的信息,请参阅 Azure Kubernetes 网络策略概述
    • 如果使用 Calico 作为网络插件,也可以捕获网络策略流量。 有关配置该配置的信息,请参阅 Calico 网站

节点无法访问 API 服务器

许多加载项和容器都需要访问 Kubernetes API(例如 kube-dns 和作员容器)。 如果在此过程中发生错误,以下步骤可帮助你确定问题的来源。

首先,确认 Kubernetes API 是否可以在 Pod 中访问:

kubectl run curl --image=mcr.microsoft.com/azure-cli -i -t --restart=Never --overrides='[{"op":"add","path":"/spec/containers/0/resources","value":{"limits":{"cpu":"200m","memory":"128Mi"}}}]' --override-type json --command -- sh

然后在现在被封装到的容器中执行以下操作。

# If you don't see a command prompt, try selecting Enter. 
KUBE_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) 
curl -sSk -H "Authorization: Bearer $KUBE_TOKEN" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1/namespaces/default/pods

正常的输出如下所示。

{ 
  "kind": "PodList", 
  "apiVersion": "v1", 
  "metadata": { 
    "selfLink": "/api/v1/namespaces/default/pods", 
    "resourceVersion": "2285" 
  }, 
  "items": [ 
   ... 
  ] 
} 

如果发生错误,请检查kubernetes-internal服务及其终结点是否正常。

kubectl get service kubernetes-internal
NAME                TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE 
kubernetes-internal ClusterIP   10.96.0.1    <none>        443/TCP   25m 
kubectl get endpoints kubernetes-internal
NAME                ENDPOINTS          AGE 
kubernetes-internal 172.17.0.62:6443   25m 

如果两个测试都返回与之前相似的响应,并且返回的 IP 和端口与容器的相匹配,那么很可能是 kube-apiserver 未运行或被网络阻止。

有四个主要原因可能导致访问被阻止:

还可以使用容器见解检查 kube-apiserver 日志。 有关查询 kube-apiserver 日志和其他许多查询的信息,请参阅 如何从容器见解查询日志

最后,可以检查群集本身上的 kube-apiserver 状态及其日志:

# Check kube-apiserver status. 
kubectl -n kube-system get pod -l component=kube-apiserver 

# Get kube-apiserver logs. 
PODNAME=$(kubectl -n kube-system get pod -l component=kube-apiserver -o jsonpath='{.items[0].metadata.name}')
kubectl -n kube-system logs $PODNAME --tail 100

403 - Forbidden如果返回错误,则 kube-apiserver 可能配置了基于角色的访问控制(RBAC),并且容器ServiceAccount可能无权访问资源。 在这种情况下,应创建适当的 RoleBinding 对象和 ClusterRoleBinding 对象。 有关角色和角色绑定的信息,请参阅 访问和身份。 有关如何在群集上配置 RBAC 的示例,请参阅 使用 RBAC 授权

供稿人

本文由Microsoft维护。 它最初是由以下贡献者撰写的。

主要作者:

其他参与者:

后续步骤