一、介绍

1、为什么需要存储卷

(1)容器启动时,除了来自于镜像的文件系统外,没有其他文件,如果想加入一些文件,例如配置文件,就需要存储卷加进去

(2)容器重启后,非原镜像中的文件会丢失,例如xx服务的数据文件,如果希望容器重启后数据依然在,需要存储卷保证数据的不丢失

(3)pod内有多个容器,如果希望多个容器间共享一些数据,就需要存储卷来存一份数据,给多个容器用,相当于磁盘

2、生命周期

存储卷被定义为pod的一部分,并和pod共享相同的生命周期

二、容器间共享数据型存储卷

1、emptyDir卷

apiVersion: v1
kind: Pod
metadata:
  name: emptydir-example
spec:
  containers:
  - image: docker.io/library/busybox:latest
    name: container1
    imagePullPolicy: IfNotPresent
    command: 
    - top
    volumeMounts:
    - name: html
      mountPath: /opt/aaa
  - image: docker.io/library/busybox:latest
    name: container2
    imagePullPolicy: IfNotPresent
    command: 
    - top
    volumeMounts:
    - name: html
      mountPath: /opt/bbb
  volumes:
  - name: html
    emptyDir: {}

容器container1向它的目录/opt/aaa写入一个文件,容器container2即可从它的/opt/bbb目录中读取到这个文件,因为这俩目录挂载的是同一个卷。

emptyDir是在工作节点的实际磁盘上创建的,要想创建在内存上,可以指定volumes的medium

2、gitRepo卷

gitRepo基本就是emptyDir卷,在pod启动后、容器启动前,k8s创建一个空目录并将指定的git仓库克隆到其中,只git pull这一次,pod启动后不会再pull,所以无法拉到新代码

有两种方法同步新代码:

a.pod删了重建(由RC控制重新拉起)

b.用一个sidecar容器共享这个卷,sidecar容器中开进程同步代码

无法拉取私仓的代码,只能拉github,因为gitRepo初衷是简单操作,配置私仓就多了一写SSH的配置了,越来越复杂

  volumes:
  - name: git
    ditRepo:
      repository: https://github.com/xxxxx.git
      revision: master
      directory: .               // 拉取代码到.目录,挂载时挂到对应目录

image.png

三、共享工作节点文件型存储卷

存储卷的生命周期和pod是相同的,pod删除时,存储卷也没了,但可以把数据存放到pod运行的工作节点上,这样即便pod删了,工作节点上的文件依然在

1、hostpath

apiVersion: v1
kind: Pod
metadata:
  name: hostpath-example
spec:
  containers:
  - image: docker.io/library/busybox:latest
    name: container1
    imagePullPolicy: IfNotPresent
    command: 
    - top
    volumeMounts:
    - name: hp
      mountPath: /opt/aaa/
  volumes:
  - name: hp
    hostPath: 
      # 工作节点的路径,不是云桌面的
      path: /opt/code/aaa/

四、尽量使用持久化存储

hostpath换个工作节点就没了,pod重启后就可能调度到其他节点上

自有集群上(对应云集群,例如Google),持久化的存储一般就需要用NFS了,包括各种类型:glusterfs、cephfs等等,这些都需要外设,外挂存储空间

五、持久卷PV和持久卷声明PVC

开发人员不应该关注于外挂存储空间的,只需要知道申请空间用于存储即可

1、解耦存储技术与pod

image.png

将底层存储技术与pod解耦后,开发人员需要关注的是持久卷声明PersistantVolumeClaims-----PVC,集群管理员要关注的是持久卷PersistantVolume-------PV

PV是集群中独立于pod的一块存储,它的底层存储技术可能是glusterfs,可能是cephfs等等,集群管理员需要事先制备好。它不属于任何命名空间,跟节点一样是集群层面的资源

PVC表达的是用户对存储的请求,当用户需要在pod中使用持久化存储时,首先要创建PVC,指定需要的最低容量和访问模式,并提交给k8s API,k8s会找到可匹配的PV并将其绑定到PVC上

一个PVC只能绑定一个PV,但是一个PV能绑定多个PVC,PVC与pod也是一一对应

