容器网络策略的生效范围由策略中标签选择器匹配到的Pod集合决定,命名空间本身是硬隔离边界,排查时优先核对策略方向、Pod标签和CNI组件的策略翻译链。
先搞明白:策略到底管住了谁
生产环境里最常见的争议是“我明明写了NetworkPolicy,流量还是通的”,多数情况下,问题出在“你以为的生效范围”和“实际匹配的Pod集合”不一致,Kubernetes的NetworkPolicy按层级生效:命名空间是天然边界,策略文件里spec.podSelector决定策略管哪些Pod,ingress和egress分别约束入方向和出方向的数据流。
举个具体场景:你的订单服务跑在production命名空间,Pod标签是app=order-service,你在同一命名空间写了一条策略,只允许app=api-gateway访问8080端口,如果api-gateway的Pod标签写成了app=api_gateway(下划线),这条策略就匹配不到任何来源,流量照常通过,这类肉眼难以察觉的标签错位,是策略“看似生效实则失效”的第一大原因。
同时要记住,策略只影响Pod与Pod、Pod与外部网络之间的通信,Service本身不参与匹配,但Service选择器指向的Pod会,换句话说,你给Deployment加了网络策略,但不小心让另一个Deployment的Pod标签重叠,策略范围就扩大了,容器网络策略配置场景里,标签重叠引发的策略误伤是运维群里的常客,排查成本往往比流量不通更高。
容器网络策略不生效怎么排查
接到告警说“服务被拦了”或者“策略没拦住”,按以下顺序逐层往下查,路径是显式的这也意味着任何一步出错都会导致策略行为偏离预期。
第一步:看策略声明有没有语法和逻辑错误
- 运行
kubectl describe networkpolicy检查策略是否被API Server接受,如果没报错但是状态一直不更新,先把旧策略删掉重建一次 - 核对
spec.podSelector的键值对,用kubectl get pods --show-labels确认目标Pod确实带这些标签 - 尤其注意标签值的大小写:标签值区分大小写,
app=OrderService和app=orderservice是两个完全不同的选择器 policyTypes字段必须显式声明,K8s默认行为是:如果你只写了ingress规则,egress策略不会被应用;反之亦然,只声明了ingress但期望同时限制出方向流量,这是策略声明时的逻辑盲区

