K8s 存储组件 通俗精讲

形象类比

K8s集群当成一栋公寓楼

  • Pod = 住户房间(用完可销毁,数据默认随房间消失)
  • NFS = 楼下公共共享仓库(所有住户共用的外置硬盘)
  • PV = 物业提前划分好的固定储物格(实实在在的存储空间)
  • PVC = 住户写的储物申请单(只说要多大空间,不用管位置)
  • ConfigMap = 普通纸质记事本(存放明文普通配置)
  • Secret = 带锁小保险柜(存放密码、密钥等敏感数据)

总结

  • Pod 中 容器应用 产生的 数据 的 目录挂载,通常都放到 pv 类型的数据卷中
  • 配置文件 、环境变量等 的挂载处理 在k8s中 推荐 使用 ConfigMap
  • 用来保存 不方便 明文存储 的 敏感信息 例如 数据库密码、账号、Token、密钥、私钥等 通常用 Secret

一、NFS 网络共享存储(存储底层数据源)

1. 通俗解释

网络文件同步系统,可以实现多台主机在指定目录下进行 资源同步。

k8s借助NFS系统,可以实现 有状态部署 的 硬盘资源的整合管理。

跨服务器共享文件夹,所有K8s节点都能读写同一份文件,是K8s最常用的本地集群持久化存储。

2. 最佳使用场景

  1. 中小型K8s集群本地持久化数据
  2. 日志收集、静态文件共享、数据库数据挂载
  3. 多Pod共享同一份数据文件

3. 实操:搭建NFS服务(腾讯云服务器)

环境

假设 集群服务器有 5 台组成,对应的 IP 地址分别是 1.1.1.1、2.2.2.2、3.3.3.3、4.4.4.4、5.5.5.5

选集群其中一台机器当NFS服务端1.1.1.1

其余所有节点:2.2.2.2~5.5.5.5 作为客户端

3.1 服务端安装配置(1.1.1.1执行)

bash 复制代码
# 安装nfs
yum install -y nfs-utils rpcbind

# 创建共享目录
mkdir -p /data/k8s-nfs

# 配置共享权限
vim /etc/exports
# 写入内容(允许所有集群网段访问)
/data/k8s-nfs  *(rw,sync,no_root_squash,no_all_squash)

# 重启开机自启
systemctl start rpcbind && systemctl enable rpcbind
systemctl start nfs && systemctl enable nfs

# 生效配置
exportfs -r

# 查看共享目录
showmount -e localhost

3.2 所有K8s节点客户端安装(全部机器执行)

bash 复制代码
yum install -y nfs-utils
# 测试挂载连通性
showmount -e 1.1.1.1

4. NFS 增删改查(服务器层面)

  • 增:新建共享目录 + 写入exports配置
  • 查:showmount -e 服务端IP
  • 改:修改/etc/exports 执行 exportfs -r
  • 删:删除目录、清空exports配置,停止nfs服务

5. 说明

K8s 集群运行 不依赖 NFS。

NFS 只是众多存储方案里的其中一种,不是刚需。

对于 ConfigMap 和 Secret 而言数据 存储在 etcd 的,自然没有 任何影响。

对于 PV 而言,不用 nfs 类型, 替换成别的存储后端:云厂商云硬盘(腾讯云 CBS、阿里云云盘)

等 即可。

只有一种情况 必须装 NFS:

业务需要多台节点、多个 Pod 共享同一份数据文件

比如:

  • 多实例 Web 共用一份静态资源
  • 集群统一日志共享目录
  • 多 Pod 读写同一个上传文件

这种场景才需要:

  1. 一台机器搭 NFS 服务端
  2. 所有集群节点装 NFS 客户端

除此之外,一辈子不装都没事。


二、PV 持久卷(PersistentVolume)

1. 通俗解释

集群管理员提前建好的存储空间,直接绑定NFS目录,定义好大小、权限、存储类型,等着业务来申请使用。

2. 最佳场景

  1. 统一规划集群存储资源
  2. 固定大小数据库、缓存数据持久化
  3. 统一管控存储权限与读写策略

3. 完整部署步骤

3.1 编写 PV yaml nfs-pv.yaml

yaml 复制代码
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv-10g
spec:
  capacity:
    storage: 10Gi  # 分配10G空间
  accessModes:
    - ReadWriteMany # 多Pod同时读写
  nfs:
    path: /data/k8s-nfs  # NFS服务端共享目录
    server: 1.1.1.1      # NFS服务端IP
  persistentVolumeReclaimPolicy: Retain # 释放后保留数据