image.png

2、创建PV

image.png

查看创建的PV

kubectl get pvNAME
CAPACITY        RECLAIMPOLICY    ACCESSMODES               STATUS                 CLAIM
mongodb-pv      1Gi              Retain                    RWO,ROX                Available

因为现在还没有创建PVC,所以该PV没有绑定任何PVC,status为available

3、创建PVC

这里讲的是PVC和PV的关系,所以先不使用StorageClass

image.png

创建成功后

查看PVC状态:

kubectl get pvc
NAME          STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mongodb-pvc   Bound    mongodb-pv   1Gi        RWO,ROX                       111m

看到该PVC绑定了一个卷,即刚才创建的PV,再回头看刚刚的PV

kubectl get  pvNAME  
CAPACITY     ACCESS     MODES          RECLAIM POLICY   STATUS   CLAIM              
mongodb-pv   1Gi        RWO,ROX        Retain           Bound    default/mongodb-pvc

PV的状态为已绑定绑定的是刚创建的PVC,该PVC是在default命名空间下的

4、在pod中使用PVC

apiVersion: v1
kind: Pod
metadata:
  name: pvcpod-example
spec:
  containers:
  - image: docker.io/library/busybox:latest
    name: container1
    imagePullPolicy: IfNotPresent
    command: 
    - top
    volumeMounts:
    - name: pvc
      mountPath: /opt/aaa/
  volumes:
  - name: pvc
    persistentVolumeClaim: 
      claimName: pvc

5、回收PV

kubectl   delete  po

在用的pvc是删不掉的,只能先删除pod

kubectl   delete  pvc

删了之后看下PVC的状态.

kubectl get pvc
NAME          STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mongodb-pvc   Pending

再看PV的状态

kubectl get pvNAME         
CAPACITY     ACCESS     MODES          RECLAIM POLICY   STATUS     CLAIM           
mongodb-pv   1Gi        RWO,ROX        Retain           Released   default/mongodb-pvc

被释放了,但仅仅是被释放了,当有新的PVC绑定到该PV后,新的PVC可以看到之前的数据,也就是说数据没有清理

通过将回收策略由Retain改为Recycle可以自动清理数据,也可以改为delete,随着PVC的删除,PV一并被删除

六、持久卷的动态卷配置

PV是提前创建的,创建多大才能使得绑定PVC后,既不浪费空间,又足够用?只能做成动态的,随着PVC的创建而创建,于是,有了StorageClass来动态配置卷

1、创建一个StorageClass资源

集群管理员可以不创建PV,但是必须创建一个或多个StorageClass,它和PV一样是k8s的一种资源

创建一个名为fast的StorageClass

它指定了当PVC请求此StorageClass时应该使用哪个置备程序来提供持久卷,创建PVC时,StorageClass会将yaml中定义的parameters传递给置备程序,并具体到每个供应器插件

2、创建PVC

如果PVC中配置了一个不存在的StorageClass,会失败

查看一下:

kubectl get pvc mongodb-pvc
NAME          STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mongodb-pvc   Bound    pvc-asdf13f  1Gi        RWO            fast           111m

可以看到绑定的StorageClass是fast

查看PV:

kubectl get pvNAME
CAPACITY     ACCESS     MODES          RECLAIM POLICY   STATUS     STORAGECLASS           
pvc-asdf13f  1Gi        RWO            Delete           Bound      fast

发现自动创建了一个PV,并且策略为delete,当PVC删除时,这个PV也删除

3、不指定StorageClass

kubectl get  sc
NAME                TYPE
fast                k8s.io/minikube-hostpath
standard(default)   k8s.io/minikube-hostpath

可以看到其实有一个默认的StorageClass的,当PVC的yaml里不指定StorageClassName时,就会用这个默认的

如果想不用动态的PV--StorageClass,只用预先配置的PV,可以在yaml里把StorageClassName这一项显示设置为“”

4、了解动态PV供应的全貌

image.png

Logo

一起探索未来云端世界的核心,云原生技术专区带您领略创新、高效和可扩展的云计算解决方案,引领您在数字化时代的成功之路。

更多推荐