你当前正在访问 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 范围,请使用 Azure CLI 中的以下 az aks show 命令。 如果 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. 使用 Azure CLI 中的 az aks update 命令更新 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 可能无权访问资源。 在这种情况下,应该创建适当的 RoleBindingClusterRoleBinding 对象。 有关角色和角色绑定的信息,请参阅访问和标识。 有关如何在群集上配置 RBAC 的示例,请参阅使用 RBAC 授权

作者

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

主要作者:

其他参与者:

后续步骤