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 地址。

这种模型可以类比为一个没有任何隔断的超大开放式办公室,每个人都可以随意走到任何人的工位旁进行交谈,毫无障碍。

Namespace: kube-system
Namespace: db
Namespace: default
Pod D - CoreDNS
Pod C - Database
Pod A - Frontend
Pod B - Backend
图1:Kubernetes 默认的全互通网络模型

如上图所示,默认情况下,前端、后端、数据库甚至系统组件之间都可以自由通信。

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-nodecilium 相关的 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。它通过标签选择器(matchLabelsmatchExpressions)来匹配目标 Pod。如果为空(podSelector: {}),则表示选中该命名空间下的所有 Pod。

(2)policyTypes

这是一个数组,用于指定该策略包含哪种类型的规则。

  • Ingress:表示该策略包含处理入站流量的规则。
  • Egress:表示该策略包含处理出站流量的规则。

注意:如果省略 policyTypes,其行为会根据 ingressegress 字段是否被定义来确定。最佳实践是明确指定 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[流量拒绝];
图2:NetworkPolicy 流量处理逻辑

关键点解读:

  1. 未被选中的 Pod:如果一个 Pod 没有被任何 NetworkPolicy 的 podSelector 选中,那么它的所有流量(入站和出站)都是允许的,即维持 K8s 的默认行为。
  2. 被选中的 Pod:一旦一个 Pod 被至少一个 NetworkPolicy 选中:
    • 如果策略定义了 Ingress 规则,那么该 Pod 的所有入站流量将默认被拒绝,除非它明确匹配某条 ingress 规则。
    • 如果策略定义了 Egress 规则,那么该 Pod 的所有出站流量将默认被拒绝,除非它明确匹配某条 egress rule。
    • 如果一个策略选中了某个 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,尝试访问 backenddatabase

# 获取 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 流量

接下来,我们按需开放流量。我们的目标是:

  1. 允许 frontend 访问 backend
  2. 允许 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 规则,导致 backenddatabase 依然被 default-deny-allEgress 规则隔离)。一个常见的需求是,限制 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 不生效!” —— 排查指南

  1. 检查 CNI 插件:确认你的集群正在运行支持 NetworkPolicy 的 CNI 插件(如 Calico, Cilium)。这是最常见的问题根源。
  2. 检查标签:仔细核对 NetworkPolicy 中的 podSelectornamespaceSelector 与 Pod、Namespace 的实际标签是否完全匹配,注意拼写错误。
  3. 检查 policyTypes:确保你想要控制的流量类型(IngressEgress)已经包含在 policyTypes 字段中。
  4. 理解隔离逻辑:记住,只有被 podSelector 选中的 Pod 才会应用隔离策略。一个没有被任何策略选中的 Pod 是完全开放的。可以先用一个“全部拒绝”的策略(如场景一)来确保所有 Pod 都被选中,然后再逐一放开。
  5. 检查 DNS:如果你定义了严格的 Egress 策略,不要忘记为 DNS(UDP/TCP 53端口)放行,否则服务发现会失败。

4.4 可视化工具推荐

对于复杂的网络策略,纯粹阅读 YAML 文件会非常困难。可以考虑使用以下工具来帮助理解和调试:

  • Cilium’s Hubble UI:提供了一个非常直观的服务依赖图和网络流可视化界面。
  • Calico Cloud/Enterprise:提供可视化的策略编辑器和流量日志。

五、总结

掌握 NetworkPolicy 是将 Kubernetes 从“玩具”推向“生产级”的关键一步。通过本文的学习,我们应牢记以下核心要点:

  1. 安全基石:Kubernetes 默认网络模型是完全开放的,存在安全风险。NetworkPolicy 是实现网络微服务隔离、遵循最小权限原则的原生解决方案。
  2. 依赖 CNI:NetworkPolicy 只是规则定义,其强制执行依赖于 Calico、Cilium 等高级 CNI 网络插件的支持。
  3. 核心三要素:一个 NetworkPolicy 的核心是 podSelector (作用于谁)、ingress (谁能进来) 和 egress (能去哪里)。
  4. 隔离逻辑:其工作模式是“一旦选中,默认拒绝”。未被任何策略选中的 Pod 保持开放,而被选中的 Pod 则必须由明确的规则放行流量。
  5. 实践出真知:从一个“全部拒绝”的策略开始,然后根据应用通信需求,逐一添加精确的允许规则,是构建安全网络的最佳实践。同时,切勿忘记为 Egress 策略配置 DNS 访问权限。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