第二步:检查CNI组件的策略翻译链
策略本身只是声明,真正把规则翻译成防火墙规则的是CNI插件,这里出现了第一个关键分叉:不同CNI的实现机制完全不同。
以最多人用的Calico为例,策略落地后要经过三层翻译:Kubernetes API → Calico API → Felix组件生成iptables规则。排查命令如下:
calicoctl get networkpolicy --output yaml # 查看Calico侧的策略实体 calicoctl node status # 确认Felix运行状态 iptables -L -n | grep -i cali # 看宿主机iptables里是否有对应规则
如果你用的是Cilium,替换成:
cilium policy get cilium endpoint list cilium monitor -v # 实时抓取被丢弃的数据包
如果你发现Kubernetes侧策略存在,但iptables里空无一物,问题基本锁死在CNI组件,先查Felix或Cilium Agent日志,有不少用户卡在这一步,原因是CNI版本和Kubernetes版本不兼容,老版本插件根本没有解析新版策略字段的能力。
第三步:挨个验证Pod的流量路径
团队内部经常争议“策略加了但流量还是通”,这时候用最小化验证法:手动创建一个带固定标签的测试Pod,从它发起请求访问目标服务,同时开启抓包工具,这里行业共识认为,用tcpdump在目标Pod所在节点执行tcpdump -i calixx port 8080,可以快速区分是策略丢弃还是应用层拒绝。
一个值得注意的细节是:NetworkPolicy对已建立的连接不生效,如果线上服务的连接在策略下发前就已建立,存量连接仍然能继续通信,需要重启相关Pod让连接断开重连才能彻底验证新策略,这个知识点很容易被忽略,但运维老手多会在排查时第一时间确认Pod的存活时间。
策略冲突和优先级怎么裁决
当多个NetworkPolicy指向同一组Pod时,生效规则是规则取并集而非覆盖,系统会先计算所有匹配到的策略里各自的规则集,只要某条来源IP在一个策略里被允许,另一个策略不允许,流量照样放行。
用一张表说清楚:
| 场景 | 策略A | 策略B |
实际结果 |
|---|---|---|---|
| 两个ingress规则 | 允许来源A访问80端口 | 允许来源A访问443端口 | 来源A可访问80和443 |
| ingress允许+egress限制 | 允许来源B访问8080 | 禁止访问外网 | 来源B可访问8080,但不能出外网 |
| 一允许一拒绝 | 允许所有来源访问80 | 拒绝来源C访问所有端口 | 来源C可访问80,因为策略A单独成立 |
这个“允许占优”规则是排查阶段的兜底思路,校准基线时,默认先写一个all deny策略,再逐步放行业务端口,利用增量式验证确认策略语义符合预期,大部分团队落地策略时首选这个模式,能有效降低后继排查的认知负担。
Kubernetes网络策略和Cilium差异
这个问题常出现在选型讨论和跨团队协作里,值得单独展开,原生NetworkPolicy功能相对有限,只能处理L3/L4层的IP和端口;CNI插件如Cilium则扩展了L7层过滤能力,可以识别HTTP路径、方法等应用层语义。
| 能力维度 | 原生NetworkPolicy | CiliumNetworkPolicy |
|---|---|---|
| L3/L4层控制 | 支持 | 支持 |
| L7层控制 | 不支持 | 支持 |
| 域名维度访问控制 | 不支持 | 支持 |
| 集群外IP白名单 | 不支持,仅支持IP段 | 支持FQDN规则 |
| 审计日志 | 无内置方案 | 支持流量审计和遥测 |
如果你的集群里跑的是普通无状态API服务,原生策略已经足够;但金融、政企等合规要求较高的行业,普遍会选Cilium的FQDN策略或HTTP感知策略来做更细粒度的管控,这里的取舍在于运维复杂度和安全能力的平衡,Cilium的Hubble组件还能提供可视化流量视图,排查效率会比纯看iptables高不少,代价是EBPF内核版本要求更苛刻。
落地检查清单
策略从测试环境搬到生产环境前,按清单扫一遍可避免大多数“事故”。
- 确认命名空间隔离级别:是否允许跨命名空间互相访问,如果允许需要显式写允许规则
- 确认Egress配置覆盖DNS解析:绝大多数业务Pod都需要访问kube-dns(CoreDNS),如果写了egress规则却漏了UDP 53端口放行,Pod解析域名会超时,服务表现为“间歇性不可用”
- 确认端口范围精确匹配:Service的targetPort和Pod容器内实际监听端口必须一致,策略里写的端口必须是Pod监听端口,不是Service端口
- 标记好策略所有者:几十条策略堆积后没人敢动,时间久了就成为安全隐患,建议在策略规范要求里强制写owner标签
- 灰度验证:先在测试命名空间完整模拟业务流量,确认策略不会拦截健康检查和探针流量

据权威调查机构数据,业界普遍认为容器网络策略配置相关问题的占比仅次于存储和编排配置错误,位居容器运维事故前列,多数企业的排查耗时集中在“策略本身没错但范围比预想大”这类语义边界模糊问题上。
回到开始的问题:策略存了不等于策略生效,策略生效不等于策略在预期范围内生效,始终围绕标签选择器、方向性、CNI翻译链这三个环节展开校验,就能避开绝大多数坑,最后给你的建议是用kubectl get networkpolicy -A定期把存量策略导出来过一遍,关注是否有孤立策略或重复覆盖的情况,这份整理成本远低于一次线上事故的排查成本。
容器网络策略生效范围常见问题
问:NetworkPolicy里的port字段不写会怎样?
如果不写port,策略会匹配该方向上的所有端口流量,通常在“允许特定来源访问所有端口”的场景下使用,但生产环境不建议这么干,端口写全有助于降低暴露面缩小影响范围。
问:跨命名空间访问时,策略写在自己命名空间还是对方命名空间?
分两边写,目标Pod的命名空间里通过ingress规则允许来源命名空间的Pod访问;发起方命名空间里通过egress规则允许出口到目标命名空间的CIDR,只写一边,策略都会被对端默认丢弃。
问:为什么策略应用后,从节点发起的访问不受限制?
因为NetworkPolicy只作用于Pod网络命名空间里的流量,节点自身发出的流量不经过Pod的网络栈,因此不受策略约束,排查问题时,用节点上curl访问业务Pod验证的是节点到Pod链路,不代表业务Pod之间也是同样结果。
