CFN Cloud
Cloud Future New Life
en zh
2025-12-29 · 0 次浏览

Kubernetes Tips:NetworkPolicy 从“默认拒绝”到可运营的落地路径

一步步上线 NetworkPolicy:先做 ingress 默认拒绝,再做 DNS/关键依赖 egress 白名单,避免“一刀切”把业务打挂。

NetworkPolicy 是 Kubernetes 里非常高 ROI 的隔离能力:能显著降低横向移动与爆炸半径。但它也很容易在上线第一天就把业务“全断网”,原因通常是:

  • 没理解 NetworkPolicy 的默认行为(它是 allow-list)
  • egress 没规划好(DNS、监控、追踪、外部依赖全要走)
  • 标签体系不稳定(policy 选不中或选错对象)

这篇 tips 给你一个可运营的推进顺序。

前置条件:你的 CNI 是否真的执行 NetworkPolicy

NetworkPolicy 的执行依赖 CNI 实现:

  • 有的 CNI 默认支持并执行
  • 有的需要显式启用
  • 有的对某些规则存在限制

上线之前先确认平台能力,否则你写了 policy 可能“看起来有”,实际不生效。

NetworkPolicy 的核心语义:选中后“默认拒绝”

很多人误以为 NetworkPolicy 是“加一条 deny 规则”。实际更像这样:

  • 如果某个 Pod 在某个方向(Ingress/Egress)没有被任何 policy 选中,那么该方向 默认允许
  • 一旦有 policy 选中了该 Pod 且包含该方向,则该方向 默认拒绝,只允许 policy 明确放行的流量。

这就是为什么“默认拒绝”通常是:

  • podSelector: {}(选中命名空间内所有 Pod)
  • policyTypes: [Ingress][Egress]

第 1 步:先做 namespace 级别的 Ingress 默认拒绝

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: app
spec:
  podSelector: {}
  policyTypes:
    - Ingress

这会阻止 app 命名空间内 Pod 的所有入站流量,除非后续显式放行。

上线建议:

  • 先在非核心命名空间试点
  • 或只对某个 app label 生效(更小爆炸半径)

第 2 步:放行来自 ingress controller/gateway 的流量

例如允许 ingress-nginx 命名空间过来的流量访问 app=api 的 8080:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-ingress
  namespace: app
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes: [Ingress]
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
      ports:
        - protocol: TCP
          port: 8080

注意:namespaceSelector 依赖命名空间标签,确认你的集群确实有这些 label。

第 3 步:如果服务之间互调,先放行“同命名空间”

微服务常见需要 namespace 内互通:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-same-namespace
  namespace: app
spec:
  podSelector: {}
  policyTypes: [Ingress]
  ingress:
    - from:
        - podSelector: {}

这一步的意义是:先让业务恢复互通,再逐步细化到“谁能访问谁”(按 label 收敛)。

第 4 步:Egress 要当成迁移项目来做(DNS 先行)

Egress 是最容易把业务打挂的一环,因为你很可能不知道依赖到底有多少:

  • DNS(必需)
  • 指标/日志/追踪(Prometheus/OTel/日志收集)
  • 外部 API(支付、短信、身份等)
  • 证书、时间同步、镜像仓库(视环境而定)

最推荐的 egress 第一步:先放行 DNS

一个更“紧”的 DNS 放行方式是只放行 kube-system 里 CoreDNS:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: app
spec:
  podSelector: {}
  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

不同集群 CoreDNS 的 label 可能不同,按实际改。

外部访问:ipBlock 很实用,但要认清局限

NetworkPolicy 支持 ipBlock

egress:
  - to:
      - ipBlock:
          cidr: 203.0.113.0/24
    ports:
      - protocol: TCP
        port: 443

注意点:

  • 它是 IP 维度,不是 DNS 维度;外部 SaaS IP 可能变动
  • 很多团队会引入统一 egress proxy/NAT,维持可控出口

调试与排障:先确认“哪些 policy 选中了我”

当你发现“突然不通”:

kubectl get netpol -n app
kubectl describe netpol -n app <name>
kubectl exec -n app -it <pod> -- sh

如果 Pod 内没有工具,建议用 ephemeral container 来跑 curl/dig/nc,这样不污染生产镜像且符合真实网络命名空间。

很多时候你会发现:

  • 不是 policy 写错,而是 label 没打上
  • 或者某个“宽松 allow” policy 让流量仍然放行(policy 的效果是 union)

平台常见的“基础放行集”

很多平台最终都会沉淀一组“每个 namespace 都需要”的 policy:

  1. 允许 ingress/gateway 进来
  2. 允许 monitoring 抓 /metrics
  3. 允许 egress DNS

把这些做成模板/基线,会让运营成本大幅下降。

Checklist

  • 确认 CNI 真正执行 NetworkPolicy
  • 先做 ingress 默认拒绝,再逐步放行入口
  • egress 从 DNS 开始,逐步补齐依赖白名单
  • 维持稳定的 label 体系(policy 依赖 labels)
  • 试点/渐进上线,避免“一刀切”

参考链接

FAQ

Q: 为什么策略不生效? A: 需要支持 NetworkPolicy 的 CNI 插件;没有 provider 时策略会被忽略。

Q: DNS 怎么放行? A: 添加 egress 到 kube-dns/CoreDNS(TCP/UDP 53),并限定 namespace 或 label。

Q: 默认就是隔离吗? A: 只有被策略选择的 Pod 才会被隔离;没有被选择的 Pod 仍然是默认放行。