200字
k8s数据持久化
2025-10-10
2025-10-11

一、K8s存储分类(修正)

K8s存储的核心分类逻辑是按生命周期与使用场景划分,而非简单"常规/特殊",更合理的分类如下:

  • 临时存储:生命周期与Pod一致,Pod删除后数据丢失

  • 持久化存储:生命周期独立于Pod,Pod删除后数据保留

  • 配置存储:用于存储配置信息或敏感数据,本质是集群资源的挂载

二、临时存储(Ephemeral Storage)

1. emptyDir

  • 作用:在Pod启动时自动创建,供Pod内所有容器共享的临时目录

  • 特点

    • 生命周期与Pod完全绑定(Pod删除/重建,数据丢失)

    • 存储位置默认由节点决定(可以是内存tmpfs或节点磁盘)

    • 无法跨Pod共享(每个Pod有独立的emptyDir,即使是Deployment的多个副本也不共享)

  • 错误修正:笔记中"通过Deployment创建4个副本,用emptyDir实现Pod之间文件共享"是错误的!副本Pod的emptyDir是相互独立的,无法跨Pod共享数据。

  • 使用场景:临时缓存、容器间数据传递(同一Pod内)、临时日志存储

  • 配置示例

 apiVersion: v1
 kind: Pod
 metadata:
   name: emptyDir-demo-pod       # Pod名称
 spec:
   containers:
   - name: app-container         # 容器1:生成临时数据
     image: busybox              # 基础镜像(轻量,适合测试)
     command: ["/bin/sh", "-c"]
     args: ["while true; do echo $(date) > /tmp/cache/date.log; sleep 10; done"] # 每10秒写时间到临时文件
     volumeMounts:
     - name: temp-data           # 关联卷名称(与下方volumes.name一致)
       mountPath: /tmp/cache     # 容器内挂载路径
 #===================================================================================================
   - name: sidecar-container     # 容器2:读取同一Pod内的临时数据(验证共享)
     image: busybox
     command: ["/bin/sh", "-c"]
     args: ["while true; do cat /tmp/cache/date.log; sleep 10; done"]    # 每10秒读取容器1写的文件
     volumeMounts:
     - name: temp-data           # 关联同一个卷,实现容器间共享
       mountPath: /tmp/cache     # 与容器1挂载路径可不同,但指向同一emptyDir
 #==================================================================================================
   volumes:                      # 定义卷
   - name: temp-data             # 卷名称
     emptyDir:
       medium: Memory            # 用内存存储(tmpfs),不指定则默认用节点磁盘

2. 其他临时卷(补充)

  • downwardAPI:将Pod自身信息(如名称、IP、标签)挂载为文件供容器读取

  • projected:将多种卷(如Secret+ConfigMap)合并挂载到同一目录

  • ephemeral:临时存储接口,可对接临时存储类(适合短期任务)

三、配置存储(Configuration Storage)

用于存储配置信息,数据来自K8s集群资源,而非底层存储介质。

1. Secret

  • 作用:存储敏感数据(密码、Token、证书等),避免明文出现在配置中

  • 特点

    • 数据会被Base64编码(注意:不是加密,敏感场景需配合加密插件)

    • Base64 编码的局限性:通过kubectl get secret my-secret -o yaml可直接看到编码后的内容

    • 属于命名空间级资源,仅同命名空间Pod可访问

  • 配置示例

 # secret-create.yaml
 apiVersion: v1
 kind: Secret
 metadata:
   name: my-secret       # Secret名称(需与Pod中secretName一致)
   namespace: default    # 命名空间(需与Pod一致)
 type: Opaque            # 通用类型(存储键值对)
 data:                   # 数据需Base64编码(注意:不是加密)
   db-username: cm9vdA==         # 原内容:root(Base64编码命令:echo -n "root" | base64)
   db-password: MTIzNDU2         # 原内容:123456
  • 使用场景:数据库密码、API密钥、TLS证书

  • 在Pod中调用secret:

     apiVersion: v1
     kind: Pod
     metadata:
       name: secret-demo-pod     # Pod名称
     spec:
       containers:
       - name: app-container
         image: busybox
         command: ["/bin/sh", "-c", "sleep 3600"]    # 让Pod持续运行,方便验证
         volumeMounts:
         - name: httpstoken          # 卷名称(与下方volumes.name一致)
           mountPath: /etc/secrets   # 容器内挂载路径
           readOnly: true            # 只读挂载(敏感数据建议加,防止容器内误修改)
       volumes:
       - name: httpstoken            # 卷名称(Pod内的“别名”)
         secret:
           secretName: my-secret     # Secret名称(需与提前创建的Secret一致)
           optional: false           # 设为false:若Secret不存在,Pod启动失败(默认值,建议保留)

    操作验证

    1. 进入容器查看 Secret 数据:kubectl exec -it secret-demo-pod -- /bin/sh

    2. 查看挂载目录下的文件(键即文件名,内容即解密后的原数据):

       ls /etc/secrets            # 输出:db-username  db-password
       cat /etc/secrets/db-password    # 输出:123456(自动解密Base64)

