Skip to content

NetworkPolicy

NetworkPolicy 用来限制 Pod 的入站和出站流量。默认很多集群里 Pod 之间是互通的,NetworkPolicy 可以把访问范围收窄到特定 namespace、Pod label、端口和协议。

前提——CNI 必须支持

NetworkPolicy 是否生效取决于 CNI。Calico、Cilium 完全支持;Flannel 等简单 CNI 不支持或支持有限。

bash
kubectl -n kube-system get pods -o wide | grep -E 'calico|cilium|flannel'

CNI 不支持 NetworkPolicy 时,创建策略对象也不会真的拦截流量。这种"策略创建了但实际没生效"的情况很容易被误判为策略已生效。

策略作用对象

NetworkPolicy 先用 podSelector 选择被保护的 Pod:

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-policy
  namespace: demo
spec:
  podSelector:
    matchLabels:
      app: api  # 策略作用到 app=api 的 Pod
  policyTypes:
    - Ingress

podSelector: {} 表示当前 namespace 所有 Pod。

默认拒绝入站

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

创建后,demo namespace 里所有 Pod 的入站流量被拒绝,除非有明确的 allow 规则放行。

白名单规则

允许带 role=frontend 的 Pod 访问 app=api 的 8080:

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: demo
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              role: frontend
      ports:
        - protocol: TCP
          port: 8080

这里的 from.podSelector 只匹配同 namespace 的 Pod。跨 namespace 需要加 namespaceSelector

yaml
ingress:
  - from:
      - namespaceSelector:
          matchLabels:
            team: platform
    ports:
      - protocol: TCP
        port: 8080

给 namespace 打标签:

bash
kubectl label namespace platform team=platform

出站限制——别忘了 DNS

限制出站时要特别注意 DNS。很多服务配置出站策略后第一个问题是 DNS 被拦,导致所有外部依赖看起来都断了:

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: demo
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

排查

bash
kubectl -n demo get networkpolicy
kubectl -n demo describe networkpolicy allow-frontend-to-api

临时 Pod 测试:

bash
kubectl -n demo run test-client --rm -it --image=curlimages/curl --restart=Never -- sh
curl -v http://api:8080/healthz
现象方向
策略创建但不生效CNI 不支持策略
同 namespace 访问失败podSelector、端口、Pod label
跨 namespace 失败namespace label、namespaceSelector
域名解析失败Egress 策略没放 DNS
Service 访问超时策略拦的是 Pod 流量,先直连 Pod IP 对比

NetworkPolicy 是白名单思路。实施时先从非核心 namespace 开始,观察日志和连接关系,再逐步收紧——一次性全集群默认拒绝,容易把监控、日志采集、CoreDNS 和基础设施也一起拦掉。