前言
前面写 Service 时,我把它理解成“给一组 Pod 提供稳定入口”。默认情况下,很多集群里的 Pod 之间是可以互相访问的。
这在学习时很方便,但在真实环境里会带来一个问题:
1 | frontend 能访问 demo-api |
如果完全不限制,网络边界就会很松。
NetworkPolicy 要解决的就是 Pod 之间的网络访问控制。
我目前把它理解成:
1 | Service |
它像在房间门口贴访问规则:不是知道门牌号就一定能进去,还要看你是不是被允许。
一个重要前提:网络插件要支持
NetworkPolicy 是 Kubernetes API 资源,但真正执行规则的是网络插件。
1 | NetworkPolicy 对象 |
如果集群使用的网络插件不支持 NetworkPolicy,那么创建了 NetworkPolicy 对象也可能不会产生实际限制。
这一点很重要。排查时不能只看:
1 | kubectl get networkpolicy |
还要确认集群网络方案是否支持它,比如 Calico、Cilium 等通常支持 NetworkPolicy。
所以 NetworkPolicy 不是“写了 YAML 就一定生效”,它依赖底层网络实现。
默认不是隔离的
NetworkPolicy 有一个容易误解的地方:没有 NetworkPolicy 时,Pod 通常不是默认隔离。
可以先这样理解:
1 | 没有 NetworkPolicy |
也就是说,策略是加上去的边界。
如果想让某个 Namespace 默认拒绝所有入站流量,可以创建一个选择所有 Pod、但不允许任何 ingress 的策略。
1 | apiVersion: networking.k8s.io/v1 |
这里的 podSelector: {} 表示选中当前 Namespace 下所有 Pod。
1 | demo-prod 所有 Pod |
Ingress 和 Egress
NetworkPolicy 里的 ingress 和 egress 不是 Kubernetes Ingress 资源。
这里的含义是:
1 | ingress |
示意图:
1 | Client Pod |
所以不要把这两个概念混在一起:
1 | Ingress 资源 |
名字相同,语境不同。
允许 frontend 访问 demo-api
假设有两个应用:
1 | frontend Pod labels: |
希望只允许 frontend 访问 demo-api 的 8080 端口。
1 | apiVersion: networking.k8s.io/v1 |
拆开看:
1 | podSelector |
图示:
1 | frontend Pod |
namespaceSelector
有时访问来源不是同一个 Namespace 的 Pod,而是某个 Namespace 里的 Pod。
例如只允许带有 team=backend 标签的 Namespace 访问:
1 | ingress: |
这会匹配 Namespace 标签,而不是 Pod 标签。
1 | namespace labels: team=backend |
如果想同时限制 Namespace 和 Pod,可以组合:
1 | ingress: |
可以理解成:
1 | 来源 Pod 必须同时满足: |
这里缩进和结构很重要。写错后,策略含义可能完全不同。
ipBlock
NetworkPolicy 也可以按 IP 段允许来源或去向。
1 | ingress: |
还可以排除某些 IP:
1 | ingress: |
不过在 Kubernetes 内部 Pod 通信里,我更倾向用 Label 和 Namespace 表达关系,而不是依赖 Pod IP。Pod IP 会变,标签关系更稳定。
ipBlock 更适合表达外部网段或明确的地址范围。
Egress:限制 Pod 能访问哪里
默认情况下,很多集群的 Pod 可以向外发起连接。可以用 egress 限制。
例如只允许 demo-api 访问 MySQL 的 3306 端口:
1 | apiVersion: networking.k8s.io/v1 |
这条策略表达:
1 | 被选中的 demo-api Pod |
如果还需要访问 DNS,通常要额外放行 DNS 服务。否则应用可能连服务名都解析不了。
1 | Egress 全限制 |
这类问题挺常见,所以写 egress 策略时要特别注意 DNS。
策略是叠加的
NetworkPolicy 不是按顺序匹配第一条,也不是后面的覆盖前面的。
对于被选中的 Pod,允许规则是叠加的。
1 | Policy A 允许 frontend |
可以理解成“允许列表合并”。
如果一个 Pod 被多条策略选中,它的允许流量是这些策略允许流量的并集。
这意味着排查时不能只看一条 NetworkPolicy,要看所有选中了这个 Pod 的策略。
1 | kubectl get networkpolicy -n demo-prod |
NetworkPolicy 和 Service 的关系
Service 负责找到后端,NetworkPolicy 负责限制流量是否允许。
1 | Client |
如果 Service 正常、EndpointSlice 也有后端,但访问仍然失败,就需要考虑 NetworkPolicy。
1 | Service selector 正确 |
不过我不会一开始就怀疑 NetworkPolicy,还是先看 Service、EndpointSlice、Pod Ready。这些确认没问题后,再看策略更有层次。
一个更完整的边界示例
目标:
1 | frontend 可以访问 demo-api:8080 |
可以拆成:
1 | 1. 默认拒绝 ingress |
这比写一条巨大策略更容易理解和维护。
我会尽量让每条 NetworkPolicy 只表达一个清晰意图:
1 | allow-frontend-to-demo-api |
命名清楚后,排查时也能一眼知道每条策略在做什么。
小结
这一篇整理下来,我对 NetworkPolicy 的理解可以概括成几句话:
- NetworkPolicy 用来限制 Pod 的入站和出站网络流量;
- 它依赖网络插件支持,不是所有集群写了就生效;
- 没有策略时,Pod 通常不是默认隔离;
podSelector选择被策略保护的 Pod;ingress控制进入 Pod 的流量;egress控制从 Pod 发出的流量;- 可以通过 podSelector、namespaceSelector、ipBlock 描述来源或去向;
- 多条策略的允许规则会叠加;
- 限制 egress 时要特别注意 DNS;
- Service 负责寻址,NetworkPolicy 负责放行或拒绝。
下一篇准备整理 Deployment 之外的工作负载对象。到目前为止大多数例子都用 Deployment,但 Kubernetes 还有 DaemonSet、Job、CronJob、StatefulSet,分别适合不同类型的任务。
参考资料
- Network Policies:https://kubernetes.io/docs/concepts/services-networking/network-policies/
- Services:https://kubernetes.io/docs/concepts/services-networking/service/
- Labels and Selectors:https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
- Network Plugins:https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/