NetworkPolicy 网络策略
CKA Domain 3 — Kubernetes NetworkPolicy 配置与管理(Ingress、Egress、隔离策略)
概述
NetworkPolicy 是 Kubernetes 中用于控制 Pod 级别的网络访问规则的资源。它通过标签选择器和命名空间选择器来定义哪些 Pod 可以相互通信。
重要前提:NetworkPolicy 需要 CNI 网络插件的支持(如 Calico、Cilium、Weave Net 等)。如果 CNI 不支持,NetworkPolicy 规则不会生效。
资源结构
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: my-network-policy
spec:
podSelector: # 选择策略作用的 Pod
matchLabels:
app: my-app
policyTypes: # 策略类型(Ingress / Egress)
- Ingress
- Egress
ingress: # 入站规则
- from:
- ipBlock:
cidr: 10.0.0.0/16
- namespaceSelector:
matchLabels:
project: my-project
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 80
egress: # 出站规则
- to:
- ipBlock:
cidr: 0.0.0.0/0
ports:
- protocol: TCP
port: 443
Ingress 规则配置
控制入站(进入 Pod)的流量。
允许特定命名空间的 Pod 访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-namespace
namespace: target-ns
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: source-ns # 命名空间标签
允许特定 Pod 标签访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-pod-label
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 8080
组合选择器(同时匹配命名空间和 Pod 标签)
ingress:
- from:
- namespaceSelector:
matchLabels:
name: dev
podSelector: # 同一规则内的多个选择器是 AND 关系
matchLabels:
role: frontend
Egress 规则配置
控制出站(从 Pod 出去)的流量。
允许访问特定外部 CIDR
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-external
spec:
podSelector:
matchLabels:
app: my-app
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/8
ports:
- protocol: TCP
port: 443
- protocol: TCP
port: 80
常见策略模式
1. Deny-All Ingress(拒绝所有入站)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
spec:
podSelector: {} # 匹配命名空间中的所有 Pod
policyTypes:
- Ingress
# ingress 为空列表,拒绝所有入站流量
2. Deny-All Egress(拒绝所有出站)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-egress
spec:
podSelector: {}
policyTypes:
- Egress
# egress 为空列表,拒绝所有出站流量
3. Allow-All Ingress(允许所有入站)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- {} # 空规则匹配所有来源
4. 允许特定命名空间访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-specific-ns
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
environment: production
ports:
- port: 80
5. 基于 IP 段的访问控制
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-ip-range
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 192.168.1.0/24
except: # 排除特定 IP
- 192.168.1.5/32
ports:
- protocol: TCP
port: 443
关键概念与注意事项
| 概念 | 说明 |
|---|---|
podSelector | 选择策略作用的 Pod,{} 匹配命名空间中所有 Pod |
policyTypes | 声明规则类型,即使 ingress/egress 为空也要指定 |
namespaceSelector | 按命名空间标签选择来源/目标 |
ipBlock | 按 CIDR 选择来源/目标 IP 段 |
| 规则内多个选择器 | AND 关系(必须同时匹配) |
| 规则间多个选择器 | OR 关系(匹配任意一个即可) |
测试 NetworkPolicy
# 创建一个测试 Pod
kubectl run test-pod --image=busybox --rm -it --restart=Never -- sh
# 测试连通性
wget -qO- http://target-svc:80
# 查看 NetworkPolicy
kubectl get networkpolicy
kubectl describe networkpolicy my-policy
🧪 完整操作实例:配置 NetworkPolicy 实现租户隔离
场景描述
默认拒绝所有入站流量,然后只允许带特定标签的 Pod 之间通信,模拟多租户隔离场景。
前置条件
- 集群使用支持 NetworkPolicy 的 CNI 插件(Calico、Cilium 等)
- kubectl 已配置好集群访问
操作步骤
Step 1: 创建两个命名空间并部署 Pod
# 创建两个命名空间模拟不同租户
kubectl create namespace tenant-a
kubectl create namespace tenant-b
# 预期输出:namespace/tenant-a created
# 在 tenant-a 中部署带标签的 Pod
kubectl run pod-a --image=nginx:1.25 --labels="app=web,tenant=a" -n tenant-a
# 预期输出:pod/pod-a created
# 在 tenant-b 中部署两个不同角色的 Pod
kubectl run pod-b1 --image=nginx:1.25 --labels="app=web,tenant=b" -n tenant-b
kubectl run pod-b2 --image=nginx:1.25 --labels="app=api,tenant=b" -n tenant-b
# 预期输出:pod/pod-b1 created
# 验证 Pod 状态
kubectl get pods -n tenant-a -o wide
kubectl get pods -n tenant-b -o wide
# 预期输出:所有 Pod 处于 Running 状态
Step 2: 创建 Deny-All Ingress NetworkPolicy
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: tenant-a
spec:
podSelector: {}
policyTypes:
- Ingress
EOF
# 预期输出:networkpolicy.networking.k8s.io/deny-all-ingress created
# 同样对 tenant-b 也应用拒绝策略
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: tenant-b
spec:
podSelector: {}
policyTypes:
- Ingress
EOF
# 预期输出:networkpolicy.networking.k8s.io/deny-all-ingress created
Step 3: 验证入站流量被拒绝
# 在 tenant-b 中启动测试 Pod,尝试访问 tenant-a 的 pod-a
kubectl run test-pod --image=busybox:1.28 -n tenant-b --rm -it --restart=Never -- sh
# 在测试 Pod 内执行:
wget -qO- --timeout=5 http://pod-a.tenant-a
# 预期输出:wget: download timed out(连接被拒绝)
# 退出测试容器后,检查 NetworkPolicy
kubectl get networkpolicy --all-namespaces
# NAMESPACE NAME POD-SELECTOR AGE
# tenant-a deny-all-ingress <none> 1m
# tenant-b deny-all-ingress <none> 1m
Step 4: 创建允许带特定标签 Pod 访问的策略
# 在 tenant-a 中创建策略,只允许标签为 app=web 的 Pod 访问
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-web-to-web
namespace: tenant-a
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: web
ports:
- protocol: TCP
port: 80
EOF
# 预期输出:networkpolicy.networking.k8s.io/allow-web-to-web created
Step 5: 验证带标签 Pod 可以访问
# 在 tenant-b 的 pod-b1(标签 app=web)中测试访问 tenant-a 的 pod-a(标签 app=web)
kubectl exec pod-b1 -n tenant-b -- wget -qO- --timeout=5 http://pod-a.tenant-a
# 预期输出:nginx 欢迎页面 HTML(策略放行,因为双方都有 app=web 标签)
# 在 tenant-b 的 pod-b2(标签 app=api)中测试访问 tenant-a 的 pod-a
kubectl exec pod-b2 -n tenant-b -- wget -qO- --timeout=5 http://pod-a.tenant-a
# 预期输出:wget: download timed out(策略拒绝,因为 pod-b2 标签是 app=api 而非 app=web)
Step 6: 使用临时诊断 Pod 全面测试
# 创建诊断 Pod 测试不同场景
kubectl run test-pod -n tenant-a --image=nicolaka/netshoot --rm -it --restart=Never -- sh
# 在诊断 Pod 内逐项测试:
# 测试 1:访问同命名空间的 pod-a(应成功)
curl -m 5 http://pod-a.tenant-a
# 预期输出:HTML 内容
# 测试 2:访问 tenant-b 的 pod-b1(取决于策略配置,可能被拒绝)
curl -m 5 http://pod-b1.tenant-b
# 预期输出:连接超时(如 tenant-b 未放行此 Pod)
验证结果
# 查看所有 NetworkPolicy
kubectl get networkpolicy --all-namespaces -o wide
# NAMESPACE NAME POD-SELECTOR AGE
# tenant-a deny-all-ingress <none> 5m
# tenant-a allow-web-to-web app=web 3m
# tenant-b deny-all-ingress <none> 5m
# 查看具体策略详情
kubectl describe networkpolicy allow-web-to-web -n tenant-a
# 确认 Ingress 规则中包含 podSelector: app=web
# 清理资源
kubectl delete namespace tenant-a tenant-b
考试提示
-
默认拒绝 + 白名单放行是最常见的 NetworkPolicy 模式
-
podSelector: {}匹配命名空间内所有 Pod,是全局策略的关键写法 -
空 ingress 列表 = 拒绝所有;空规则
ingress: [{}]= 允许所有 -
规则内多个选择器是 AND 关系,规则间是 OR 关系 — CKA 高频易错点
-
NetworkPolicy 是命名空间级别资源,只作用在其所属命名空间内
-
测试时优先使用
kubectl run ... -- wget而非ping(部分 CNI 可能禁 ICMP) -
如果 busybox 的 wget 不可用,改为
kubectl run ... -- curl或使用netshoot镜像 -
https://kubernetes.io/docs/concepts/services-networking/network-policies/
-
https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy/
-
https://kubernetes.io/docs/concepts/services-networking/network-policies/#networkpolicy-resource