云原生之Kubernetes:12、PV、PVC和SC的作用

文章目录

  • 前言
  • 一、Volume定义
  • 二、Volume分类
  • 三、PV和PVC的生命周期
  • 四、PV的回收策略
  • 五、PV的申明类型
  • 六、pv、pvc和sc的关系
  • 七、查询命令
  • 八、实战:基于nfs的静态pv/pvc
  • 九、实战:基于nfs的动态Provisioner

前言

在Kubernetes中,因为deployment默认使用的是hostpath,当我们pod重启或删除pod后数据会丢失。这时候我们就需要一个持久化存储来解决这个问题。 本次介绍的是kubernetes pv与pvc,同时使用nfs作为后端存储进行演示。

一、Volume定义

在容器的生命周期里,位于磁盘上的文件,它的生命周期是很短暂的,docker里面如此,kubernetes里亦然。
数据很可能因为各种不可抗因素丢失,比如pod被迫下线时,它会根据rs控制器的数量定义,重新生成一个干净状态的新pod。
Volume的引入不但解决里数据稳定性的问题,也解决了同一个pod内,多个containers数据共享的需求;

和docker里不同的是:
1)kubernetes中内置封装了很多存储类型,pod也可以选择性的使用一个或多个。
2)当pod被删除时,Volume才可能会被清理,并且数据是否丢失和删除取决于Volume的具体类型和其回收策略

二、Volume分类

kubernetes内置封装了很多存储类型,大致可分为以下七大部分:

我已经整理好了官方配置文档,大家可以直接按需阅读,如何使用和配置。

存储类型 存储组件 官网文档
云存储 awsElasticBlockStore awsElasticBlockStore
云存储 azureDisk azureDisk
云存储 azureFile azureFile
云存储 gcePersistentDisk gcePersistentDisk
云存储 vsphereVolume vsphereVolume
分布式存储 cephfs cephfs
分布式存储 glusterfs glusterfs
分布式存储 rbd rbd
网络存储 nfs nfs
网络存储 fc fc
网络存储 iscsi iscsi
临时存储 emptyDir emptyDir
本地存储 hostPath hostPath
特殊存储 configMap configMap
特殊存储 downwardAPI downwardAPI
特殊存储 secret secret
自定义存储 csi csi
持久卷申请 persistentVolumeClaim persistentVolumeClaim

三、PV和PVC的生命周期

1、资源供应 (Provisioning)

Kubernetes支持两种资源的供应模式:静态模式(Staic)和动态模式(Dynamic)。资源供应的结果就是创建好的PV。

静态模式:集群管理员手工创建许多PV,在定义PV时需要将后端存储的特性进行设置
动态模式:集群管理员无须手工创建PV,而是通过StorageClass的设置对后端存储进行描述,标记为某种 “类型(Class)”。此时要求PVC对存储的类型进行声明,系统将自动完成PV的创建及PVC的绑定。PVC可以声明Class为"",说明该PVC禁止使用动态模式

2、资源绑定 (Binding)

在用户定义好PVC后,系统将根据PVC对存储资源的请求 (存储空间和访问模式)在已存在的PV中选择一个满足PVC要求的PV,一旦找到,就将该PV与用户定义的PVC进行绑定,然后用户的应用就可以使用这个PVC了。如果系统中没有满足PVC要求的PV,PVC则会无限期处于Pending状态,直到等到系统管理员创建了一个符合要求的PV。PV一旦绑定在某个PVC上,就被这个PVC独占,不能再与其他PVC进行绑定了。在这种情况下,当PVC申请的存储空间比PV的少时,整个PV的空间都能够为PVC所用,可能会造成资源的浪费。如果资源供应使用的是动态模式,则系统在PVC找到合适的StorageClass后,将会自动创建PV并完成PVC的绑定

3、资源使用 (Using)

Pod 使用volume的定义,将PVC挂载到容器内的某个路径进行使用。volume的类型为persistentVoulumeClaim,在容器应用挂载了一个PVC后,就能被持续独占使用。不过,多个Pod可以挂载同一个PVC,应用程序需要考虑多个实例共同访问一块存储空间的问题

4、资源释放 (Releasing)

当用户对存储资源使用哪个完毕后,用户可以删除PVC,与该PVC绑定的PV将会被标记为已释放,但还不能立刻与其他PVC进行绑定。通过之前PVC写入的数据可能还留在存储设备上,只有在清除之后该PV才能继续使用

四、PV的回收策略

