K8S 企业容器云04 - 持久化存储

3 分钟读完

PV & PVC & StorageClass

持久化

K8S 使用 PersistentVolume(PV) 实现存储持久化

容器 volume,是将一个宿主机的目录和一个容器内目录绑定挂载;

在容器云环境内,对存储资源的持久化需求即 volume 的 “持久性” :

  • 容器使用该目录里的内容不受容器生命周期影响,不和当前宿主机绑定;

  • 当容器重启或在其他宿主机重建后,仍可通过挂载这个 volume 访问原有存储资源

实现持久化的宿主机目录

分为两个阶段

  1. Attach – nodeName

    为宿主机节点挂载远程设备(磁盘)

  2. Mount – volueme dir

    将磁盘设备格式化,并挂载到宿主机特定目录

两阶段实现机制

由独立于 kubelet 主控制循环以外的两个控制循环实现

  1. Attach 阶段

    AttachDetachController 是 kube-controller-manager 的一部分,运行在 K8S Master 节点

    负责调用具体存储资源的 API,无需在宿主机上运行

    循环检查 Pod 对应的 PV,和这个 Pod 所在宿主机之间挂载状态,进而决定是否进行 Attach/Detach 操作

  2. Mount 阶段

    独立于 kubelet 主循环的 VolumeManagerReconciler,避免影响 Pod 创建等主进程

    在容器宿主机节点运行

PV & PVC & StorageClass

概念

  • PV - 持久化存储数据卷,是一个 API 对象,用于定义一个持久化存储在宿主机上的目录

  • PVC - 声明容器所需持久化存储资源的属性要求

    (即 PVC 提供对某种持久化存储的描述,PV 则负责具体持久化存储的实现)

  • StorageClass - 以 Dynamic Provisioning 机制自动创建所需 PV 的 API 对象

PV & PVC 绑定条件

  1. PV 的 spec 字段(资源属性)匹配 PVC 需求;

  2. PV 和 PVC 的 storageClassName 一致

PersistentVolumeController 循环遍历查找满足 PVC 条件的 PV,匹配成功则绑定(将 PV 对象的名字填在 PVC 对象的 spec.volumeName 字段)

容器挂载 PV

Pod 的 volumes 字段声明所用 PVC 名称(claimName);

Pod 创建后,kubelet 将 PVC 所匹配到的 PV 挂载到该 Pod

StorageClass

定义两项内容

  1. PV 资源属性:存储类型、volume 规格等

  2. PV 对应存储插件:

K8S 根据 Pod 提交的 PVC,找到对应 StorageClass,调用 StorageClass 声明的存储插件,创建 PV

运维无需手动创建大量的 PV,只需分类创建几个 StorageClass 供 K8S 自动生成 PV

pv&pvc&storageclass 关系流程图

Local Persistent Volume

使用宿主机本地磁盘目录

  • 业务需求:高优先级的系统应用,需要在多个不同节点上存储数据,并且对 I/O 较为敏感

  • 典型场景:分布式数据存储如 MongoDB、Cassandra;分布式文件系统如 GlusterFS、Ceph 等

  • 安全要求:数据保存在本地硬盘,避免宕机造成数据丢失,需要具备数据备份和恢复能力

设计原则

  1. 本地磁盘抽象 Local PV

    使用独立于宿主机系统以外的磁盘或块设备

  2. 实现将 Pod 调度到对应 Local PV 所在宿主机

    • 常规 PV - 先在宿主机创建 Pod,根据 Pod 需求在该宿主机上创建和持久化 volume

    • Local PV - 控制器在调度 Pod 之前需要明确 volume 分布 (VolumeBindingChecker)

测试

使用宿主机挂载内存盘模拟独立磁盘设备

1- 宿主机 k02 创建 RAM Disk

# mkdir /mnt/disks

# for i in vol1 vol2 vol3; do
> mkdir /mnt/disks/$i
> mount -t tmpfs $i /mnt/disks/$i
> done

2- 定义 PV

