Kubenets 存储的分类+数据的持久化+PVC/PV+StorageClass

Kubenets 存储的分类+数据的持久化+PVC/PV+StorageClass

  1. ConfigMap

  2. Secret

  3. Downward API

  4. Volume

  5. PV/PVC

  6. StorageClass

1. ConfigMap

以注入的方式存储非机密的配置信息(例如配置文件、环境变量、命令行参数等)。Pod 可以通过环境变量或挂载为文件的方式读取 ConfigMap。

# 文件方式创建
$ kubectl create configmap xxx --from-file=xxx.file

# 命令参数方式创建
$ kubectl create configmap xxx --from-literal=name=xxx --from-literal=password=xx

# --dry-run只编写不运行, -o yaml > xxx.yaml 导出到xx.yaml保存为yaml格式
--dry-run=client
-o yaml > xxx.yaml 

# 完整命令
$ kubectl create configmap xxx --from-literal=name=xxx --from-literal=password=xxx --dry-run=client -o yaml > xxx.yaml

使用方式:

  1. 作为环境变量注入 Pod
   apiVersion: v1
   kind: ConfigMap
   metadata:
     name: app-env-bulk
   ---
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: envfrom-demo
   spec:
     replicas: 1
     selector:
       matchLabels:
         app: envfrom-demo
     template:
       metadata:
         labels:
           app: envfrom-demo
       spec:
         containers:
           - name: app
             image: busybox
             command: ["sh", "-c", "env | grep DB_"]
             envFrom:
               - configMapRef:
                   name: app-env-bulk

2.作为环境变量单个键值注入

   apiVersion: v1
   kind: ConfigMap
   metadata:
     name: app-env
   ---
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: env-demo
   spec:
     replicas: 1
     selector:
       matchLabels:
         app: env-demo
     template:
       metadata:
         labels:
           app: env-demo
       spec:
         containers:
           - name: app
             image: busybox
             command: ["sh", "-c", "env | grep LOG_LEVEL"]
             env:
               - name: LOG_LEVEL
                 valueFrom:
                   configMapKeyRef:
                     name: app-env
                     key: LOG_LEVEL
               - name: FEATURE_FLAG
                 valueFrom:
                   configMapKeyRef:
                     name: app-env
                     key: FEATURE_FLAG
  1. 以卷 (configMap volume) 的方式挂载为文件/目录

      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: app-config-files
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: volume-demo
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: volume-demo
        template:
          metadata:
            labels:
              app: volume-demo
          spec:
            containers:
              - name: app
                image: busybox
                command: ["sh", "-c", "ls /config && cat /config/application.properties"]
                volumeMounts:
                  - name: config-vol
                    mountPath: /config
                    readOnly: true
            volumes:
              - name: config-vol
                configMap:
                  name: app-config-files
    

2. Secret

存储敏感数据(如密码、证书、密钥),内容会以 Base64 编码保存。与 ConfigMap 类似,可通过环境变量或卷挂载到 Pod,并在 API Server/ETCD 中进行额外的访问控制。

# base64编码
$ echo -n "Hello World" | base64 
SGVsbG8gV29ybGQ=

# base64解码
$ echo -n "SGVsbG8gV29ybGQ=" | base64 -d