当pod资源被删除时,其相关pv和数据如何操作?该删除还是保留呢?
kubernetes通过persistentVolumeReclaimPolicy字段进行设置:

Delete: 数据和pv都会删除
Recyle: (已废弃)
Retain: 数据和pv都不动

五、PV的申明类型

PV的申明类型可分为以下两种:

Static(静态):

管理员根据使用情况,人为预先进行配置

Dynamic(动态):

基于已创建的StorageClasses(简称SC)存储类,起到动态申请和创建的作用
API server需要增加一个参数配置:–enable-admission-plugins,具体类型参考:storage-classes

六、pv、pvc和sc的关系

定义:

PVC:描述使用者(Pod)想要使用的持久化属性,比如存储大小、读写权限等
PV:描述一个具体的Volume属性,比如Volume的类型、挂载目录、远程存储服务器地址等
SC:运维人员根据pv特征,可能是性能、质量级别、备份策略等进行定义的抽象存储类,通过接收pvc请求,从而启到动态实例化pv的效果

你可能还有一点茫然,我来举个例子:

PVC:好比接口,使用者只需要知道这个接口如何使用即可,比如该传哪些参数,哪些是必传的等等,他并不需要了解接口是如何实现的
PV:就是这些接口的实现,内部是用nfs,还是ceph的存储系统等等
SC:则是这些接口根据一系列规则所进行的抽象类,通过接收pvc请求,从而启到动态实例化pv的效果

另外,还有2点是非常重要的:

1、pv没有namespace名称空间概念,而pvc有namespace名称空间的概念
2、pv和pvc一一对应绑定

七、查询命令

#pv的API字段配置说明
[root@centos-1 mainfasts]# kubectl explain pods.spec.volumes
KIND:     Pod
VERSION:  v1
RESOURCE: volumes <[]Object>

#pvc的API字段配置说明      
[root@centos-1 dingqishi]# kubectl explain pods.spec.volumes.persistentVolumeClaim
KIND:     Pod
VERSION:  v1
RESOURCE: persistentVolumeClaim <Object>

#sc的API字段配置说明 
[root@k8s-etcd-mater01 fault-injection]# kubectl explain sc
KIND:     StorageClass
VERSION:  storage.k8s.io/v1

八、实战:基于nfs的静态pv/pvc

首先你要先准备好nfs的挂载配置,我这里的配置如下所示:

角色 ip 备注
server 192.168.0.11 共享目录:/home/nfstestdir
client 192.168.0.12 挂载点:/mnt

1、首先编辑pv.yaml的配置文件,正确填写nfs服务端的配置信息,并使用apply -f命令生成

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 100Mi
  accessModes:
    - ReadWriteMany
  nfs:
    # FIXME: use the right IP
    server: 192.168.0.11
    path: "/home/nfstestdir"

注意:pv是没有名称空间概念的。

2、编辑pvc.yaml,需要指定刚才创建的pv的名字,并apply -f生成

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
  namespace: pv-test 
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 90Mi

3、此时你可以通过以下命令查看到pv和pvc的状态了,此时pv和pvc的绑定已经完成了

[root@k8s-etcd-mater01 aaron]# kubectl get pvc -n pv-test
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc   Bound    nfs-pv   100Mi      RWX                           17s

[root@k8s-etcd-mater01 aaron]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
nfs-pv   100Mi      RWX            Retain           Bound    pv-test/nfs-pvc                           53s

4、接下来我们要部署一个pod,让他使用pvc资源

apiVersion: v1
kind: Pod
metadata:
  name: nginx-volume-pvc
  namespace: pv-test
spec:
  containers:
  - name: nginx-pvc
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - name: html-pvc         #自定义名的引用
      mountPath: /usr/share/nginx/html/
  volumes:               #这里是选择volume的类型
  - name: html-pvc           #自定义名
    persistentVolumeClaim:
      claimName: nfs-pvc     #我们刚才定义的pvc名 

注意:pvc是有名称空间的,需要使用pvc的话,需要和pvc在同一个名称空间里!

5、此时pvc的状态已经是Bound了,

[root@k8s-etcd-mater01 aaron]# kubectl get pod -n pv-test
NAME               READY   STATUS    RESTARTS   AGE
nginx-volume-pvc   1/1     Running   0          7m1s

[root@k8s-etcd-mater01 aaron]# kubectl get pvc -n pv-test
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc   Bound    nfs-pv   100Mi      RWX                           21m

[root@k8s-etcd-mater01 aaron]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
nfs-pv   100Mi      RWX            Retain           Bound    pv-test/nfs-pvc                           22m

