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
相关推荐
Patrick_Wilson3 分钟前
Node.js SSR 内存治理:为什么 --max-old-space-size 不等于进程内存
kubernetes·node.js·v8
开发者联盟league7 分钟前
使用k8s安装Jenkins
容器·kubernetes·jenkins
正经教主1 小时前
【docker基础】 第七课:Docker Compose 多容器实战
运维·docker·容器
正经教主1 小时前
【docker基础】Redis的docker部署
redis·docker·容器
DolphinScheduler社区1 小时前
Apache DolphinScheduler 3.4.2 正式发布!新增 Amazon EMR Serverless 插件,增强监控与补数据能力
大数据·云原生·serverless·apache·海豚调度·版本发版
成为你的宁宁1 小时前
【基于 Prometheus Operator 实现 K8s 环境下 Redis Cluster 集群监控部署】
redis·kubernetes·prometheus
是一个Bug2 小时前
Docker 与 Kubernetes:从“集装箱”到“远洋舰队”
docker·容器·kubernetes
heimeiyingwang2 小时前
【架构实战】注册中心选型:Nacos vs Eureka vs Consul
微服务·云原生·架构
java_cj2 小时前
阅读 k8s 源码的准备工作
云原生·容器·kubernetes
开发者联盟league2 小时前
使用Jenkins整合Sonarqube/Gitlab/Harbor/Kubernetes实现CICD
kubernetes·gitlab·jenkins