2. ConfigMap

  • 作用:存储非敏感配置信息(配置文件、环境变量、命令行参数等)

  • 特点

    • 数据明文存储(不适合敏感信息)

    • 支持热更新(当ConfigMap内容修改,挂载的文件会自动更新,无需重启Pod)

  • 配置示例(错误修正:configMap下直接指定name,而非列表):

 # configmap-create.yaml
 apiVersion: v1
 kind: ConfigMap
 metadata:
   name: app-config          # ConfigMap名称(需与Pod中name一致)
   namespace: default
 data:
   log-level: "info"         # 明文存储(无需编码,区别于Secret)
   app.properties: |         # 存储多行配置(用|保留换行)
     env=production
     timeout=30s
  • 使用场景:应用配置文件(如nginx.conf)、环境变量配置

     apiVersion: v1
     kind: Pod
     metadata:
       name: configmap-demo-pod      # Pod名称
     spec:
       containers:
       - name: nginx-container
         image: nginx:alpine     # 用nginx镜像验证配置挂载
         volumeMounts:
         - name: kube-proxy-config       # 卷名称(与下方volumes.name一致)
           mountPath: /etc/nginx/conf.d  # 容器内nginx配置目录
       volumes:
       - name: kube-proxy-config     # 卷名称(Pod内“别名”)
         configMap:
           name: nginx-config        # ConfigMap名称(需与提前创建的一致)
           items:                    # 可选:只挂载ConfigMap中的部分键(不写则挂载所有键)
           - key: nginx.conf         # ConfigMap中的键
             path: default.conf      # 容器内的文件名(可自定义,无需与键一致)
    • 操作验证:

      1. 进入容器查看配置:kubectl exec -it configmap-demo-pod -- /bin/sh

      2. 验证配置文件:cat /etc/nginx/conf.d/default.conf(输出提前定义的 nginx 配置)

四、持久化存储(Persistent Storage)

数据生命周期独立于Pod,核心通过PV(PersistentVolume)PVC(PersistentVolumeClaim) 实现"存储资源与使用分离"。