Local PV 不支持 Dynamic Provisioning ,先手动创建 PV

‘local:’ 指定 Local PersistentVolume 类型

‘path: /mnt/disks/vol1’ 指定该 PV 对应的磁盘路径 (k02 上)

资源目录在 k02 上,通过亲和性 ‘nodeAffinity’ 过滤主机名配对

# vim local-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 2Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /mnt/disks/vol1
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - k02

# kubectl apply -f local-pv.yaml
persistentvolume/example-pv created

# kubectl get pv
NAME         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS    REASON   AGE
example-pv   2Gi        RWO            Delete           Available           local-storage            3m50s

3- 定义 StorageClass

创建名为 ‘local-storage’ 的 SC

‘provisioner’ 字段使用 no-provisioner,因为 Local PV 不支持动态创建

‘WaitForFirstConsumer’: 延迟绑定,将 PVC 和 PV 绑定推迟到 ‘调度的时候’,根据 Pod 实际需求情况更新调度规则

# vim local-sc.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

# kubectl apply -f local-sc.yaml
storageclass.storage.k8s.io/local-storage created

# kubectl get sc
NAME            PROVISIONER                    AGE
local-storage   kubernetes.io/no-provisioner   9s

4- 定义 PVC

因为 PVC 的 ‘storageClassName’ 是 local-storage

根据上面 SC 的延迟绑定设置,PVC 暂不配对 PV,进入 ‘Pending’ 状态,等待 Pod 产生时调度

# vim local-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: example-local-claim
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  storageClassName: local-storage

# kubectl apply -f local-pvc.yaml
persistentvolumeclaim/example-local-claim created

# kubectl get pvc
NAME                  STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS    AGE
example-local-claim   Pending                                      local-storage   4s

5- 定义 Pod

‘volumes’ 字段设定 PVC 为 ‘example-local-claim’

Pod 调度后, PVC 状态由 ‘Pending’ 转为 ‘Bound’,延迟绑定生效

# vim local-pod.yaml
kind: Pod
apiVersion: v1
metadata:
  name: example-pv-pod
spec:
  volumes:
    - name: example-pv-storage
      persistentVolumeClaim:
        claimName: example-local-claim
  containers:
    - name: example-pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: example-pv-storage

# kubectl get pvc
NAME                  STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS    AGE
example-local-claim   Bound    example-pv   2Gi        RWO            local-storage   18m

6- 持久化测试

在容器 volume 内创建文件

# kubectl exec -it example-pv-pod -- /bin/sh
## cd /usr/share/nginx/html
## touch myPVfile.txt

在宿主机 k02 查看内存磁盘空间

# ls /mnt/disks/vol1/
myPVfile.txt

删除、重建测试用 Pod

# kubectl delete -f local-pod.yaml
pod "example-pv-pod" deleted

# kubectl apply -f local-pod.yaml
pod/example-pv-pod created

# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
example-pv-pod   1/1     Running   0          11s

# kubectl describe pv example-pv
Name:              example-pv
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"PersistentVolume","metadata":{"annotations":{},"name":"example-pv"},"spec":{"accessModes":["ReadWriteOnce"],"ca...
                   pv.kubernetes.io/bound-by-controller: yes
Finalizers:        [kubernetes.io/pv-protection]
StorageClass:      local-storage
Status:            Bound
Claim:             default/example-local-claim
Reclaim Policy:    Delete
Access Modes:      RWO
VolumeMode:        Filesystem
Capacity:          2Gi
Node Affinity:     
  Required Terms:  
    Term 0:        kubernetes.io/hostname in [k02]
Message:           
Source:
    Type:  LocalVolume (a persistent volume backed by local storage on a node)
    Path:  /mnt/disks/vol1
Events:    <none>

文件 ‘myPVfile’ 存在,证实持久性

# kubectl exec -it example-pv-pod -- /bin/sh
# ls /usr/share/nginx/html
myPVfile.txt

使用 Static Provisioner 管理 Local PV

https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner

分类:

更新时间: