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 定义:
yaml
apiVersion: networking.k8s.io/v1 # 固定版本
kind: NetworkPolicy
metadata:
name: 策略名称
namespace: 作用的命名空间 # 策略是命名空间级别的,只对当前命名空间的Pod生效
spec:
podSelector: # 筛选"被该策略管控的Pod"(通过标签匹配)
matchLabels:
app: mysql # 例:管控所有带app=mysql标签的Pod
policyTypes: # 策略类型:Ingress(入站)、Egress(出站),至少指定一种
- Ingress
- Egress
ingress: # 入站规则(允许哪些流量进入被管控的Pod)
- from: # 流量来源(谁能访问)
- podSelector: # 来源是特定标签的Pod
matchLabels:
app: web
- namespaceSelector: # 来源是特定标签的命名空间
matchLabels:
env: prod
- ipBlock: # 来源是特定IP段(支持CIDR)
cidr: 192.168.0.0/16
except: # 排除某个子段
- 192.168.1.0/24
ports: # 允许访问的端口和协议
- protocol: TCP
port: 3306
egress: # 出站规则(允许被管控的Pod访问哪些目标)
- to: # 访问目标(和from语法相同)
- podSelector:
matchLabels:
app: redis
ports: # 允许访问的端口和协议
- protocol: TCP
port: 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 端口,拒绝其他所有入站流量。
yaml
# mysql-allow-web.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mysql-allow-web
namespace: default
spec:
podSelector:
matchLabels:
app: mysql # 管控mysql Pod
policyTypes:
- Ingress # 只控制入站
ingress:
- from:
- podSelector:
matchLabels:
app: web # 只允许web Pod访问
ports:
- protocol: TCP
port: 3306 # 只允许3306端口
应用策略:
bash
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(包括集群外的公网)。
yaml
# backend-restrict-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-restrict-egress
namespace: default
spec:
podSelector:
matchLabels:
app: backend # 管控backend Pod
policyTypes:
- 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 默认拒绝入站流量,只允许显式配置的规则访问(生产环境推荐)。
yaml
# default-deny-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: default
spec:
podSelector: {} # 空选择器 → 管控所有Pod
policyTypes:
- Ingress # 无任何ingress规则 → 默认拒绝所有入站
注意:此策略会阻断所有未被其他策略允许的入站流量。如需允许某些访问,需额外创建允许规则(策略会叠加生效)。
场景 4:允许访问特定命名空间的 Pod
需求:default命名空间的app=frontend Pod,允许被prod命名空间(带env=prod标签)的所有 Pod 访问 80 端口。
yaml
# frontend-allow-prod.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-allow-prod
namespace: default
spec:
podSelector:
matchLabels:
app: frontend
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
env: prod # 来源是带env=prod标签的命名空间
ports:
- protocol: TCP
port: 80
前提 :需先给prod命名空间打标签:
bash
kubectl label namespace prod env=prod
5 策略的 "叠加性" 与优先级
NetworkPolicy 是叠加生效的,而非覆盖:
- 若多个策略匹配同一个 Pod,所有策略的规则会 "合并"(取并集);
- 没有策略时,默认允许所有流量;
- 一旦有策略匹配 Pod,仅允许策略中显式允许的流量,其他流量均被拒绝("默认拒绝未允许的")。
6 操作与验证命令
1. 常用命令
bash
# 创建策略
kubectl apply -f policy.yaml
# 查看当前命名空间的所有策略
kubectl get networkpolicy # 缩写:kubectl get netpol
# 查看策略详情(包括规则)
kubectl describe netpol <策略名称>
# 删除策略
kubectl delete netpol <策略名称>
2. 验证策略是否生效
最直接的方式是 "测试流量是否符合预期":
-
用
kubectl run创建测试 Pod(带特定标签):bash# 创建一个带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限制允许的端口和协议。