DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

NetworkPolicy 已放行 DNS,查询仍超时:检查 namespaceSelector 的标签

namespaceSelector 匹配标签而非对象名称。核对真实 DNS 路径、Namespace 标签和 peer 层级,在必要端口与目标范围内修正出口许可。

启用出口隔离后,Pod 的 DNS 查询开始超时。策略里已经写了 kube-system 和端口 53,但 namespaceSelector 使用的是 name: kube-system,实际 Namespace 却没有这个标签时,这条规则不会匹配预期的 DNS 命名空间。

Namespace 的对象名称与任意名为 name 的标签不是同一字段。下面针对普通 Pod 网络、插件确实执行 NetworkPolicy,且 DNS 由相应命名空间里的 Pod 提供的情况。NodeLocal DNS、hostNetwork 或其他本地解析路径不能直接照搬。

查 Namespace 标签,不要只看 Service

先确认客户端实际 nameserver,再读取 DNS 所在命名空间与 Pod 的标签。以下假设目标确实在 kube-system,镜像包含 cat:

kubectl -n app exec client-pod -- cat /etc/resolv.conf
kubectl get namespace kube-system --show-labels
kubectl -n kube-system get pods --show-labels
kubectl -n app get networkpolicy -o yaml

对照所有选中客户端的出口策略,不能只看一份名为 allow-dns 的文件。策略许可是叠加的,有其他宽泛规则时,偶然成功也不能证明这条选择器正确。

若 Namespace 只有 kubernetes.io/metadata.name=kube-system,下面这个局部选择器不会因为对象就叫 kube-system 而自动成立:

namespaceSelector:
  matchLabels:
    name: kube-system

Kubernetes 1.22 起,控制平面为 Namespace 设置的 kubernetes.io/metadata.name 标签已稳定,值就是该命名空间名称。现场仍应读取标签确认;更旧集群或不同平台需按实际支持选择受维护的身份标签。

Service 上有 name 或 app 标签,也不会让 Namespace 自动拥有同名标签。另一个命名空间使用 name 选择器能够访问,可能只是它本来就有这个自定义标签,不能推断所有系统命名空间都一样。

两种选择器放在同一个 peer 内

只写 podSelector 时,选择范围是 NetworkPolicy 自己所在的命名空间。要限定另一个命名空间中的 DNS Pod,应在同一个 to 成员里同时写 namespaceSelector 和 podSelector,两者共同匹配。

下面是完整策略示例,必须先确认客户端 app 标签、DNS Pod 的 k8s-app 标签和监听端口与现场一致:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-app-dns
  namespace: app
spec:
  podSelector:
    matchLabels:
      app: example-client
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

这是对已确认 DNS 目标的出口许可,不提供应用其余出口,也不替代现有入站策略。不要因为只想允许 DNS,就把原有业务许可整份覆盖。

如果在 namespaceSelector 和 podSelector 前各写一个 -,就变成两个 peer 的“或”:相应命名空间的 Pod,以及本命名空间匹配标签的 Pod,任一满足即可。它不是“该命名空间中的该 DNS Pod”,许可范围会变化。

DNS 地址路径还需要对上

客户端 resolv.conf 可能指向 DNS Service 的 ClusterIP,最终后端则是 DNS Pod。使用 ipBlock 时,地址转换发生在策略判断前还是后,依赖插件与 Service 实现;某个 Pod IP 的规则能工作,不能推广成所有集群都应固定放行该 IP。

DNS Pod 地址可能改变,也不应为一次查询失败许可整个节点或 Pod 网段。若使用 NodeLocal DNS 或 hostNetwork,先查该方案的网络和策略契约;普通 peer 选择器可能没有按同一种方式匹配流量。

在原客户端验证,并保留隔离

保存原策略与标签,在隔离环境或批准的变更范围修正准确选择器。用原客户端的正常查询与应用连接验证,确认必要的 UDP、TCP DNS 路径可用,其他本来禁止的出口仍被限制。

只有解析恢复、业务却仍连接失败时,继续查目标 Service 后端和端口。客户端使用了错误 DNS 策略的 hostNetwork 场景可另查ClusterFirstWithHostNet 的适用条件,不应重复扩大 NetworkPolicy 范围。

回退时恢复原规则与本次改动的标签,核对它们没有影响其他引用者。不要用删除全部出口隔离的方式作为最终修复,也不要为了恢复规则清空命名空间或重建全部 DNS 服务。