【Docker-Day 37】K8s 网络“防火墙”:NetworkPolicy 深度解析与实战
Langchain系列文章目录
01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来
Python系列文章目录
PyTorch系列文章目录
机器学习系列文章目录
深度学习系列文章目录
Java系列文章目录
JavaScript系列文章目录
Python系列文章目录
Go语言系列文章目录
Docker系列文章目录
01-【Docker-Day 1】告别部署噩梦:为什么说 Docker 是每个开发者的必备技能?
02-【Docker-Day 2】从零开始:手把手教你在 Windows、macOS 和 Linux 上安装 Docker
03-【Docker-Day 3】深入浅出:彻底搞懂 Docker 的三大核心基石——镜像、容器与仓库
04-【Docker-Day 4】从创建到删除:一文精通 Docker 容器核心操作命令
05-【Docker-Day 5】玩转 Docker 镜像:search, pull, tag, rmi 四大金刚命令详解
06-【Docker-Day 6】从零到一:精通 Dockerfile 核心指令 (FROM, WORKDIR, COPY, RUN)
07-【Docker-Day 7】揭秘 Dockerfile 启动指令:CMD、ENTRYPOINT、ENV、ARG 与 EXPOSE 详解
08-【Docker-Day 8】高手进阶:构建更小、更快、更安全的 Docker 镜像
09-【Docker-Day 9】实战终极指南:手把手教你将 Node.js 应用容器化
10-【Docker-Day 10】容器的“持久化”记忆:深入解析 Docker 数据卷 (Volume)
11-【Docker-Day 11】Docker 绑定挂载 (Bind Mount) 实战:本地代码如何与容器实时同步?
12-【Docker-Day 12】揭秘容器网络:深入理解 Docker Bridge 模式与端口映射
13-【Docker-Day 13】超越默认Bridge:精通Docker Host、None与自定义网络模式
14-【Docker-Day 14】Docker Compose深度解析
15-【Docker-Day 15】一键部署 WordPress!Docker Compose 实战终极指南
16-【Docker-Day 16】告别单机时代:为什么 Docker Compose 不够用,而你需要 Kubernetes?
17-【Docker-Day 17】K8s 架构全解析:深入理解 Kubernetes 的大脑 (Master) 与四肢 (Node)
18-【Docker-Day 18】告别选择困难症:一文掌握 Minikube、kind、k3d,轻松搭建你的第一个 K8s 集群
19-【Docker-Day 19】万物皆 YAML:掌握 Kubernetes 声明式 API 的艺术
20-【Docker-Day 20】揭秘 Kubernetes 的原子单位:深入理解 Pod
21-【Docker-Day 21】Pod的守护神:ReplicaSet与ReplicationController,轻松实现应用高可用
22-【K8s-Day 22】深入解析 Kubernetes Deployment:现代应用部署的基石与滚动更新的艺术
23-【K8s-Day 23】从 Pod 的“失联”到 Service 的“牵线”:深入理解 ClusterIP 核心原理
24-【Docker-Day 24】K8s网络解密:深入NodePort与LoadBalancer,让你的应用走出集群
25-【Docker-Day 25】深入理解 Kubernetes Namespace:实现多租户与环境隔离的利器
26-【Docker-Day 26】K8s实战演练:从零开始部署一个完整的前后端分离Web应用
27-【K8s-Day 27】应用的“体检医生”:深入解析 Kubernetes 健康检查探针 (Probe)
28-【Docker-Day 28】K8s 核心配置管理:解密 ConfigMap,告别硬编码!
29-【Docker-Day 29】K8s 安全第一课:揭秘敏感信息管理器 Secret
30-【Docker-Day 30】解密 K8s 的“硬盘”:深入理解 PersistentVolume (PV) 与 PersistentVolumeClaim (PVC)
31-【Docker-Day 31】告别手动创建 PV!一文搞懂 Kubernetes StorageClass 工作原理与实战
32-【K8s-Day 32】StatefulSet 深度解析:为你的数据库和有状态应用保驾护航
33-【Docker-Day 33】掌握 K8s 任务调度:DaemonSet、Job、CronJob 实战指南
34-【Docker-Day 34】Kubernetes Ingress 详解:从小白到精通的 K8s 流量路由指南
35-【Docker-Day 35】实战部署 Nginx Ingress Controller:集群流量入口的终极指南
36-【Docker-Day 36】K8s网络解密:CNI接口如何为Pod分配IP地址?
37-【Docker-Day 37】K8s 网络“防火墙”:NetworkPolicy 深度解析与实战
文章目录
摘要
在 Kubernetes 的世界里,网络是所有组件通信的命脉。然而,默认情况下,K8s 集群的网络是一个完全开放的“大平层”,任何 Pod 都可以不受限制地访问其他任何 Pod,这带来了巨大的安全隐患。本文将深入探讨 Kubernetes 的原生网络安全机制——NetworkPolicy。我们将从其为何重要讲起,逐步解析其核心概念与工作原理,并通过一系列由浅入深的实战演练,带你亲手为应用构建一个安全的“网络堡垒”。无论你是 K8s 初学者还是希望加固现有集群安全性的进阶用户,本文都将为你提供清晰的指引和可操作的最佳实践。
一、为什么需要 NetworkPolicy?K8s 的“开放式”网络模型
在深入学习如何设防之前,我们必须先理解“敌人”的样貌。Kubernetes 为了简化容器间的通信,默认采用了一种极其开放的网络模型。
1.1 开放的“大平层”:默认全互通的网络
在标准的 Kubernetes 集群中,一旦 Pod 被创建并分配了 IP 地址,它就进入了一个巨大的、扁平化的网络空间。这意味着,无论 Pod 位于哪个节点、属于哪个命名空间,它都可以直接访问到集群内任何其他 Pod 的 IP 地址。
这种模型可以类比为一个没有任何隔断的超大开放式办公室,每个人都可以随意走到任何人的工位旁进行交谈,毫无障碍。
如上图所示,默认情况下,前端、后端、数据库甚至系统组件之间都可以自由通信。
1.2 潜在的安全风险
这种“完全信任”的设计在开发和测试阶段可能很方便,但在生产环境中却隐藏着巨大的安全风险:
- 攻击横向移动(Lateral Movement):如果一个应用(如对外服务的前端
Pod A)存在漏洞被攻击者攻破,攻击者就可以利用这个 Pod 作为跳板,直接扫描和攻击内网中的其他关键服务,如Pod B(后端) 和Pod C(数据库),从而窃取敏感数据或破坏整个系统。 - 缺乏最小权限原则:网络层面没有遵循“最小权限原则”。前端应用根本不需要直接与数据库通信,但在默认模型下,这种访问是畅通无阻的。
- 合规性要求:许多行业安全标准(如 PCI DSS)要求对网络进行分段,以隔离持卡人数据环境与其他系统。默认的 K8s 网络模型无法满足这些合规性要求。
1.3 NetworkPolicy 的登场:Pod 级别的“防火墙”
为了解决上述问题,Kubernetes 引入了 NetworkPolicy 资源对象。NetworkPolicy 提供了一种以声明式方式定义 Pod 间网络流量规则的机制,它充当了 Pod 级别的虚拟“防火墙”。
通过 NetworkPolicy,我们可以精确地定义:
- 哪些 Pod 可以接收流量(Ingress)。
- 这些 Pod 可以向哪些目标发送流量(Egress)。
它将网络控制的粒度从节点级别细化到了每个 Pod,实现了所谓的微服务网络隔离(Micro-segmentation),从而将开放的“大平层”改造为一个个安全、独立的“隔间”。
二、NetworkPolicy 核心概念与工作原理
理解 NetworkPolicy 的工作方式是有效使用它的关键。它并非一个独立运行的程序,而是需要与集群的网络插件(CNI)协同工作。
2.1 前提条件:支持 NetworkPolicy 的 CNI 插件
重要:NetworkPolicy 资源本身仅仅是规则的“定义”,它并不负责“执行”。真正负责解析并执行这些规则的是集群的网络插件(CNI, Container Network Interface)。
并非所有的 CNI 插件都支持 NetworkPolicy。一些简单的覆盖网络插件(如 Flannel 的默认配置)可能不支持。你需要确保你的集群使用了支持此功能的 CNI 插件,例如:
- Calico (非常流行,以其强大的网络策略功能著称)
- Cilium (基于 eBPF,性能优越,功能丰富)
- Weave Net
- Antrea
如何检查? 你可以检查 kube-system 命名空间下运行的 DaemonSet,通常 CNI 插件会以 DaemonSet 的形式部署在每个节点上。例如,看到 calico-node 或 cilium 相关的 Pod 就意味着你的集群具备了执行网络策略的能力。
2.2 核心组成要素:YAML 字段解析
一个 NetworkPolicy 对象主要由以下几个部分构成:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector: # (1) 应用于哪些 Pod?
matchLabels:
role: db
policyTypes: # (2) 策略类型:Ingress, Egress 或两者
- Ingress
- Egress
ingress: # (3) Ingress 规则 (入站流量)
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress: # (4) Egress 规则 (出站流量)
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
(1)podSelector
此字段定义了该 NetworkPolicy 作用于哪些 Pod。它通过标签选择器(matchLabels 或 matchExpressions)来匹配目标 Pod。如果为空(podSelector: {}),则表示选中该命名空间下的所有 Pod。
(2)policyTypes
这是一个数组,用于指定该策略包含哪种类型的规则。
Ingress:表示该策略包含处理入站流量的规则。Egress:表示该策略包含处理出站流量的规则。
注意:如果省略 policyTypes,其行为会根据 ingress 和 egress 字段是否被定义来确定。最佳实践是明确指定 policyTypes。
(3)ingress
定义允许进入 podSelector 所选中 Pod 的流量规则列表。每个规则项可以指定流量来源(from)和目标端口(ports)。
from: 定义允许的流量来源,可以是以下一种或多种的组合:podSelector: 允许来自同一命名空间内匹配此标签的 Pod 的流量。namespaceSelector: 允许来自匹配此标签的其他命名空间中所有 Pod 的流量。ipBlock: 允许来自特定 IP 地址范围(CIDR)的流量,用于集群内外通信。
(4)egress
定义 podSelector 所选中 Pod 允许发出的流量规则列表。每个规则项可以指定流量目标(to)和目标端口(ports)。
to: 定义允许访问的目标,其结构与from字段完全相同。
2.3 规则匹配逻辑:隔离与放行
NetworkPolicy 的核心逻辑可以总结为“一旦选中,默认拒绝”。
graph TD
Start((开始: Pod 收到/发出流量)) --> IsPodSelected{Pod 是否被任何<br>NetworkPolicy 的<br>podSelector 选中?};
IsPodSelected -- 否 --> Allow[流量放行<br>(K8s 默认行为)];
IsPodSelected -- 是 --> CheckPolicyType{该流量类型 (Ingress/Egress)<br>是否在 policyTypes 中定义?};
CheckPolicyType -- 否 --> Allow;
CheckPolicyType -- 是 --> MatchRule{是否有任何一条<br>对应的 Ingress/Egress 规则<br>匹配该流量?};
MatchRule -- 是 --> Allow;
MatchRule -- 否 --> Deny[流量拒绝];
关键点解读:
- 未被选中的 Pod:如果一个 Pod 没有被任何 NetworkPolicy 的
podSelector选中,那么它的所有流量(入站和出站)都是允许的,即维持 K8s 的默认行为。 - 被选中的 Pod:一旦一个 Pod 被至少一个 NetworkPolicy 选中:
- 如果策略定义了
Ingress规则,那么该 Pod 的所有入站流量将默认被拒绝,除非它明确匹配某条ingress规则。 - 如果策略定义了
Egress规则,那么该 Pod 的所有出站流量将默认被拒绝,除非它明确匹配某条egressrule。 - 如果一个策略选中了某个 Pod,但
ingress字段为空(ingress: []),则意味着拒绝所有入站流量。egress同理。
- 如果策略定义了
三、实战演练:从零开始构建安全网络
纸上谈兵终觉浅,让我们通过一个三层应用的例子来实践 NetworkPolicy。
3.1 准备实验环境
首先,我们创建一个新的命名空间,并部署 frontend, backend, database 三个模拟服务。
# 1. 创建命名空间
kubectl create namespace network-policy-demo
# 2. 部署应用 (保存为 CSDN-demo.yaml)
# ---
# apiVersion: v1
# kind: Pod
# metadata:
# name: frontend
# namespace: network-policy-demo
# labels:
# app: frontend
# spec:
# containers:
# - name: nginx
# image: nginx
# ---
# apiVersion: v1
# kind: Pod
# metadata:
# name: backend
# namespace: network-policy-demo
# labels:
# app: backend
# spec:
# containers:
# - name: nginx
# image: nginx
# ---
# apiVersion: v1
# kind: Pod
# metadata:
# name: database
# namespace: network-policy-demo
# labels:
# app: database
# spec:
# containers:
# - name: nginx # 使用 nginx 模拟,易于测试连通性
# image: nginx
kubectl apply -f CSDN-demo.yaml
验证默认连通性:
进入 frontend Pod,尝试访问 backend 和 database。
# 获取 backend 和 database 的 Pod IP
BACKEND_IP=$(kubectl get pod backend -n network-policy-demo -o jsonpath='{.status.podIP}')
DATABASE_IP=$(kubectl get pod database -n network-policy-demo -o jsonpath='{.status.podIP}')
# 进入 frontend Pod
kubectl exec -it frontend -n network-policy-demo -- /bin/bash
# 在 frontend Pod 内部执行
# apt-get update && apt-get install -y curl (如果镜像不带 curl)
curl $BACKEND_IP # 应该会返回 Nginx 欢迎页 (成功)
curl $DATABASE_IP # 应该会返回 Nginx 欢迎页 (成功)
exit
结果表明,所有 Pod 之间默认是互通的。
3.2 场景一:默认隔离整个命名空间
我们的第一步是改变默认的“允许所有”策略。我们创建一个策略,选中命名空间中的所有 Pod,但不定义任何允许规则。
deny-all.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: network-policy-demo
spec:
podSelector: {} # 空选择器,选中该 namespace 下所有 Pod
policyTypes:
- Ingress
- Egress
应用该策略:
kubectl apply -f deny-all.yaml
再次验证:
kubectl exec -it frontend -n network-policy-demo -- /bin/bash
# 在 frontend Pod 内部执行
curl --connect-timeout 5 $BACKEND_IP # 将会超时 (失败)
curl --connect-timeout 5 $DATABASE_IP # 将会超时 (失败)
exit
现在,该命名空间内的所有 Pod 都被完全隔离,无法接收或发送任何流量。我们成功建立了安全基线。
3.3 场景二:允许特定 Pod 间的 Ingress 流量
接下来,我们按需开放流量。我们的目标是:
- 允许
frontend访问backend。 - 允许
backend访问database。
allow-backend-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backend-ingress
namespace: network-policy-demo
spec:
podSelector:
matchLabels:
app: backend # 此策略作用于 backend Pod
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # 只允许来自 frontend Pod 的流量
ports:
- protocol: TCP
port: 80 # 访问 backend Pod 的 80 端口
allow-database-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-database-ingress
namespace: network-policy-demo
spec:
podSelector:
matchLabels:
app: database # 此策略作用于 database Pod
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend # 只允许来自 backend Pod 的流量
ports:
- protocol: TCP
port: 80 # 访问 database Pod 的 80 端口
应用这两个策略:
kubectl apply -f allow-backend-ingress.yaml
kubectl apply -f allow-database-ingress.yaml
验证:
- 从
frontend访问backend:kubectl exec -it frontend -n network-policy-demo -- curl $BACKEND_IP # 成功! - 从
frontend访问database:kubectl exec -it frontend -n network-policy-demo -- curl --connect-timeout 5 $DATABASE_IP # 失败! (符合预期) - 从
backend访问database:kubectl exec -it backend -n network-policy-demo -- curl $DATABASE_IP # 成功!
我们已经成功实现了服务间的定向访问控制。
3.4 场景三:控制 Egress 流量
目前,虽然我们控制了入站流量,但所有 Pod 仍然可以向任何地方发起连接(因为我们的 default-deny-all 策略中包含了 Egress,但后续的策略没有定义 Egress 规则,导致 backend 和 database 依然被 default-deny-all 的 Egress 规则隔离)。一个常见的需求是,限制 backend 只能访问 database 和必要的 DNS 服务,不能访问外部网络。
我们需要修改 backend 的策略,为其添加 Egress 规则。
backend-policy-with-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-policy # 我们将 Ingress 和 Egress 合并到一个策略中
namespace: network-policy-demo
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 80
egress:
- to:
- podSelector:
matchLabels:
app: database # 1. 允许访问 database Pod
ports:
- protocol: TCP
port: 80
- to:
- namespaceSelector: {} # 2. 允许访问所有 namespace 的 DNS 服务
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
注意:允许 DNS 是至关重要的。在 Kubernetes 中,服务发现依赖于 DNS (如
backend.network-policy-demo.svc.cluster.local)。如果Egress策略阻止了对kube-dns服务的访问(通常在kube-system命名空间,端口 53),那么所有基于服务名的通信都会失败。
先删除旧策略,再应用新策略:
kubectl delete netpol allow-backend-ingress -n network-policy-demo
kubectl apply -f backend-policy-with-egress.yaml
现在 backend Pod 的出站流量被精确控制,既能访问它需要的 database,又能进行 DNS 查询,但无法访问其他任何地方。
四、高级技巧与常见问题 (FAQ)
4.1 如何允许来自不同 Namespace 的流量?
使用 namespaceSelector。例如,假设你有一个 monitoring 命名空间,里面的 Prometheus 需要抓取 network-policy-demo 命名空间中 backend Pod 的指标。
# ... spec for backend-policy ...
ingress:
- from:
# ... 其他 from 规则 ...
- namespaceSelector: # 允许来自带有特定标签的 namespace 的所有 Pod
matchLabels:
team: monitoring
你只需为 monitoring 命名空间打上 team=monitoring 的标签即可:kubectl label namespace monitoring team=monitoring。
4.2 如何允许来自集群外部的流量?
使用 ipBlock。假设你需要允许来自公司办公网(10.1.2.0/24)的流量访问 frontend Pod。
# ... spec for a policy selecting frontend ...
ingress:
- from:
- ipBlock:
cidr: 10.1.2.0/24
4.3 “我的 NetworkPolicy 不生效!” —— 排查指南
- 检查 CNI 插件:确认你的集群正在运行支持 NetworkPolicy 的 CNI 插件(如 Calico, Cilium)。这是最常见的问题根源。
- 检查标签:仔细核对 NetworkPolicy 中的
podSelector、namespaceSelector与 Pod、Namespace 的实际标签是否完全匹配,注意拼写错误。 - 检查
policyTypes:确保你想要控制的流量类型(Ingress或Egress)已经包含在policyTypes字段中。 - 理解隔离逻辑:记住,只有被
podSelector选中的 Pod 才会应用隔离策略。一个没有被任何策略选中的 Pod 是完全开放的。可以先用一个“全部拒绝”的策略(如场景一)来确保所有 Pod 都被选中,然后再逐一放开。 - 检查 DNS:如果你定义了严格的
Egress策略,不要忘记为 DNS(UDP/TCP 53端口)放行,否则服务发现会失败。
4.4 可视化工具推荐
对于复杂的网络策略,纯粹阅读 YAML 文件会非常困难。可以考虑使用以下工具来帮助理解和调试:
- Cilium’s Hubble UI:提供了一个非常直观的服务依赖图和网络流可视化界面。
- Calico Cloud/Enterprise:提供可视化的策略编辑器和流量日志。
五、总结
掌握 NetworkPolicy 是将 Kubernetes 从“玩具”推向“生产级”的关键一步。通过本文的学习,我们应牢记以下核心要点:
- 安全基石:Kubernetes 默认网络模型是完全开放的,存在安全风险。NetworkPolicy 是实现网络微服务隔离、遵循最小权限原则的原生解决方案。
- 依赖 CNI:NetworkPolicy 只是规则定义,其强制执行依赖于 Calico、Cilium 等高级 CNI 网络插件的支持。
- 核心三要素:一个 NetworkPolicy 的核心是
podSelector(作用于谁)、ingress(谁能进来) 和egress(能去哪里)。 - 隔离逻辑:其工作模式是“一旦选中,默认拒绝”。未被任何策略选中的 Pod 保持开放,而被选中的 Pod 则必须由明确的规则放行流量。
- 实践出真知:从一个“全部拒绝”的策略开始,然后根据应用通信需求,逐一添加精确的允许规则,是构建安全网络的最佳实践。同时,切勿忘记为 Egress 策略配置 DNS 访问权限。
更多推荐


所有评论(0)