3.2 创建PV

bash 复制代码
kubectl apply -f nfs-pv.yaml

4. PV 全套增删改查命令

bash 复制代码
# 查所有PV
kubectl get pv

# 查看PV详细信息
kubectl describe pv nfs-pv-10g

# 修改PV(直接编辑)
kubectl edit pv nfs-pv-10g

# 删除PV
kubectl delete pv nfs-pv-10g

5. 业务案例

提前创建20G、50G大小NFS-PV,统一给MySQL、Redis业务预留存储。

6. PV 需要 运维人员 提前创建好吗?

静态 PV 必须运维提前建好,没建就用不了; 但 K8s 有 免手动建 PV 的方案

1. 先说传统模式(你之前学的 NFS+PV+PVC)

规则死规定:

  1. 运维不手动创建PV → 集群里就没有可用存储空间
  2. 开发写好PVC去申请存储
  3. 集群里找不到匹配的PV,PVC状态一直卡在 Pending
  4. 最终业务Pod挂载失败,无法启动

简单说:
静态卷模式:无提前建好的PV = PVC申请不到存储 = 用不了


2. 不用运维提前建PV的方案(生产最常用)

K8s 提供 StorageClass 存储类

作用:自动创建PV

流程彻底改变:

  1. 运维只配置一次「存储模板」(比如NFS模板、云盘模板)
  2. 运维再也不用一个个手动建PV
  3. 开发直接创建PVC
  4. K8s自动根据模板实时生成对应PV,自动绑定
  5. 直接正常使用

通俗比喻

  • 老式静态PV:管理员提前把一个个空柜子摆好(建好PV),你才能领
  • StorageClass (SC)动态卷:商场有自助存包机,你一扫码申请,机器当场变出柜子,不用管理员提前摆

两种模式对比

模式 有无SC 流程 优缺点
静态存储 不用SC 运维手动建PV → 开发建PVC绑定 运维麻烦,必须提前规划
动态存储 配置SC 运维配置SC规则 → 开发直接建PVC → 自动生成PV 按需创建,运维零工作量,生产首选

StorageClass 常用命令(增删改查)

bash 复制代码
# 查看所有存储类
kubectl get sc

# 查看详细信息
kubectl describe sc nfs-dynamic-sc

# 修改存储类
kubectl edit sc nfs-dynamic-sc

# 删除存储类
kubectl delete sc nfs-dynamic-sc

适合用 StorageClass

  1. 生产正式环境 (99%企业在用)
    业务量大、项目多,不可能让运维手动一个个建PV
  2. 微服务集群
    每个服务独立存储,按需申请5G、10G、20G自动分配
  3. CI/CD自动发布项目
    流水线部署自动创建PVC,自动生成存储
  4. 云服务器K8s集群
    腾讯云/阿里云自带云盘SC,直接用,不用搭NFS
  5. 弹性扩容业务
    临时扩容Pod,自动申请存储,用完释放

不适合用 StorageClass

  1. 极简测试单机集群
    自己学习玩一玩,数量少,手动建PV更快
  2. 需要提前规划固定大容量存储
    超大数据库提前划分好固定分区

三、PVC 持久卷声明(PersistentVolumeClaim)

1. 通俗解释

开发人员提交的存储申请单 ,只填写:我需要多大空间、读写权限,K8s自动匹配空闲PV,不用关心存储真实位置

2. 最佳场景

  1. 业务项目申请持久化存储
  2. 部署MySQL、Redis、Nginx日志持久化
  3. 开发无需接触底层NFS,只申请即可

3. 完整部署步骤

3.1 编写PVC yaml nfs-pvc.yaml

yaml 复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: app-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi # 申请10G存储

3.2 创建PVC自动绑定PV

bash 复制代码
kubectl apply -f nfs-pvc.yaml

创建后自动匹配状态为Available 的同规格PV,状态变成Bound绑定成功。

3.3 Pod挂载PVC实现数据持久化

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: data-volume
      mountPath: /usr/share/nginx/html # 容器内挂载目录
  volumes:
  - name: data-volume
    persistentVolumeClaim:
      claimName: app-pvc # 引用上面PVC

执行创建:

bash 复制代码
kubectl apply -f nginx-pod.yaml

效果:删除Pod重建,网页数据依然保留在NFS服务器里。

4. PVC 增删改查命令

bash 复制代码
# 查看所有PVC
kubectl get pvc

# 查看绑定详情
kubectl describe pvc app-pvc

# 在线修改PVC
kubectl edit pvc app-pvc