常见类型如下:

  1. Opaque:默认类型,存放任意 key/value,需要自行决定编码内容。

     apiVersion: v1
     kind: Secret
     metadata:
       name: app-secret
     type: Opaque
     stringData:
       username: admin
       password: s3cr3t
    
     or 
    
     apiVersion: v1
     kind: Secret
     metadata:
       name: app-secret
     type: Opaque
     data:
       username: base64(admin)
       password: base64(s3cr3t)
    
  2. kubernetes.io/service-account-token:ServiceAccount 自动挂载的令牌,附带 CA、namespace 等字段。

     apiVersion: v1
     kind: Secret
     metadata:
       name: default-token
       annotations:
         kubernetes.io/service-account.name: default
     type: kubernetes.io/service-account-token
    
  3. kubernetes.io/dockercfg 与 kubernetes.io/dockerconfigjson:Docker Registry 凭据,分别对应旧版 .dockercfg 和新版 .dockerconfigjson。

     apiVersion: v1
     kind: Secret
     metadata:
       name: regcred
     type: kubernetes.io/dockerconfigjson
     data:
       .dockerconfigjson: <base64-encoded-config>
    
  4. kubernetes.io/basic-auth:基于用户认证,保存用户名/密码对。

     apiVersion: v1
     kind: Secret
     metadata:
       name: basic-auth
     type: kubernetes.io/basic-auth
     stringData:
       username: user1
       password: passw0rd
    
  5. kubernetes.io/ssh-auth:存放 SSH 私钥数据。

     apiVersion: v1
     kind: Secret
     metadata:
       name: git-ssh
     type: kubernetes.io/ssh-auth
     stringData:
       ssh-privatekey: |
         -----BEGIN OPENSSH PRIVATE KEY-----
         ...
         -----END OPENSSH PRIVATE KEY-----
    
  6. kubernetes.io/tls:TLS 证书与私钥(字段固定为 tls.crt、tls.key)。

     apiVersion: v1
     kind: Secret
     metadata:
       name: tls-cert
     type: kubernetes.io/tls
     stringData:
       tls.crt: |
         -----BEGIN CERTIFICATE-----
         ...
         -----END CERTIFICATE-----
       tls.key: |
         -----BEGIN PRIVATE KEY-----
         ...
         -----END PRIVATE KEY-----
    
  7. bootstrap.kubernetes.io/token:集群 bootstrap 令牌,用于 kubeadm 加入节点。

     apiVersion: v1
     kind: Secret
     metadata:
       name: bootstrap-token-abcdef
       namespace: kube-system
     type: bootstrap.kubernetes.io/token
     stringData:
       description: "kubeadm bootstrap token"
       token-id: abcdef
       token-secret: 0123456789abcdef
    

3. Downward API

把 Pods 自身的元数据(例如 Pod 名称、命名空间、标签、注解、资源请求与限制等)暴露给容器,方式包括环境变量和挂载为文件。Downward API 不需要事先创建对象,由 kubelet 在 Pod 生命周期内自动提供。

  1. 环境变量注入 Pod 元数据(fieldRef)

     apiVersion: v1
     kind: Pod
     metadata:
       name: env-fieldref-demo
     spec:
       containers:
         - name: app
           image: busybox
           command: ["sh", "-c", "env && sleep 3600"]
           env:
             - name: POD_NAME
               valueFrom:
                 fieldRef:
                   fieldPath: metadata.name
             - name: POD_NAMESPACE
               valueFrom:
                 fieldRef:
                   fieldPath: metadata.namespace
             - name: POD_IP
               valueFrom:
                 fieldRef:
                   fieldPath: status.podIP
    
  2. 环境变量注入资源请求/限制(resourceFieldRef)

     apiVersion: v1
     kind: Pod
     metadata:
       name: env-resource-demo
     spec:
       containers:
         - name: app
           image: busybox
           resources:
             requests:
               cpu: "250m"
               memory: "128Mi"
             limits:
               cpu: "500m"
               memory: "256Mi"
           env:
             - name: CPU_LIMIT
               valueFrom:
                 resourceFieldRef:
                   containerName: app
                   resource: limits.cpu
             - name: MEM_REQUEST
               valueFrom:
                 resourceFieldRef:
                   containerName: app
                   resource: requests.memory
           command: ["sh", "-c", "echo $CPU_LIMIT $MEM_REQUEST && sleep 3600"]
    
  3. DownwardAPI 卷(以文件形式暴露元数据或资源值,可热更新)

     apiVersion: v1
     kind: Pod
     metadata:
       name: volume-downward-demo
       labels:
         app: demo
     spec:
       containers:
         - name: app
           image: busybox
           command: ["sh", "-c", "cat /etc/podinfo/* && sleep 3600"]
           volumeMounts:
             - name: podinfo
               mountPath: /etc/podinfo
               readOnly: true
       volumes:
         - name: podinfo
           downwardAPI:
             items:
               - path: "labels"
                 fieldRef:
                   fieldPath: metadata.labels
               - path: "annotations"
                 fieldRef:
                   fieldPath: metadata.annotations
               - path: "requests_cpu"
                 resourceFieldRef:
                   containerName: app
                   resource: requests.cpu
               - path: "limits_memory"
                 resourceFieldRef:
                   containerName: app
                   resource: limits.memory
    
  4. 投射卷(Projected Volume)结合 DownwardAPI 与其他来源

     apiVersion: v1
     kind: Pod
     metadata:
       name: projected-downward-demo
     spec:
       containers:
         - name: app
           image: busybox
           command: ["sh", "-c", "ls /projected && sleep 3600"]
           volumeMounts:
             - name: projected-vol
               mountPath: /projected
               readOnly: true
       volumes:
         - name: projected-vol
           projected:
             sources:
               - downwardAPI:
                   items:
                     - path: pod_name
                       fieldRef:
                         fieldPath: metadata.name
                     - path: cpu_limit
                       resourceFieldRef:
                         containerName: app
                         resource: limits.cpu
               - configMap:
                   name: app-config
               - secret:
                   name: app-secret
    

