自定义网络安全组阻止流量

访问托管在 Azure Kubernetes 服务 (AKS) 群集上的应用程序时,会收到“超时”错误消息。 即使应用程序正在运行并且其余的配置似乎正确,也可能发生此错误。

先决条件

  • 用于连接到群集的 Kubernetes kubectl 工具或类似工具。 若要使用 Azure CLI 安装 kubectl,请运行 az aks install-cli 命令。

  • 客户端 URL (cURL) 工具或类似的命令行工具。

  • 用于处理包的 apt-get 命令行工具。

症状

如果运行以下 kubectl get 和 cURL 命令,则会遇到类似于以下控制台输出的“超时”错误:

$ kubectl get pods
NAME                             READY   STATUS    RESTARTS   AGE
my-deployment-66648877fc-v78jm   1/1     Running   0          5m53s

$ kubectl get service
NAME                      TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)        AGE
my-loadbalancer-service   LoadBalancer   10.0.107.79   10.81.x.x   80:31048/TCP   4m14s

$ curl -Iv http://10.81.124.39  # Use an IP address that fits the "EXTERNAL-IP" pattern.
*   Trying 10.81.x.x:80...
* connect to 10.81.x.x port 80 failed: Timed out
* Failed to connect to 10.81.x.x port 80 after 21033 ms: Timed out
* Closing connection 0
curl: (28) Failed to connect to 10.81.x.x port 80 after 21033 ms: Timed out

原因

如果每次都遇到相同的“超时”错误,这通常表明网络组件正在阻止流量。

若要排查此问题,可以从检查对 Pod 的访问权限开始,然后通过 由内到外 的方法转到客户端。

若要检查 Pod,请运行以下命令kubectl getkubectl describe 命令:

$ kubectl get pods -o wide
NAME                             READY   STATUS    RESTARTS   AGE   IP            NODE                               
my-deployment-66648877fc-v78jm   1/1     Running   0          53s   172.25.0.93   aks-agentpool-42617579-vmss000000

$ kubectl describe pod my-deployment-66648877fc-v78jm  # Specify the pod name from the previous command.
...
...
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  117s  default-scheduler  Successfully assigned default/my-deployment-66648877fc-v78jm to aks-agentpool-42617579-vmss000000
  Normal  Pulling    116s  kubelet            Pulling image "httpd"
  Normal  Pulled     116s  kubelet            Successfully pulled image "httpd" in 183.532816ms
  Normal  Created    116s  kubelet            Created container webserver
  Normal  Started    116s  kubelet            Started container webserver

根据此输出,Pod 似乎正常运行,无需重启任何操作。

打开测试 Pod 以检查对应用程序 Pod 的访问权限。 运行以下 kubectl getkubectl runapt-get和 cURL 命令:

$ kubectl get pods -o wide  # Get the pod IP address.
NAME                             READY   STATUS    RESTARTS   AGE     IP            NODE                                
my-deployment-66648877fc-v78jm   1/1     Running   0          7m45s   172.25.0.93   aks-agentpool-42617579-vmss000000  

$ kubectl run -it --rm aks-ssh --image=debian:stable  # Launch the test pod.
If you don't see a command prompt, try pressing enter.
$ root@aks-ssh:

$ # Install packages inside the test pod.
$ root@aks-ssh: apt-get update -y && apt-get install dnsutils -y && apt-get install curl -y
Get:1 http://deb.debian.org/debian bullseye InRelease [116 kB]
Get:2 http://deb.debian.org/debian bullseye-updates InRelease [39.4 kB]
...
...
Running hooks in /etc/ca-certificates/update.d...
done.

$ # Try to check access to the pod using the pod IP address from the "kubectl get" output.
$ curl -Iv http://172.25.0.93
*   Trying 172.25.0.93:80...
* Connected to 172.25.0.93 (172.25.0.93) port 80 (#0)
...
...
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
...
...
* Connection #0 to host 172.25.0.93 left intact

可以直接访问 Pod。 因此,应用程序正在运行。

定义的服务是一种 LoadBalancer 类型。 这意味着从最终客户端到 Pod 的请求流将如下所示:

客户端 >> 负载均衡器 >> AKS 节点 >> 应用程序 Pod

在此请求流中,可以通过以下组件阻止流量:

  • 群集中的网络策略
  • 网络安全组 (AKS 子网和 AKS 节点的 NSG)

若要检查网络策略,请运行以下命令kubectl get

$ kubectl get networkpolicy --all-namespaces
NAMESPACE     NAME                 POD-SELECTOR             AGE
kube-system   konnectivity-agent   app=konnectivity-agent   3h8m

只有 AKS 默认策略存在。 因此,网络策略似乎不会阻止流量。

若要使用 AKS 检查 NSG 及其关联规则,请执行以下步骤:

  1. Azure 门户中,搜索并选择“虚拟机规模集”。

  2. 在规模集实例列表中,选择正在使用的实例。

  3. 在规模集实例的菜单窗格中,选择 Networking

此时会显示规模集实例的“ 网络 ”页。 在“ 入站端口规则 ”选项卡中,将显示两组规则,它们基于对规模集实例执行操作的两个 NSG:

  • 第一组由子网级别的 NSG 规则组成。 这些规则显示在以下注释标题下:

    附加到子网的网络安全组 <my-aks-nsg> (: <my-aks-subnet>)

    如果使用 AKS 群集的自定义虚拟网络和自定义子网,则这种安排很常见。 子网级别的规则集可能类似于下表。

    优先级 名称 端口 协议 Source 目标 操作
    65000 AllowVnetInBound 任何 任何 VirtualNetwork VirtualNetwork 允许
    65001 AllowAzureLoadBalancerInBound 任何 任何 AzureLoadBalancer 任何 允许
    65500 DenyAllInBound 任何 任何 任何 任何 拒绝
  • 第二组由网络适配器级别的 NSG 规则组成。 这些规则显示在以下注释标题下:

    附加到网络接口的网络安全组 aks-agentpool-agentpool-number-nsg<> (:aks-agentpool-vm-scale-set-number-vmss<>)

    此 NSG 由 AKS 群集应用,并由 AKS 管理。 相应的规则集可能类似于下表。

    优先级 名称 端口 协议 Source 目标 操作
    500 <guid-TCP-80-Internet> 80 TCP Internet 10.81.x。X 允许
    65000 AllowVnetInBound 任何 任何 VirtualNetwork VirtualNetwork 允许
    65001 AllowAzureLoadBalancerInBound 任何 任何 AzureLoadBalancer 任何 允许
    65500 DenyAllInBound 任何 任何 任何 任何 拒绝

在网络适配器级别,IP 地址为 10.81 处有 TCP 的 NSG 入站规则。x.端口 80 上的 x (表中) 突出显示。 但是,NSG 在子网级别的规则中缺少等效的规则。

为什么 AKS 没有将规则应用于自定义 NSG? 因为 AKS 不对其子网应用 NSG,并且不会修改与该子网关联的任何 NSG。 AKS 仅在网络适配器级别修改 NSG。 有关详细信息,请参阅 是否可以使用 AKS 配置 NSG?

解决方案

如果启用了应用程序在特定端口上进行访问,则必须确保自定义 NSG 允许该端口作为 Inbound 规则。 在子网级别的自定义 NSG 中添加相应的规则后,可以访问该应用程序。

$ curl -Iv http://10.81.x.x
*   Trying 10.81.x.x:80...
* Connected to 10.81.x.x (10.81.x.x) port 80 (#0)
...
...
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
...
...
* Connection #0 to host 10.81.x.x left intact

联系我们寻求帮助

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