# 删除PVC
kubectl delete pvc app-pvc

5. 实战场景

部署MySQL数据库,挂载PVC持久化库文件,集群节点漂移数据不丢失。


四、ConfigMap 明文配置中心

1. 通俗解释

存放明文普通配置的文件仓库,比如端口、域名、超时时间、环境地址,所有人都能看。

2. 最佳使用场景

  1. 项目配置文件、日志级别、接口地址
  2. Nginx配置、启动参数、开发环境变量
  3. 非敏感通用配置统一管理

3. 三种创建方式 + 实操

方式1:命令行快速创建(最简单)

bash 复制代码
# 键值对创建
kubectl create configmap app-config --from-literal=env=prod,port=8080

# 从本地配置文件创建
kubectl create configmap nginx-conf --from-file=./nginx.conf

方式2:yaml标准创建 configmap.yaml

yaml 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: web-config
data:
  APP_ENV: production
  LOG_LEVEL: info
  DB_HOST: 10.0.0.10

创建:

bash 复制代码
kubectl apply -f configmap.yaml

3种挂载使用方式

  1. 注入环境变量
  2. 挂载为配置文件
  3. 启动命令引用

示例Pod引用ConfigMap:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: config-pod
spec:
  containers:
  - name: app
    image: busybox
    command: ["sleep","3600"]
    env:
    - name: ENV
      valueFrom:
        configMapKeyRef:
          name: web-config
          key: APP_ENV

这个配置文件的作用:

创建一个 Pod,里面运行一个 busybox 容器,把 ConfigMap(web-config) 里的配置项 APP_ENV,自动注入成容器内部的环境变量 ENV,容器启动后休眠 1 小时方便我们测试。

4. ConfigMap 增删改查

bash 复制代码
# 查询
kubectl get configmap
kubectl describe configmap web-config

# 修改
kubectl edit configmap web-config

# 删除
kubectl delete configmap web-config

5. 业务案例

统一管理微服务环境变量,测试/生产环境一键切换ConfigMap实现环境切换。


五、Secret 加密私密配置

1. 通俗解释

加密保险箱,专门存放账号密码、数据库密码、Token、密钥,数据默认Base64编码加密,比明文安全。

2. 最佳使用场景

  1. MySQL、Redis、MQ数据库账号密码
  2. 接口密钥、JWT令牌、登录凭证
  3. 集群内部私密授权信息

3. 实操部署

3.1 命令行创建(推荐)

bash 复制代码
# 创建数据库账号密码secret
kubectl create secret generic db-secret \
--from-literal=db_user=root \
--from-literal=db_pwd=123456
1. kubectl create secret
  • 含义:执行创建 Secret 资源
  • 作用:告诉 K8s 集群:我要创建一个「加密配置保险箱」
2. generic
  • 含义:通用型 Secret
  • 作用:最常用的Secret类型,专门存账号、密码、Token、密钥等任意敏感键值对

Secret 一共 3 种官方标准类型:

  • generic(通用型 / 万能型)→ 存任意敏感数据(账号、密码、Token、密钥)
  • tls(证书专用型)→ 存HTTPS 证书 + 私钥(网站加密用)
  • docker-registry(镜像仓库专用型)→ 存私有镜像仓库登录凭证(拉私有镜像用)
3. db-secret
  • 含义:给这个 Secret 起的名字
  • 作用:后面 Pod 要引用这个密码时,必须写这个名字
4. --from-literal
  • 含义:直接用「键=值」的字面量方式创建
  • 作用:不用写YAML文件,命令行直接明文写配置,最简单快捷
5. db_user=root
  • 键名:db_user(数据库用户名)
  • 键值:root
  • 作用:存数据库账号
6. db_pwd=123456
  • 键名:db_pwd(数据库密码)
  • 键值:123456
  • 作用:存数据库密码

3.2 yaml方式创建 secret.yaml

先加密明文:

bash 复制代码
echo -n "root" | base64 # 输出:cm9vdA==
echo -n "123456" | base64 # 输出:MTIzNDU2

写入yaml:

yaml 复制代码
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  db_user: cm9vdA==
  db_pwd: MTIzNDU2

创建:

bash 复制代码
kubectl apply -f secret.yaml

3.3 Pod引用Secret(注入密码)

yaml 复制代码
# 1. 固定API版本:Pod属于K8s核心v1版本API
apiVersion: v1

# 2. 资源类型:我要创建的是【Pod】(K8s最小运行单元)
kind: Pod

# 3. 元数据:给Pod起名字
metadata:
  name: mysql-pod  # 这个Pod的名字叫 mysql-pod

