持久化存储卷和声明介绍

PersistentVolume(PV)用于为用户和管理员提供如何提供和消费存储的API,PV由管理员在集群中提供的存储。它就像Node一样是集群中的一种资源。PersistentVolume 也是和存储卷一样的一种插件,但其有着自己独立的生命周期。PersistentVolumeClaim (PVC)是用户对存储的请求,类似于Pod消费Node资源,PVC消费PV资源。Pod能够请求特定的资源(CPU和内存),声明请求特定的存储大小和访问模式。PV是一个系统的资源,因此没有所属的命名空间

持久化存储卷和声明的生命周期

在K8s集群中,PV 作为存储资源存在。PVC 是对PV资源的请求和使用,也是对PV存储资源的”提取证”,而Pod通过PVC来使用PV。PV 和 PVC 之间的交互过程有着自己的生命周期,这个生命周期分为5个阶段 - 供应(Provisioning):即PV的创建,可以直接创建PV(静态方式),也可以使用StorageClass动态创建,供应是为集群提供可用的存储卷,在Kubernetes中有两种持久化存储卷的提供方式:静态或者动态 - 绑定(Binding):将PV分配给PVC - 使用(Using):Pod通过PVC使用该Volume - 释放(Releasing):Pod释放Volume并删除PVC - 回收(Reclaiming):回收PV,可以保留PV以便下次使用,也可以直接从云存储中删除

根据上述的5个阶段,存储卷的存在下面的4种状态: - Available:可用状态,处于此状态表明PV以及准备就绪了,可以被PVC使用了。 - Bound:绑定状态,表明PV已被分配给了PVC。 - Released:释放状态,表明PVC解绑PV,但还未执行回收策略。 - Failed:错误状态,表明PV发生错误。

PV 和 PVC 的使用方法在上一篇有详细介绍,但是前面的 PV 都是静态的,就是我要使用的一个 PVC 的话就必须手动去创建一个 PV,不人性化,如果我们有一个应用需要对存储的并发度要求比较高,而另外一个应用对读写速度又要求比较高,特别是对于 StatefulSet 类型的应用简单的来使用静态的 PV 就很不合适了,这种情况下我们就需要用到动态 PV,StorageClass

安装部署

nfs-client-provisioner

nfs-client-provisioner 是一个Kubernetes的简易NFS的外部provisioner,本身不提供NFS,需要现有的NFS服务器提供存储,部署方法也可以查看nfs-cilent文档,下面所用的文件都在这里,在部署nfs-cilent之前,需要先安装nfs server,安装在上一篇有

  • PV以 ${namespace}-${pvcName}-${pvName}的命名格式提供(在NFS服务器上)
  • PV回收的时候以 archieved-${namespace}-${pvcName}-${pvName} 的命名格式(在NFS服务器上)
配置 NFS 客户端
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
vim deployment.yaml

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 192.168.11.115  # 你的NFS server 地址
            - name: NFS_PATH
              value: /nfs/k8s  # 你的 nFS server 共享数据目录
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.11.115  # NFS SERVER  地址
            path: /nfs/k8s
方法二、ansible自动安装NFS-client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
cat >push-nfs.yam <<EOF
---
- hosts: k8s-node  
  remote_user: root
  tasks:
    - name: install nfs-utils
      yum: name=nfs-utils state=present
    - name: install rpcbind
      yum: name=rpcbind state=present
    - name: start rpcbind
      systemd: name=rpcbind state=started enabled=true
    - name: start nfs
      systemd: name=nfs state=started enabled=true
EOF
1
2
3
4
5
6
7
vim class.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: fuseim.pri/ifs  # 这里要与上面deployment的 PROVISIONER_NAME 名字一致

授权

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
vim rbac.yaml

kind: ServiceAccount
apiVersion: v1
metadata:
  name: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
创建资源对象
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
kubectl create -f deployment.yaml
kubectl create -f class.yaml
kubectl create -f rbac.yaml

# 查看资源状态
kubectl get po
NAME                                     READY   STATUS      RESTARTS   AGE
nfs-client-provisioner-6c6c68b75-c7ftb   1/1     Running     3          15h