1. HostPath(节点本地存储)

  • 作用:将Pod所在节点的本地目录挂载到Pod内

  • 错误修正

    • 归类错误:HostPath不属于"永久卷",而是节点级本地存储,本质是临时存储的特殊形式(依赖节点生命周期)

  • 配置示例

    在节点上创建目录(关键前提)
    • 操作节点:登录 Pod 会调度到的节点(若用多节点集群,需确保目标节点有此目录)

       # 在节点上执行(非kubectl命令)
       mkdir -p /opt/t0814        # 创建目录(需与Pod中hostPath.path一致)
       chmod 777 /opt/t0814        # 赋予读写权限(避免容器内权限不足)
     apiVersion: v1
     kind: Pod
     metadata:
       name: hostpath-demo-pod       # Pod名称
     spec:
       nodeName: worker-1            # 可选:指定调度到的节点(确保该节点有/opt/t0814目录)
       containers:
       - name: app-container
         image: busybox
         command: ["/bin/sh", "-c", "echo 'hostPath test' > /etc/nginx/test.txt && sleep 3600"]  # 写文件到挂载目录
         volumeMounts:
         - name: local-data          # 卷名称(与下方volumes.name一致)
           mountPath: /etc/nginx     # 容器内挂载路径
       volumes:
       - name: local-data            # 卷名称
         hostPath:
           path: /opt/t0814          # 节点上的目录(需提前创建,与步骤1一致)
           type: Directory           # 校验节点上是目录(不存在则Pod启动失败)
    • 操作验证:

      1. 登录节点查看文件(验证数据持久化):cat /opt/t0814/test.txt(输出:hostPath test)

      2. 删除 Pod 后,节点目录数据仍存在:kubectl delete pod hostpath-demo-pod

  • 注意事项

    • 仅用于开发/测试(生产环境禁用),因为:

      • 数据依赖节点,Pod调度到其他节点时无法访问原数据

      • 不同节点的hostPath目录内容可能不一致

    • 需确保节点上的目录存在且权限正确(否则Pod会启动失败)

  • 补充:type 类型

    • 不指定 type(默认):不校验路径类型和是否存在(路径可能不存在,或类型不符合预期,Pod 可能启动失败或运行异常)

    • Directory:必须是已存在的目录(若不存在,Pod 启动失败)

    • DirectoryOrCreate:若路径不存在,则自动创建为目录(权限默认 0755,属主 root);若已存在,必须是目录

    • File:必须是已存在的文件(若不存在或为目录,Pod 启动失败)

    • FileOrCreate:若路径不存在,则自动创建为空文件(权限默认 0644,属主 root);若已存在,必须是文件

    • Socket:必须是已存在的 Unix 套接字文件(如 /var/run/docker.sock

    • CharDevice:必须是已存在的字符设备文件(如 /dev/ttyS0

    • BlockDevice:必须是已存在的块设备文件(如 /dev/sda1

2. PV(PersistentVolume,持久卷)

  • 定义:集群级资源,由管理员创建,代表底层实际存储资源(如NFS目录、CEPH存储池、云厂商磁盘等)

  • 核心属性

    • 容量(capacity):存储大小(如100Gi)

    • 访问模式(accessModes):

      • ReadWriteOnce(RWO):仅单节点可读写

      • ReadOnlyMany(ROX):多节点可读

      • ReadWriteMany(RWX):多节点可读写(需存储支持,如NFS/CEPH)

      • ReadWriteOncePod(RWOP):仅单Pod读写

    • 存储类(storageClassName):用于动态绑定(需配合StorageClass)

    • 回收策略(reclaimPolicy):

      • Retain:PVC删除后,PV保留数据(手动清理)

      • Delete:PVC删除后,PV自动删除(适合云存储)

      • Recycle:已废弃(用Delete替代)

    • 生命周期:

      1. 可用(available):PV已创建

      2. 绑定(bound):PV与PVC 捆绑

      3. 释放(release):PVC被删除

      4. 回收(reclaim):等待被处理

  • 配置示例(NFS作为PV后端)

    前提:准备 NFS 服务器(示例用 NFS 作为 PV 后端)

    1. 安装 NFS 服务器(以 CentOS 为例):yum install -y nfs-utils

    2. 创建 NFS 共享目录:mkdir -p /nfs/data && chmod 777 /nfs/data

    3. 配置 NFS 共享:echo "/nfs/data 192.168.1.0/24(rw,sync,no_root_squash)" >> /etc/exports

    4. 启动 NFS 服务:systemctl start nfs-server && systemctl enable nfs-server

 # pv-create.yaml
 apiVersion: v1
 kind: PersistentVolume
 metadata:
   name: nfs-pv          # PV名称(集群内唯一)
 spec:
   capacity:
     storage: 100Gi      # PV容量(需大于等于PVC申请的容量)
   accessModes:
     - ReadWriteMany     # 访问模式(多节点可读写,需NFS支持)
   nfs:
     path: /nfs/data     # NFS服务器共享目录(与前提步骤2一致)
     server: 192.168.1.100   # NFS服务器IP(替换为你的NFS服务器IP)
   storageClassName: ""  # 不指定存储类(静态绑定,PVC需匹配)
   reclaimPolicy: Retain # 回收策略:PVC删除后,PV保留数据(手动清理)
  • 部署 PV:kubectl apply -f pv-create.yaml

  • 验证 PV:kubectl get pv nfs-pv(状态为Available,表示可被 PVC 绑定)

3. PVC(PersistentVolumeClaim,持久卷声明)

  • 定义:命名空间级资源,由用户创建,用于"申请"PV资源(类似"存储订单")

  • 核心逻辑:PVC根据容量、访问模式、存储类等条件,自动绑定匹配的PV(静态绑定),或通过StorageClass动态创建PV(动态绑定)

  • 配置示例

 # pvc-create.yaml
 apiVersion: v1
 kind: PersistentVolumeClaim
 metadata:
   name: app-pvc         # PVC名称(命名空间内唯一)
   namespace: default    # 命名空间(需与Pod一致)
 spec:
   accessModes:
     - ReadWriteMany     # 访问模式(需与PV完全匹配)
   resources:
     requests:
       storage: 50Gi     # 申请容量(需小于等于PV容量100Gi)
   storageClassName: ""  # 存储类(需与PV一致,空表示匹配无存储类的PV)
  • 部署 PVC:kubectl apply -f pvc-create.yaml

  • 验证 PVC:kubectl get pvc app-pvc(状态为Bound,表示已与 PV 绑定)

在 Pod 中调用 PVC(完整 Pod YAML)
 # pod-with-pvc.yaml
 apiVersion: v1
 kind: Pod
 metadata:
   name: pvc-demo-pod        # Pod名称
 spec:
   containers:
   - name: app-container
     image: busybox
     command: ["/bin/sh", "-c", "echo 'PV/PVC test' > /data/test.txt && sleep 3600"] # 写文件到PVC挂载目录
     volumeMounts:
     - name: app-storage     # 卷名称(与下方volumes.name一致)
       mountPath: /data      # 容器内挂载路径
   volumes:
   - name: app-storage       # 卷名称
     persistentVolumeClaim:
       claimName: app-pvc    # PVC名称(需与步骤2创建的PVC一致)
  • 操作验证:

    1. 查看 NFS 共享目录(验证数据持久化):cat /nfs/data/test.txt(输出:PV/PVC test)

    2. 删除 Pod 后数据仍存在:kubectl delete pod pvc-demo-pod

    3. 删除 PVC 后,PV 状态变为Released(数据保留,需手动清理后可重新绑定):kubectl delete pvc app-pvc

PV和PVC和StorageClass的关系

PV创建有静态(手动创建)和动态(自动创建),这个动态的就是storageclass。

五、常规网络存储(补充)

这类存储通常作为PV的后端,提供持久化、可共享的存储能力:

  • NFS:网络文件系统,支持多节点读写(RWX),适合中小规模集群

  • CEPH:分布式存储系统,支持块存储(RBD)、文件系统(CephFS),适合大规模集群

  • 云厂商存储:如AWS EBS、阿里云OSS、Google Persistent Disk,与云平台深度集成

  • SCSI/iSCSI:块存储协议,通常用于高性能本地存储或SAN存储

除了作为 PV 后端,NFS 也可直接在 Pod 中挂载(无需 PV/PVC,适合简单场景):

 apiVersion: v1
 kind: Pod
 metadata:
   name: nfs-direct-pod
 spec:
   containers:
   - name: app
     image: busybox
     command: ["/bin/sh", "-c", "sleep 3600"]
     volumeMounts:
     - name: nfs-volume
       mountPath: /mnt/nfs
   volumes:
   - name: nfs-volume
     nfs:
       server: 192.168.1.100     # NFS服务器IP
       path: /nfs/data           # NFS共享目录

常见排错

在实际使用中,存储配置失败是新手高频问题,补充 3 个典型场景的排错步骤:

问题现象

可能原因

排错命令

Pod 一直 Pending,事件提示 “no persistent volumes available”

1. 无匹配的 PV(容量 / 访问模式 / 存储类不匹配)2. 动态 StorageClass 未部署或 Provisioner 故障

1. kubectl describe pvc PVC名称(查看绑定事件)2. kubectl get sc(检查 StorageClass 状态)

Pod 启动失败,事件提示 “permission denied”

1. HostPath/NFS 目录权限不足(未设 777)2. SELinux 限制

1. 登录节点执行ls -ld /opt/t0814(检查目录权限)2. 临时关闭 SELinux:setenforce 0(测试是否为 SELinux 问题)

ConfigMap 修改后,容器内配置未更新

1. 未等待同步(需 1 分钟内)2. 应用未监听文件变化

1. kubectl exec -it Pod名称 -- cat /etc/nginx/conf.d/default.conf(查看文件是否同步)2. 重启 Pod:kubectl rollout restart pod Pod名称

评论