九、实战:基于nfs的动态Provisioner

上面我们使用了基于nfs静态配置的方法,来给pod资源提供存储容量,这个方式的缺点显而易见。
需要我们作为管理员,预先配置好存储容量:要几个pv,并且容量多少!

这种协作方式一般不太可取,后面我将以NFS Provisioner为例,来讲述动态供给的例子。
1、NFS Provisioner介绍

NFS Provisioner是一个自动配置卷程序,它使用现有的和已配置的 NFS 服务器来支持通过持久卷声明动态配置Kubernetes持久卷。
你可以在Github-NFS Provisioner上找到他的项目。

2、NFS环境准备

这里我就沿用上面的环境了,不再另行配置

角色 ip 备注
server 192.168.0.11 共享目录:/home/nfstestdir
client 192.168.0.12 挂载点:/mnt

3、部署方式

NFS Provisioner的部署方式可以分为两种:
helm和手工的方式。

  1. helm的方式较为简单,命令如下:
    如果你对helm还不熟悉却想使用这种部署方式,请先阅读Helm基础。
helm install stable/nfs-client-provisioner --set nfs.server=nfs_serverip --set nfs.path=nfs_server_path
  1. 手工方式:
    本章将展示如何以手工方式部署安装。

4、创建SA

首先我们需要创建一个serviceaccount,并使用RoleBinding绑定到leader-locking-nfs-client-provisioner上面。

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
kubectl apply -f rbac.yaml

5、创建nfs-client

将nfs配置成storageclass,安装对应的自动配置程序nfs-client,可以自动创建持久卷(pv)。
每当创建storageclass时,就会在kubernetes里面自动创建pv,nfs目录下自动创建文件夹,省去手动创建的繁琐。

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.0.114        #nfs服务器
            - name: NFS_PATH
              value: /home/nfstestdir     #共享目录
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.0.114         #nfs服务器
            path: /home/nfstestdir        #共享目录
kubectl apply -f nfs-client-deployment.yaml

6、创建存储类

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: fuseim.pri/ifs #---动态卷分配者名称,必须和上面创建的"provisioner"变量中设置的Name一致
parameters:
  archiveOnDelete: "true" #---设置为"false"时删除PVC不会保留数据,"true"则保留数据

设置默认存储类(可选):

metadata.annotations:
storageclass.kubernetes.io/is-default-class: "true" #---设置为默认的storageclass

7、创建PVC

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
  annotations:
    volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"  #---需要与上面创建的storageclass的名称一致
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Mi

8、测试

此时,我们要创建一个测试用的pod,将nfs存储挂载至容器的mnt目录,并新建一个success的文件,观察动态供给是否正常工作。

kind: Pod
apiVersion: v1
metadata:
  name: test-pod
spec:
  containers:
  - name: test-pod
    image: busybox:1.24
    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-claim           #我们定义的pvc

具体创建流程如下所示:

pod->test-claim(pvc)->managed-nfs-storage(SC存储类)->provisioner: fuseim.pri/ifs(PV:nfs-client)

此时,我们查看相关pv,发现已经动态供给了。

[root@k8s-etcd-mater01 nfs]# kubectl get pv,pvc
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS          REASON   AGE
persistentvolume/pvc-50b542db-2ee3-11ea-a207-001c425c73bc   1Mi        RWX            Delete           Bound    default/test-claim   managed-nfs-storage            41m
persistentvolume/pvc-9e0191c8-2ee0-11ea-82c1-001c42662fdd   2Gi        RWO            Delete           Bound    default/test-web-0   managed-nfs-storage            42m

NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/test-claim   Bound    pvc-50b542db-2ee3-11ea-a207-001c425c73bc   1Mi        RWX            managed-nfs-storage   41m
persistentvolumeclaim/test-web-0   Bound    pvc-9e0191c8-2ee0-11ea-82c1-001c42662fdd   2Gi        RWO            managed-nfs-storage   61m

你也可以到nfs服务器端,查看success文件是否生成。

[root@k8s-node01 nfstestdir]# tree
.
├── 11
├── 12
├── 21313
├── 3
├── default-test-claim-pvc-50b542db-2ee3-11ea-a207-001c425c73bc
│   └── SUCCESS
└── default-test-web-0-pvc-9e0191c8-2ee0-11ea-82c1-001c42662fdd

你可能感兴趣的:(#,Kubernetes,云原生,kubernetes,云原生,docker)