K8s学习笔记(二十三) 网络策略 NetworkPolicy
K8s学习笔记(二十三) 网络策略NetworkPolicy
Kubernetes 的NetworkPolicy(网络策略) 是用于控制 Pod 之间网络访问的规则系统,相当于 K8s 集群内的 “防火墙”。它通过标签(Labels) 筛选目标 Pod,定义允许 / 拒绝的入站(Ingress)和出站(Egress)流量,解决了 “默认情况下 Pod 之间可自由通信” 的安全风险。
1 NetworkPolicy 的核心作用
默认情况下,K8s 集群中所有 Pod 之间可以自由通信(无论是否在同一 Node、同一命名空间),这在生产环境中存在安全隐患(比如数据库 Pod 不应被所有 Pod 访问)。
NetworkPolicy 的核心价值:
- 限制 Pod 的入站流量(谁能访问我);
- 限制 Pod 的出站流量(我能访问谁);
- 基于 Pod 标签、命名空间标签、IP 地址范围等精细化控制。
2 NetworkPolicy 依赖什么?
NetworkPolicy 本身是 K8s 的 API 对象(类似 Pod、Deployment),但需要 CNI 插件支持才能生效(并非所有 CNI 都支持)。
支持 NetworkPolicy 的主流 CNI:
- Calico(最常用,企业级);
- Weave Net;
- Cilium;
不支持的 CNI:Flannel(仅解决互通,无策略能力)。
因此,学习前需确保你的 K8s 集群使用了支持 NetworkPolicy 的 CNI(推荐用 Calico,前面已讲过部署方法)。
3 NetworkPolicy 的核心要素
一个完整的 NetworkPolicy 由以下关键部分组成,通过 YAML 定义:
apiVersion: networking.k8s.io/v1 # 固定版本
kind: NetworkPolicy
metadata:name: 策略名称namespace: 作用的命名空间 # 策略是命名空间级别的,只对当前命名空间的Pod生效
spec:podSelector: # 筛选“被该策略管控的Pod”(通过标签匹配)matchLabels:app: mysql # 例:管控所有带app=mysql标签的PodpolicyTypes: # 策略类型:Ingress(入站)、Egress(出站),至少指定一种- Ingress- Egressingress: # 入站规则(允许哪些流量进入被管控的Pod)- from: # 流量来源(谁能访问)- podSelector: # 来源是特定标签的PodmatchLabels:app: web- namespaceSelector: # 来源是特定标签的命名空间matchLabels:env: prod- ipBlock: # 来源是特定IP段(支持CIDR)cidr: 192.168.0.0/16except: # 排除某个子段- 192.168.1.0/24ports: # 允许访问的端口和协议- protocol: TCPport: 3306egress: # 出站规则(允许被管控的Pod访问哪些目标)- to: # 访问目标(和from语法相同)- podSelector:matchLabels:app: redisports: # 允许访问的端口和协议- protocol: TCPport: 6379
关键要素拆解:
-
podSelector:
决定 “哪些 Pod 会被该策略管控”。若为空(
{}),则管控当前命名空间下的所有 Pod。 -
policyTypes:
必须显式声明策略类型(Ingress/Egress),否则规则不生效。
-
ingress.from(流量来源):
支持三种来源:
podSelector:同一命名空间内,带特定标签的 Pod;namespaceSelector:带特定标签的命名空间(其内所有 Pod);ipBlock:IP 地址段(可用于允许集群外部 IP 访问,如公司内网)。
-
ingress.ports / egress.ports:
限制允许的协议(TCP/UDP/SCTP)和端口,若不指定,则允许所有端口。
4 常见场景与示例
通过具体场景学习,更容易理解。以下示例均假设在default命名空间操作。
场景 1:只允许 web Pod 访问 mysql Pod(入站控制)
需求:default命名空间中,带app=mysql标签的 Pod,只允许带app=web标签的 Pod 访问其 3306 端口,拒绝其他所有入站流量。
# mysql-allow-web.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:name: mysql-allow-webnamespace: default
spec:podSelector:matchLabels:app: mysql # 管控mysql PodpolicyTypes:- Ingress # 只控制入站ingress:- from:- podSelector:matchLabels:app: web # 只允许web Pod访问ports:- protocol: TCPport: 3306 # 只允许3306端口
应用策略:
kubectl apply -f mysql-allow-web.yaml
效果验证:
- 用
app=web的 Pod ping 或 telnet mysql 的 3306 端口 → 成功; - 用其他标签(如
app=test)的 Pod 访问 → 失败(超时)。
场景 2:禁止 Pod 访问外部网络(出站控制)
需求:default命名空间中,带app=backend标签的 Pod,只能访问集群内带app=db标签的 Pod,禁止访问任何外部 IP(包括集群外的公网)。
# backend-restrict-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:name: backend-restrict-egressnamespace: default
spec:podSelector:matchLabels:app: backend # 管控backend PodpolicyTypes:- Egress # 只控制出站egress:- to:- podSelector:matchLabels:app: db # 只允许访问db Pod# 不指定ports → 允许所有端口访问db
效果验证:
- backend Pod 访问 db Pod → 成功;
- backend Pod 访问公网 IP(如
ping 8.8.8.8) → 失败。
场景 3:默认拒绝所有入站流量(最小权限原则)
需求:default命名空间中,所有 Pod 默认拒绝入站流量,只允许显式配置的规则访问(生产环境推荐)。
# default-deny-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:name: default-deny-ingressnamespace: default
spec:podSelector: {} # 空选择器 → 管控所有PodpolicyTypes:- Ingress # 无任何ingress规则 → 默认拒绝所有入站
注意:此策略会阻断所有未被其他策略允许的入站流量。如需允许某些访问,需额外创建允许规则(策略会叠加生效)。
场景 4:允许访问特定命名空间的 Pod
需求:default命名空间的app=frontend Pod,允许被prod命名空间(带env=prod标签)的所有 Pod 访问 80 端口。
# frontend-allow-prod.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:name: frontend-allow-prodnamespace: default
spec:podSelector:matchLabels:app: frontendpolicyTypes:- Ingressingress:- from:- namespaceSelector:matchLabels:env: prod # 来源是带env=prod标签的命名空间ports:- protocol: TCPport: 80
前提:需先给prod命名空间打标签:
kubectl label namespace prod env=prod
5 策略的 “叠加性” 与优先级
NetworkPolicy 是叠加生效的,而非覆盖:
- 若多个策略匹配同一个 Pod,所有策略的规则会 “合并”(取并集);
- 没有策略时,默认允许所有流量;
- 一旦有策略匹配 Pod,仅允许策略中显式允许的流量,其他流量均被拒绝(“默认拒绝未允许的”)。
6 操作与验证命令
1. 常用命令
# 创建策略
kubectl apply -f policy.yaml# 查看当前命名空间的所有策略
kubectl get networkpolicy # 缩写:kubectl get netpol# 查看策略详情(包括规则)
kubectl describe netpol <策略名称># 删除策略
kubectl delete netpol <策略名称>
2. 验证策略是否生效
最直接的方式是 “测试流量是否符合预期”:
-
用
kubectl run创建测试 Pod(带特定标签):# 创建一个带app=test标签的测试Pod(用busybox,支持ping、wget) kubectl run test-pod --image=busybox:1.35 --rm -it -- sh -
在测试 Pod 中执行命令(如
ping <目标Pod IP>、wget -qO- <目标Pod IP:端口>),观察是否通断。
7 常见问题与注意事项
-
策略不生效?
- 检查 CNI 是否支持 NetworkPolicy(如 Calico 是否正常运行:
kubectl get pods -n calico-system); - 检查
podSelector标签是否匹配目标 Pod(标签错误是常见原因); - 检查
policyTypes是否包含需要的类型(如漏写 Ingress)。
- 检查 CNI 是否支持 NetworkPolicy(如 Calico 是否正常运行:
-
命名空间隔离?
NetworkPolicy 是命名空间级别的,只能管控当前命名空间的 Pod。跨命名空间的访问需通过
namespaceSelector指定来源命名空间。 -
IPBlock 的注意事项
ipBlock.cidr支持集群内外的 IP,但不建议直接使用 Pod IP(Pod 重建后 IP 会变,应优先用标签);- 集群内部的 Service ClusterIP 属于
ipBlock的范围,可通过 CIDR 允许访问。
总结
NetworkPolicy 的核心是 “基于标签的精细化流量控制”,关键是掌握:
- 用
podSelector选择被管控的 Pod; - 用
from/to定义流量的来源 / 目标(Pod、命名空间、IP); - 用
ports限制允许的端口和协议。