4. Volume

解决 Pod 容器「文件系统不持久、彼此隔离」的问题,让数据可以:在同一个 Pod 内共享、在容器重启后保留,甚至在不同 Pod / 节点之间持久存储。

  1. Pod 使用 emptyDir 卷(生命周期随 Pod)
    apiVersion: v1
    kind: Pod
    metadata:
     name: emptydir-pod
    spec:
     containers:
       - name: app
         image: nginx:1.27
         volumeMounts:
           - name: cache
             mountPath: /cache
     volumes:
       - name: cache
         emptyDir: {}
    
  2. Pod 使用 hostPath 卷(挂宿主机目录)

    Kubernetes 中 hostPath 的 type 主要有以下几种(不区分大小写时写法类似,但推荐用官方写法):

    • DirectoryOrCreate

      • 如果路径存在:必须是目录,否则报错。

      • 如果路径不存在:在宿主机上创建一个空目录(权限 0755,属主为 kubelet 运行用户)。

    • Directory

      • 路径必须已经存在并且是一个目录。

      • 如果不存在或不是目录:Pod 启动失败。

    • FileOrCreate

      • 如果路径存在:必须是文件,否则报错。

      • 如果路径不存在:在宿主机上创建一个空文件(权限 0644,属主为 kubelet 运行用户)。

    • File

      • 路径必须已经存在并且是一个普通文件。

      • 如果不存在或不是文件:Pod 启动失败。

    • Socket

      • 路径必须存在且是 Unix Domain Socket(如一些本地通信场景)。

      • 否则 Pod 启动失败。

    • CharDevice

      • 路径必须存在且是字符设备(如 /dev/null、串口设备等)。

      • 否则 Pod 启动失败。

    • BlockDevice

      • 路径必须存在且是块设备(如磁盘 /dev/sdb 等)。

      • 否则 Pod 启动失败。

apiVersion: v1
kind: Pod
metadata:
  name: hostpath-pod
spec:
  containers:
    - name: app
      image: nginx
      volumeMounts:
        - name: host-data
          mountPath: /data    # 挂载容器内部的路径
  volumes:
    - name: host-data
      hostPath:
        path: /var/data       # 宿主机路径
        type: DirectoryOrCreate
  1. 使用 PV + PVC 持久卷
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-example
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:                    # 演示用,生产一般用云盘/NFS/CSI
    path: /mnt/data/pv-example
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-example
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: pvc-pod
spec:
  containers:
    - name: app
      image: nginx:1.27
      volumeMounts:
        - name: data
          mountPath: /usr/share/nginx/html
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: pvc-example