kubectl get storageclass
NAME                  PROVISIONER      AGE
managed-nfs-storage   fuseim.pri/ifs   15h

测试

创建 StorageClass

创建一个案列测试动态PV,首先创建一个PVC对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
vim test-pvc.yaml

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-pvc
  annotations:
    volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"   # 利用 annotationgs 声明 StorageClass对象的标识
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi

kubectl create -f test-pvc.yaml
kubectl get pvc
NAME            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
test-pvc        Bound    pvc-50ac81f5-4bbd-11e9-8dee-000c292d6872   1Mi        RWX            managed-nfs-storage   106m

kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                   STORAGECLASS          REASON   AGE
pvc-50ac81f5-4bbd-11e9-8dee-000c292d6872   1Mi        RWX            Delete           Bound    default/test-pvc        managed-nfs-storage            107m

#可以看到自动生成了一个关联的PV对象,通过StorageClass对象自动创建的
启动测试 Pod

POD文件如下,作用就是在test-pvc的PV里touch一个SUCCESS文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
vim test-pod.yaml

kind: Pod
apiVersion: v1
metadata:
  name: test-pod
spec:
  containers:
  - name: test-pod
    image: busybox
    imagePullPolicy: IfNotPresent
    command:
    - "/bin/sh"
    args:
    - "-c"
    - "touch /mnt/SUCCESS && exit 0 || exit 1"
    volumeMounts:
    - name: nfs-pvc
      mountPath: "/mnt"
  restartPolicy: "Never"
  volumes:
  - name: nfs-pvc
    persistentVolumeClaim:
      claimName: test-pvc

# 创建 pod,一会儿pod就是completed,说明执行完毕
kubectl create -f test.pod.yaml

# 查看nfs server的共享数据目录下的数据
ls /nfs/k8s
default-test-pvc-pvc-50ac81f5-4bbd-11e9-8dee-000c292d6872

# 文件夹命名规则遵从:${namespace}-${pvcName}-${pvName},查看文件夹内容
ls /nfs/k8s/default-test-pvc-pvc-50ac81f5-4bbd-11e9-8dee-000c292d6872/
SUCCESS
创建 Statefulset

可以看到我们这里是手动创建的一个 PVC 对象,在实际工作中,使用 StorageClass 更多的是 StatefulSet 类型的服务,StatefulSet类型的服务我们也可以通过一个volumeClaimTemplates属性来直接使用 StorageClass

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
vim test-statefulset.yaml

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: nfs-web
spec:
  serviceName: "nginx"
  replicas: 2
  template:
    metadata:
      labels:
        app: nfs-web
    spec:    
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
      annotations:
        volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
    spec:
      accessModes: 
        - ReadWriteMany
      resources:
        requests:
          storage: 1Gi

# 创建
kubectl create test-statefulset.yaml

# 查看 PV PVC
 kubectl get pvc
NAME            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
www-nfs-web-0   Bound    pvc-9910023f-4bc2-11e9-8dee-000c292d6872   1Gi        RWX            managed-nfs-storage   85m
www-nfs-web-1   Bound    pvc-f9a7ff42-4bc2-11e9-8dee-000c292d6872   1Gi        RWX            managed-nfs-storage   83m

kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                   STORAGECLASS          REASON   AGE
pvc-9910023f-4bc2-11e9-8dee-000c292d6872   1Gi        RWX            Delete           Bound    default/www-nfs-web-0   managed-nfs-storage            85m
pvc-f9a7ff42-4bc2-11e9-8dee-000c292d6872   1Gi        RWX            Delete           Bound    default/www-nfs-web-1   managed-nfs-storage            83m

可以看到生成了2个PVC,平且都是绑定状态,PV也能看到对应的对象

# 查看 nfs server 共享数据目录
ls /nfs/k8s
default-www-nfs-web-0-pvc-9910023f-4bc2-11e9-8dee-000c292d6872  
default-www-nfs-web-1-pvc-f9a7ff42-4bc2-11e9-8dee-000c292d6872