# 4. Pod规格:定义Pod里装什么、怎么运行
spec:
  containers:  # 容器列表(一个Pod里可以跑多个容器)
  - name: mysql          # 给容器起个名字:mysql
    image: mysql:5.7     # 用官方MySQL 5.7版本镜像(固定写法)
    
    # 🔥🔥🔥 核心重点:环境变量配置(密码安全核心)
    env:
    # MySQL 官方镜像强制要求必须设置这个环境变量
    # 作用:设置 MySQL 的 root 用户密码
    - name: MYSQL_ROOT_PASSWORD  
      
      # 值不从YAML写死明文,而是从【Secret】中读取
      valueFrom:
        # 明确告诉K8s:值来自 Secret 加密配置
        secretKeyRef:
          name: db-secret   # 读取哪个Secret?→ 你创建的 db-secret
          key: db_pwd       # 读Secret里的哪个键?→ db_pwd(存的是123456)

4. Secret 增删改查命令

bash 复制代码
# 查看
kubectl get secret
kubectl describe secret db-secret

# 修改
kubectl edit secret db-secret

# 删除
kubectl delete secret db-secret

5. Secret 数据安全性 的保障

Secret 真正的安全来自 K8s 集群的 4 道安全锁

安全锁 1:RBAC 权限控制(最重要)

  • 不是谁都能查看 Secret
  • 只有集群管理员、授权账号 才能 kubectl get secret
  • 普通开发、外部人员根本看不到 Secret 内容

比喻:Secret 是放在带锁保险柜 里的纸条,Base64 只是纸条上的字写歪了,锁才是安全核心

安全锁 2:命名空间隔离

  • Secret 只能在同一个 Namespace 内使用
  • 跨项目、跨环境完全隔离,无法窃取

安全锁 3:只存内存,不写硬盘

  • Pod 挂载的 Secret 不会写入节点磁盘
  • 直接放在 tmpfs(内存临时文件)中
  • Pod 删除,数据立刻消失,不留痕迹

安全锁 4:传输全程 HTTPS 加密

  • K8s 各组件之间传输 Secret,全程 TLS 加密
  • 网络传输中不可能被窃听

综上所述:

K8s 超级集群管理员,可以毫无阻碍查看、解码、获取集群内任意所有 Secret 明文敏感数据,没有任何遮挡。

  • 超级管理员拥有全局最高 RBAC 权限,不受任何权限限制
  • 可以随意执行查看、导出所有 Secret 资源
  • Secret 仅靠 Base64 编码,管理员一键就能解码成明文

6. 什么要用 Base64?

不是为了加密!是为了兼容存储

  1. Secret 可以存二进制文件(证书、图片、密钥)
  2. etcd 只能存文本,不能存二进制
  3. Base64 把二进制 → 纯文本,方便 K8s 存储传输
    就是个格式转换工具,和安全无关!

7. 生产环境真正的「高强度安全」怎么做?

如果你的业务是金融、支付等高安全要求:

  1. 开启 K8s etcd 静态加密(Secret 落盘加密存储)
  2. 搭配云厂商 KMS 密钥管理服务(腾讯云/阿里云)
  3. 严格 RBAC 权限,禁止越权查看 Secret
  4. 敏感密钥使用外部密钥管理系统,不存 K8s
相关推荐
千匠网络5 小时前
千匠网络制造行业渠道分销B2B解决方案:AI驱动,重构产业分销模式
网络·云原生·架构·制造业·b2b·电商解决方案
饭后一颗花生米5 小时前
2026年,Docker已死?Containerd、Podman与Nix的容器新战争
docker·容器·podman
DN金猿5 小时前
SpringCloudAlibaba微服务启动报错
微服务·云原生·nacos·架构·springcloud·sca
珂玥c5 小时前
k8s集群网络层碎碎念
云原生·容器·kubernetes
万里侯5 小时前
云原生安全扫描:保护容器化应用的安全
微服务·容器·k8s
easy_coder5 小时前
Kubernetes 域名解析问题排查实战:短名为什么有时能解析,有时不行
人工智能·kubernetes·云计算
米高梅狮子14 小时前
03.网络类服务实践
linux·运维·服务器·网络·kubernetes·centos·openstack
ElevenS_it18815 小时前
Zabbix+Prometheus+云监控告警统一接入实战:用Webhook+事件总线搭建多源告警归一化平台
kubernetes·zabbix·prometheus
万里侯16 小时前
GitOps实战:用Git管理基础设施
微服务·容器·k8s