5. PV/PVC+StatefulSet有状态服务

Kubernetes 的 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 负责为 Pod 提供持久化存储:

  • PV:管理员预先配置的存储资源,抽象了底层存储实现(如 NFS、iSCSI、CSI 驱动等),带有容量、访问模式、回收策略等属性。

  • PVC:应用侧对存储的请求,指定所需容量、访问模式、StorageClass 等;控制面会尝试把 PVC 绑定到满足条件的 PV,或通过 StorageClass 动态创建新的 PV。

  • Pod 使用 PVC:在 Pod 的 spec.volumes 中引用 PVC,容器通过 volumeMounts 挂载后即可读写。

  • 生命周期:删除 PVC 时,PV 根据回收策略(Retain、Delete、Recycle)决定是否保留或清除实际存储;未被绑定的 PV 处于 Available 状态,可供其它 PVC 使用。

  • 常见注意事项:确保访问模式匹配(例如 ReadWriteOnce vs ReadOnlyMany)、容量需要满足或高于 PVC 请求、StorageClass 的 allowVolumeExpansion 决定是否可扩容等。

要让 Kubernetes 的 PVC/PV 能够正常使用,需要在集群里部署与 PVC 兼容的存储插件(通常称为 CSI 驱动或传统的外部存储插件)。思路如下:

  • 确认需求:确定应用需要的访问模式(RWO/RWX/ROX)、性能和容量要求,然后挑选合适的后端存储(NFS、iSCSI、Ceph RBD/CephFS、各云厂商块存储、分布式文件系统等)。

  • 安装对应存储插件:

    • 现代集群最常用的是 CSI(Container Storage Interface)驱动。通常可通过 Helm Chart、Operator 或云厂商提供的安装脚本部署。

    • 例如:

      • NFS:可以部署 nfs-subdir-external-provisioner(Provisioner + NFS 服务已准备好)。

      • iSCSI:需要在节点上配置 iSCSI initiator,并部署提供 iSCSI Target 的 CSI(如 OpenEBS iSCSI)。

      • Ceph:常见方案是 Rook-Ceph Operator 或 ceph-csi(支持 RBD、CephFS)。

      • 云厂商块存储:AWS EBS CSI、Azure Disk CSI、GKE PD CSI 等。

PV 访问模式(Access Modes)

PV 的访问模式定义了存储卷如何被挂载和访问:

1. ReadWriteOnce (RWO)

  • 说明:卷可以被单个节点以读写方式挂载

  • 特点:同一时间只能被一个节点挂载

  • 适用场景:数据库、单实例应用

  • 限制:不支持多节点同时读写

2. ReadOnlyMany (ROX)

  • 说明:卷可以被多个节点以只读方式挂载

  • 特点:多个节点可同时读取,但不能写入

  • 适用场景:配置文件、静态资源分发

  • 限制:所有挂载都是只读的

3. ReadWriteMany (RWX)

  • 说明:卷可以被多个节点以读写方式挂载

  • 特点:支持多节点同时读写

  • 适用场景:共享存储、多实例应用

  • 限制:需要底层存储系统支持(如 NFS、GlusterFS)

4. ReadWriteOncePod (RWOP) ⭐

  • 说明:卷可以被单个 Pod 以读写方式挂载(Kubernetes v1.22+)

  • 特点:确保整个集群中只有一个 Pod 可以读写挂载

  • 适用场景:需要严格单写入者的应用

  • 优势:比 RWO 更严格,提供更好的数据一致性保证

注: 需在每个node节点安装NFS服务器.

# 更新软件软
$ apt update && apt upgrade -y

# 安装NFS服务器
$ apt install -y nfs-kernel-server

$ mkdir /nfs-share
$ chmod 666 /nfs-share
$ chown nobody /nfs-share

