「KUBERNETES-OBJECTS」- PersistentVolume, PersistentVolumeClaim

解决方案

PV + PVC 是我们早期最常用的方法,也是我们入门时学习使用的数据持久化方法;

持久化数据存储:Persistent Volume
PV 是集群内的资源,没有命名空间;PVC 则是命名空间内的资源;

使用步骤如下:
1)PV 非命名空间资源,因此需要集群管理员定义 PV 资源,它是对存储的抽象;
2)然后,开发者通过 PVC 资源来引用该 PV 资源,
3)最后,在 Pod 的 Volumes 中引用 PVC 资源;

注意事项:
1)如果使用 PVC 资源,则必须定义 PV 资源;
2)PVC 与 PV 是对应绑定的。如果已经有 PVC 绑定到 PV 对象,则其他 PVC 对象不能再绑定到该 PV 对象;
3)虽然 PV 不能共享,但是多个 POD 能够绑定到同个 PVC 以实现存储空间共享;

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: task-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: task-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi

---
apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
spec:
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: task-pv-claim
  containers:
    - name: task-pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: task-pv-storage
          # 以只读方式挂载
          readOnly:  true

场景:重新使用 PV(已使用且释放)

A private cloud – all for myself » How to reuse a PersistentVolume/PV in Kubernetes

如果 PV 已经使用(已被 PVC 引用),即使删除 PVC 以后,也无法再继续使用该 PV 资源;

解决方法:
1)首先,修改 PV/persistentVolumeReclaimPolicy 为 Retain 以保存数据;
2)然后,删除 PVC/POD 资源,查看 PV 状态,应为 Released 状态;
3)最后,删除 PV/claimRef 属性,此时 PV 状态应为 Avaiable 状态;

场景:将 PVC 资源绑定特定 PV 资源

kubernetes – Can a PVC be bound to a specific PV? – Stack Overflow
Using Persistent Volumes | Developer Guide | OpenShift Container Platform 3.11

通常 PVC 所使用的 PV 是按需绑定的,由调度器负责分配;

但是,我们可以配置 PVC 资源绑定到特定 PV 资源,这需要我们同时设置 pvc/volumeName 以及 pv/claimRef 属性:
1)单纯设置 PVC/volumeName 不能防止 PV 被其他 PVC“抢占”;
2)单纯设置 PV/claimRef 不能防止 PVC 被绑定到其他 PV 资源;

如下示例 YAML 配置文件:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-storage-share
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  claimRef:
    name: nfs-storage-share
    namespace: default
  nfs:
    server: "ip address of the nfs server"
    path: "/"
---
apiVersion: "v1"
kind: "PersistentVolumeClaim"
metadata:
  name: "nfs-storage-share"
  namespace: default
spec:
  accessModes:
    - "ReadWriteOnce"
  resources:
    requests:
      storage: "50Gi"
  volumeName: "nfs-storage-share"

hostPath

接下来,要掌握 Minikube 上的数据存储。部署一个有状态的应用程序,例如 MySQL 集群;

创建 hostPath 类型的 PV,并以挂载普通卷的方式将 PV 挂载到容器的文件系统内;
该案例使用 hostPath 类型的 PV,生成环境中不建议使用。应该定义 NFS 或者其他类型支持的网络卷;

分为两步:
1)管理员创建 PV 对象;
2)开发者创建 PVC 对象,以引用该 PV 资源;

1)管理员创建 PV 对象:

kind: PersistentVolume
apiVerion: v1
metadatda:
  name: hostpathpv
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/tmp/data"

# 当然,前提是这个目录是存在的;

2)开发者创建 PVC 对象,来使用空间:

# 如果要使用 PV,则要先进行 PVC 定义,声明要使用某个持久卷
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: mypvc
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resource:
    request:
      # 申请 200Mi 空间
      strage: 200Mi

kubectl create -f pvc.yaml
kubectl get pv # 来查看状态

3)在容器中使用该卷:

# ...
volume:
  - name: pvc-claim
    persistentVolumeClaim:
      claimName: mypvc

使用 PVC 申请空间:

# data.yaml
kind: PersistentVolumnClaim
apiVersion: v1
metadata:
  name: data
spec:
  accessModes:
    - ReadWriteOnce
  resource:
    requests:
      storage: 1Gi

然后创建该 PVC:kubctl create -f data.yaml
查看状态:kubectl get pv

接下来就是在 Pod 中使用该 PVC:

kind: Pod
apiVersion: v1
metadata:
  name: db
spec:
  container:
    - name: mysql
      image: mysql:5.5
      volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
      env:
        - name: MySQL_ROOT_PATH
          value: root
  volumns:
    - name: data
      persistentVolumeClaim:
        claimName: data

Access Modes

Persistent Volumes/Access Modes

参考官方文档,以获取详细的使用方法,该部分仅记录我们在实践过程中所遇到的问题;

使用方法

RWO – ReadWriteOnce
ROX – ReadOnlyMany
RWX – ReadWriteMany
RWOP – ReadWriteOncePod

accessModes 虽然是个数组,但是每次仅能使用一个值;

配置案例

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes: -------------------------------------------- # 指定 Access Mode 类型;
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 8Gi
  storageClassName: slow
  selector:
    matchLabels:
      release: "stable"
    matchExpressions:
      - {key: environment, operator: In, values: [dev]}

问题:…Multi-Attach error for volume “xxx” Volume is already used by pod(s) xxx…

Access Mode of ReadWriteOnce does not work as expected · Issue #263
kubernetes persistent volume ReadWriteOnly(RWO) does not work for nfs

accessModes 所指定的属性值,并非强制的,具体行为取决于底层存储的实现。例如,在 NFS 中,即便使用 PVC(accessModes: [ReadWriteOnce]) 资源,依旧能够在多个节点上使用该资源。但是,如果使用 Rook CephFS StorageClass 存储,则无法在多个节点中使用同个 PVC(accessModes: [ReadWriteOnce]) 资源;

AccessModes is meant to be a reflection of the provider’s, in this case EFS’s, capabilities. It is basically a label to ensure that if a user requests RWX storage via a PVC they will get a RWX PV. Or if they are want RWO storage they may get a RWO or RWX PV. It is not meant for enforcement. It is not enforced by Kubernetes, by design, and cannot be inforced by the driver.

The accessModes are dependent upon the storage provider. For NFS they don’t really do anything different, but a HostPath should use the modes correctly.

参考文献

Configure a Pod to Use a PersistentVolume for Storage | Kubernetes