2. NetworkPolicy API对象精讲
NetworkPolicy 是 Kubernetes 中用于描述 Pod 组之间、以及 Pod 与外部网络之间允许通信规则的 API 对象。它本身不是“防火墙开关”,而是一份声明式的“白名单”:一旦某个 Pod 被至少一个 NetworkPolicy 的 podSelector 选中,该 Pod 就进入“被隔离”状态,只有被显式允许的流量才能通过。理解这一点,是掌握后续所有字段语义的前提。
一个 NetworkPolicy 的核心结构可以拆成四层:选谁(podSelector)、管什么方向(policyTypes)、允许谁进来(ingress)、允许谁出去(egress)。其中 ingress 和 egress 内部又各自包含 from/to 与 ports 两个维度,而 from/to 的匹配对象又由 podSelector、namespaceSelector、ipBlock 三者组合而成。下面这张图展示了这些字段之间的层级与组合关系。
podSelector:决定“谁被管”
podSelector 是 NetworkPolicy 的必填字段,它通过标签选择器决定这条策略作用于当前命名空间内的哪些 Pod。空选择器 {} 表示选中命名空间内所有 Pod。需要特别注意的是:podSelector 只在本命名空间内生效,它不能跨命名空间选 Pod。如果一条策略选中了某个 Pod,该 Pod 在对应方向上就进入隔离状态。
例如,下面这条策略选中带有 app=web 标签的 Pod,并只允许入站流量:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: web-allow-ingress
namespace: prod
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 8080
这条策略的语义是:prod 命名空间中 app=web 的 Pod 只接受来自同命名空间 app=api 的 Pod 访问 TCP 8080 端口,其他入站流量一律拒绝。注意,这里没有写 egress,且 policyTypes 只声明了 Ingress,因此该 Pod 的出站流量不受影响。
policyTypes:决定“管哪个方向”
policyTypes 是一个字符串列表,取值只能是 Ingress 或 Egress。它决定了这条策略是否对入站、出站方向施加隔离。这里有一个容易被忽略的默认规则:
- 如果策略中写了
ingress规则但没写policyTypes,Kubernetes 会自动补上Ingress。 - 如果策略中写了
egress规则但没写policyTypes,会自动补上Egress。 - 如果两者都没写,
policyTypes默认为[Ingress]。
因此,只写 egress 规则却忘记声明 policyTypes 是常见错误:此时策略会被当作只管理 Ingress,egress 规则不生效。反过来,如果 policyTypes 声明了 Egress 但 egress 字段为空数组 [],则表示拒绝所有出站流量,这是一个非常强的“默认拒绝”写法。
ingress 与 egress:白名单规则的内部结构
ingress 和 egress 都是规则数组,数组内多条规则之间是“或”关系——命中任意一条即放行。每条规则内部包含两个可选维度:
- 来源/目的匹配:ingress 用
from,egress 用to,内部可放 podSelector、namespaceSelector、ipBlock。 - 端口匹配:
ports,指定 protocol(TCP/UDP/SCTP)和 port(端口号或命名端口)。
如果一条规则只写了 from 没写 ports,表示允许来自该来源的所有端口;如果只写了 ports 没写 from,表示允许来自所有来源的这些端口。两者都省略(即空规则 {})则表示允许所有流量。
namespaceSelector 与 ipBlock:跨命名空间与外部地址
namespaceSelector 用于按标签选择命名空间,从而允许来自其他命名空间 Pod 的流量。它与 podSelector 的组合逻辑是本节最关键的考点:
- 写在同一个 from 元素内:表示“在匹配的命名空间中,再匹配对应标签的 Pod”,两者是“与”关系。
- 分写在两个 from 元素内:表示“匹配该命名空间的所有 Pod”或“匹配本命名空间内该标签的 Pod”,两者是“或”关系。
下面这个片段展示了“与”关系的写法,允许 env=staging 命名空间中 app=api 的 Pod 访问:
ingress:
- from:
- namespaceSelector:
matchLabels:
env: staging
podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 8080
ipBlock 则用于匹配 IP 网段,常用于放行集群外部地址。它由 cidr 和可选的 except 组成,except 用于在 CIDR 中排除子网段。例如 cidr: 10.0.0.0/8 配合 except: [10.10.0.0/16],表示允许 10.0.0.0/8 中除 10.10.0.0/16 以外的地址。需要留意的是,ipBlock 匹配的是数据包的源/目的 IP,对于经过 NAT 或 Service 转发的流量,实际匹配到的可能是节点 IP 或 Pod IP,具体取决于 CNI 实现。
一个完整的双向策略示例
下面这条策略同时管理入站和出站,选中 app=db 的 Pod:只允许来自 app=api 的 Pod 访问 5432 端口,且只允许该 Pod 出站访问 app=api 的 5432 端口。这是一个典型的“最小权限”数据库策略。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-policy
namespace: prod
spec:
podSelector:
matchLabels:
app: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 5432
egress:
- to:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 5432
应用后可以用 kubectl describe networkpolicy db-policy -n prod 查看策略的解析结果,确认 podSelector、policyTypes 和规则是否符合预期。如果发现某个 Pod 被意外隔离,优先检查是否有其他 NetworkPolicy 的 podSelector 也选中了它——多个策略对同一 Pod 的规则是“并集”关系,只要任意一条策略允许,流量就能通过。