$ cat /etc/exports
/nfs-share *(rw,sync,no_subtree_check,no_root_squash)

# Kubernetes NFS 共享配置
# 格式:共享目录  允许访问的网段(权限选项)

# 方式1:允许所有节点访问(开发环境)
/nfs-share/k8s-pv  *(rw,sync,no_subtree_check,no_root_squash)

# 方式2:限制特定网段(生产环境推荐)
# /nfs-share/k8s-pv  10.0.0.0/8(rw,sync,no_subtree_check,no_root_squash)
# /nfs-share/k8s-pv  192.168.0.0/16(rw,sync,no_subtree_check,no_root_squash)

# 重启服务
$ systemctl restart nfs-server.service 

# 检查
$ dpkg -l | grep nfs
$ showmount -e xxx (主机ip: Ex:192.168.61.141)

--------------------------------  
node01 || node01
$ mkdir nfs-share && mkdir nfs-share/k8s-pv

# 挂载
$ mount -t nfs 192.168.61.141:/nfs-share/k8s-pv /nfs-share/k8s-pv/

# 解除挂载
$ umount /nfs-share/k8s-pv/

对于 StatefulSet,通常不直接创建 PVC,而是使用 volumeClaimTemplates,真正应用时在 StatefulSet 中定义模板即可。

PV清单文件

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-demo-retain
spec:
  capacity:
    storage: 1Gi
  accessModes: [ReadWriteMany]
  storageClassName: manual    # 存储类名
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /nfs-share/k8s-pv
    server: 192.168.61.141
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-demo-recycle
spec:
  capacity:
    storage: 1Gi
  accessModes: [ReadWriteMany]
  storageClassName: manual    # 存储类名
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /nfs-share/data
    server: 192.168.61.141
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-demo-delete
spec:
  capacity:
    storage: 1Gi
  accessModes: [ReadWriteMany]
  storageClassName: manual    # 存储类名
  persistentVolumeReclaimPolicy: Delete
  nfs:
    path: /nfs-share/tmp
    server: 192.168.61.141

svc-headless清单文件

apiVersion: v1
kind: Service
metadata:
  name: web-headless
  labels:
    app: web
spec:
  clusterIP: None # statefulSet 无头服务
  selector:
    app: web
  ports:
    - port: 80
      targetPort: http

statefulSet清单文件

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web-stateful
spec:
  serviceName: web-headless
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: nginx
          ports:
            - containerPort: 80
              name: http
          volumeMounts:
            - name: www        # 绑定的卷名称
              mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
    - metadata:
        name: www        # 绑定的卷名称
      spec:
        accessModes: [ReadWriteMany]
        storageClassName: manual    # 存储类名
        resources:
          requests:
            storage: 1Gi
总结:
  • 无状态服务:使用 ConfigMap/Secret 提供配置,数据写入外部存储(数据库、对象存储、消息队列等)。

  • 有状态服务:使用 StatefulSet + PV/PVC,或使用 Operator 管理。

  • PVC 需手动删除

6. StorageClass

StorageClass 基于云供应商提供的服务, 是 Kubernetes 中用于定义存储类型的资源对象.

主要作用
  1. 动态存储供应:自动创建 PersistentVolume(PV)

  2. 存储分类:区分不同性能和特性的存储

  3. 简化管理:无需手动创建 PV

  4. 创建StorageClass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard    # 指定 StorageClass
provisioner: kubernetes.io/aws-ebs  # 存储供应者
parameters:
  type: gp3
  fsType: ext4
reclaimPolicy: Delete  # 回收策略:Retain 或 Delete
volumeBindingMode: Immediate  # 绑定模式:Immediate 或 WaitForFirstConsumer
allowVolumeExpansion: true  # 是否允许卷扩容
  1. 在 PVC 中引用 StorageClass
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: standard  # 指定 StorageClass
  resources:
    requests:
      storage: 10Gi
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容