网络策略 NetworkPolicy
本教程共 65 篇 · 第 30 篇 · 更新于 2026-08-14 · 约 15 分钟阅读
本节目标:学会用 NetworkPolicy 给 Pod 之间的流量”上锁”。看懂入口/出口隔离、四种选择器怎么组合、默认拒绝策略怎么写,以及为什么它离不开支持策略的 CNI。
默认情况下,Kubernetes 集群里的网络是”全通”的。同一个命名空间里的 Pod 想连谁就连谁,跨命名空间也基本拦不住。这在测试环境无所谓,到了生产就成了大隐患:一个被攻破的前端 Pod,能直接摸到数据库。
NetworkPolicy(网络策略)就是用来关上这扇门的。
30-1 它工作在哪一层
NetworkPolicy 控制的是 OSI 第三层(IP)和第四层(端口)的流量,也就是 TCP、UDP、SCTP 这类。它管不了 HTTP 路径、域名这种七层东西——那是 Ingress 或服务网格的活。
它的思路是”以应用为中心”:你声明”某组 Pod 允许和哪些实体通信”,剩下的流量就被挡住。注意是被允许的才放行,不是被禁止的才拦——这是个白名单模型。
NoteNetworkPolicy 是白名单。写了一条策略后,没被明确允许的流量就会被拒绝。这点和写防火墙一样,先想清楚要放哪些。
30-2 前置条件:CNI 得支持
这是最关键的一点。NetworkPolicy 本身只是一份”声明”,真正去拦截、放行流量的,是底层的 CNI 网络插件。
如果你用的是纯 Flannel,哪怕写一百条 NetworkPolicy,流量照样全通——因为 Flannel 不实现策略处理。要用 NetworkPolicy,得选 Calico、Cilium 这类支持策略的实现。
Warning光创建 NetworkPolicy 资源、底层却没支持的 CNI,等于贴了告示没人执行。先确认你的网络插件支持策略,否则写了也是摆设。
30-3 两种隔离:入口与出口
Pod 的隔离分两个方向:
- 入口隔离(Ingress):控制谁能连进来。
- 出口隔离(Egress):控制能连出去。
默认情况下,两个方向都是非隔离的,所有流量放行。一旦有某条 NetworkPolicy 选中了这个 Pod,且在 policyTypes 里写了 Ingress,那这个 Pod 的入口就被隔离了——只有策略 ingress 列表里允许的流量能进。
出口同理。而且多个策略是相加的,不会互相冲突。只要有一条允许,连接就成立;要彻底放行,源端出口策略和目的端入口策略都得放行。
30-4 一个完整的例子
下面这条策略把 default 命名空间里 role=db 的 Pod 同时做了入口和出口隔离:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
它表达的意思是:
- 只有这些来源能连
role=db的 6379 端口:role=frontend的 Pod、project=myproject命名空间里的 Pod、以及除172.17.1.0/24外的172.17.0.0/16网段。 - 这些数据库 Pod 只能往
10.0.0.0/24的 5978 端口发起连接。
Tip
podSelector不写任何 label(空选择器)就代表”选中该命名空间下的所有 Pod”。这是写默认策略的常用手法。
30-5 四种 from/to 选择器
在 ingress.from 或 egress.to 里,可以混用四种选择器挑”流量从哪来 / 到哪去”:
- podSelector:同命名空间内、带指定标签的 Pod。
- namespaceSelector:带指定标签的整个命名空间里的所有 Pod。
- podSelector + namespaceSelector 组合:某个命名空间里、带特定标签的 Pod。
- ipBlock:一组 IP CIDR,通常用于集群外部地址。
关于第 3 点有个经典坑。下面这段,namespaceSelector 和 podSelector 是同一级的数组元素,意思是”来自 user=alice 命名空间 或 role=client 的 Pod”:
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
- podSelector:
matchLabels:
role: client
而下面这样把它们写进同一个元素,意思是更严格的”既在 user=alice 命名空间,又是 role=client 的 Pod”:
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
podSelector:
matchLabels:
role: client
Warning缩进差一个层级,语义从”或”变成”且”。写多条件时务必用
kubectl describe看 Kubernetes 怎么解读你的策略,别凭感觉。
30-6 默认拒绝:把门先关上
默认全通太危险,常见做法是先给命名空间上一个”默认拒绝所有入站”的策略:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress
podSelector: {} 选中所有 Pod,但 ingress 列表为空,于是没有任何入站被允许。哪怕别的策略没选中的 Pod,也被这道”兜底”挡住了。它对出口没影响。
反过来想要全放,也可以写一条允许所有入站:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
namespace: default
spec:
podSelector: {}
ingress:
- {}
policyTypes:
- Ingress
ingress 里一个空的 {} 表示”允许一切来源”。有了它,再叠加别的条件也不会把流量误杀。
Warning默认拒绝所有出口会顺带把 DNS 流量也掐掉。如果你的工作负载要解析域名,必须额外写一条允许访问集群 DNS 服务的出口策略,否则 Pod 连名字都查不出来。
30-7 能精细到什么程度
NetworkPolicy 支持:
- 按
protocol(TCP/UDP/SCTP)区分。 - 按端口号限制。
- 入站、出站分别定义。
- 多策略叠加(取并集)。
它做不了的:
- 七层内容过滤(URL、Header、域名)。
- 对 Service VIP 做基于名字的复杂路由。
- 加密、认证这类安全能力。
这些要靠服务网格(如 Istio、Linkerd)来补。NetworkPolicy 负责”通不通”,服务网格负责”怎么通、通得安不安全”。
30-8 调试小贴士
写完策略发现不通,先排查三件事:
- CNI 到底支不支持策略?(最常见的原因)
- 源端出口策略和目的端入口策略是否都放行了?
podSelector/namespaceSelector的标签是否真的对得上 Pod?
Tip策略是白名单相加。连接失败往往是”有一端没放行”。用
kubectl describe networkpolicy核对实际生效的选择器,比肉眼看 YAML 靠谱。
小结
NetworkPolicy 在三四层给 Pod 流量上白名单。它依赖支持策略的 CNI 才能真正拦流量。入口、出口两个方向独立隔离,多个策略取并集。
默认全通不安全,先用默认拒绝兜底,再逐条放行需要的流量。它管”通不通”,管不了七层细节——那是下一章南北向/东西向和服务网格的议题。