Kubernetes的存储之Volume

在虚拟化的一系列解决方案中,数据的持久化都是需要我们非常关心的问题,dokcer是这样,Kubernetes也是这样。不过在Kubernetes中,有一个数据卷的概念。

一、Volume简介

我们经常都会说:容器、Pod都是很短暂的!其含义就是容器和Pod的生命周期都是很短暂的,会被频繁地销毁和创建。容器销毁时,保存在容器内部文件系统中的数据都会被清除。

Volume的生命周期独立于容器,Pod中的容器可能被销毁和重启,但Volume会被保留。

Kubernetes Volume主要解决了以下两个问题:
1)数据持久性:通常情况下,容器运行起来后,写到其文件系统的文件是暂时性的。当容器崩溃后,kubelet会将这个容器不断的重启,当达到重启的次数后,容器仍然不可用,那么就会将这个容器kill掉,重新生成新的容器。此时,新运行的容器并没有原容器中的数据,因为容器是由镜像创建的;
2)数据共享:同一个Pod中运行的容器之间,经常会存在共享文件/共享文件夹的需求;

从根本上来说,一个数据卷仅仅是一个可以被Pod访问的目录或文件。这个目录是怎么来的,取决于该数据卷的类型。同一个Pod中的两个容器可以将一个数据卷挂载到不同的目录下。

Volume 提供了对各种 backend 的抽象,容器在使用 Volume 读写数据的时候不需要关心数据到底是存放在本地节点的文件系统中呢还是云硬盘上。对它来说,所有类型的 Volume 都只是一个目录。

二、Volume之emptyDir

1)emptyDir简介

emptyDir 是最基础的 Volume 类型。正如其名字所示,一个 emptyDir Volume 是 Host 上的一个空目录。

emptyDir Volume 对于容器来说是持久的,对于 Pod 则不是。当 Pod 从节点删除时,Volume 的内容也会被删除。但如果只是容器被销毁而 Pod 还在,则 Volume 不受影响。类似于docker数据持久化中的docker manager volume方式!

2)emptyDir使用示例

[[email protected] yaml]# vim emptyDir.yaml
apiVersion: v1
kind: Pod
metadata:
  name: producer-consumer          #定义Pod的名称
spec:
  containers:
  - image: busybox
    name: producer              #定义容器的名称
    volumeMounts:
    - mountPath: /producer_dir            #指定容器内的路径
      name: shared-volume                 #表示把shared-volume挂载到容器中
    args:               #当容器运行完成后,执行以下的写操作
    - /bin/sh
    - -c
    - echo "hello k8s" > /producer_dir/hello; sleep 30000

  - image: busybox
    name: consumer             #定义容器的名称
    volumeMounts:
    - mountPath: /consumer_dir
      name: shared-volume                     #与上一个容器一样
    args:
    - /bin/sh
    - -c
    - cat /consumer_dir/hello; sleep 30000

  volumes:
  - name: shared-volume           #定义数据卷的名称,必须与以上挂载的数据卷名称一致
    emptyDir: {}             #定义一个类型为emptyDir的数据卷,名称为shared-volume
[[email protected] yaml]# kubectl apply -f emptyDir.yam        #生成所需的Pod资源
[[email protected] yaml]# kubectl exec -it producer-consumer -c producer /bin/sh
#进入第一个容器进行验证
/ # cat /producer_dir/hello
hello k8s
[[email protected] yaml]# kubectl exec -it producer-consumer -c consumer /bin/sh
#进行第二个容器进行验证
/ # cat /consumer_dir/hello
hello k8s

到此可以看出这个pod中的两个容器指定的目录内容都是一样的,具体是本地的那个目录还需进一步进行验证。

[[email protected] yaml]# kubectl get pod -o wide
NAME                READY   STATUS    RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATES
producer-consumer   2/2     Running   0          7m58s   10.244.2.2   node02   <none>           <none>
#可以看出这个pod是运行在node02上的
[[email protected] ~]# docker ps | grep busybox          #由于容器较多,根据使用的镜像名称进行筛选
4fbd734e1763        busybox                "/bin/sh -c ‘cat /co…"    8 minutes ago       Up 8 minutes                            k8s_consumer_producer-consumer_default_003a002d-caec-4202-a020-1ae8d6ff7eba_0
b441c2ff2217        busybox                "/bin/sh -c ‘echo \"h…"   8 minutes ago       Up 8 minutes                            k8s_producer_producer-consumer_default_003a002d-caec-4202-a020-1ae8d6ff7eba_0
[[email protected] ~]# docker inspect 4fbd734e1763         #根据容器的ID查看容器的详细信息
#找到Mounts字段,如下:
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/003a002d-caec-4202-a020-1ae8d6ff7eba/volumes/kubernetes.io~empty-dir/shared-volume",
                                #此处指定的便是docker host本地的目录
                "Destination": "/consumer_dir",             #容器中的目录
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
[[email protected] ~]# docker inspect b441c2ff2217
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/003a002d-caec-4202-a020-1ae8d6ff7eba/volumes/kubernetes.io~empty-dir/shared-volume",
                "Destination": "/producer_dir",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
#可以看出这两个容器的源目录是一样,挂载的是docker host本地的同一个目录
[[email protected] ~]# cd /var/lib/kubelet/pods/003a002d-caec-4202-a020-1ae8d6ff7eba/volumes/kubernetes.io~empty-dir/shared-volume
[[email protected] shared-volume]# cat hello
hello k8s
#验证内容

由于是Kubernetes集群的环境,删除一个容器比较麻烦,直接将pod删除,查看docker host本地的数据是否存在!

[[email protected] yaml]# kubectl delete -f emptyDir.yaml
#master节点将pod删除
[[email protected] ~]# cd /var/lib/kubelet/pods/003a002d-caec-4202-a020-1ae8d6ff7eba/volumes/kubernetes.io~empty-dir/shared-volume
-bash: cd: /var/lib/kubelet/pods/003a002d-caec-4202-a020-1ae8d6ff7eba/volumes/kubernetes.io~empty-dir/shared-volume: 没有那个文件或目录
#node02进行验证,发现目录已经消失

3)emptyDir总结

emptyDir 是Docker Host 上创建的临时目录,其优点是能够方便地为 Pod 中的容器提供共享存储,不需要额外的配置。但它不具备持久性,如果 Pod 不存在了,emptyDir 也就没有了。根据这个特性,emptyDir 特别适合 Pod 中的容器需要临时共享存储空间的场景!

简单来说就是,如果容器被删除,数据依然存在;如果Pod被删除,数据将不会存在!

三、Volume之HostPath

hostPath Volume 的作用是将 Docker Host 文件系统中已经存在的目录 mount 给 Pod 的容器。大部分应用都不会使用 hostPath Volume,因为这实际上增加了 Pod 与节点的耦合,限制了 Pod 的使用。不过那些需要访问 Kubernetes 或 Docker 内部数据(配置文件和二进制库)的应用则需要使用 hostPath。类似于docker数据持久化中的bind mount方式!

当然也可以进行创建,这里就偷个懒,使用Kubernetes集群自带的YAML文件进行介绍!

[[email protected] yaml]# kubectl edit --namespace=kube-system pod kube-apiserver-master
#查看apiserver组件的yaml文件

如图:

如果 Pod 被销毁了,hostPath 对应的目录也还会被保留,从这点看,hostPath 的持久性比 emptyDir 强。不过一旦 Host 崩溃,hostPath 也就没法访问了。

由于使用场景较少,以上两种方式这里就不详细介绍了!

四、Volume之Persistent Volume

Persistent Volume概述

普通Volume和使用它的Pod之间是一种静态绑定关系,在定义Pod的文件里,同时定义了它使用的Volume。Volume 是Pod的附属品,我们无法单独创建一个Volume,因为它不是一个独立的K8S资源对象。

而Persistent Volume 简称PV是一个K8S资源对象,所以我们可以单独创建一个PV。它不和Pod直接发生关系,而是通过Persistent Volume Claim,简称PVC来实现动态绑定。Pod定义里指定的是PVC,然后PVC会根据Pod的要求去自动绑定合适的PV给Pod使用。

既然有了PV这个概念,那么PVC(PersistentVolumeClaim)这个概念也不得不说一下,PVC代表用户使用存储的请求,应用申请PV持久化空间的一个申请、声明。K8s集群可能会有多个PV,你需要不停的为不同的应用创建多个PV。

如图:


1)PV是集群中的存储资源,通常由集群管理员创建和管理;
2)StorageClass用于对PV进行分类,如果配置正确,Storage也可以根据PVC的请求动态创建PV;
3)PVC是使用该资源的请求,通常由应用程序提出请求,并指定对应的StorageClass和需求的空间大小;
4)PVC可以作为数据卷的一种,被挂载到Pod中使用;

PV与PVC的管理过程如下:
1)在主机上划分出一个单独的目录用于PV使用,并且定义其可用大小;
2)创建PVC这个资源对象,便于申请PV的存储空间;
3)Pod中添加数据卷,数据卷关联到PVC;
4)Pod中包含容器,容器挂载数据卷;

下面通过一个案例来详细了解一下Persistent Volume!

案例实现过程:
1)底层采用NFS存储,然后再NFS的目录下划分1G的容量供PV调度;
2)创建PVC来申请PV的存储空间;
3)创建Pod,使用PVC申请的存储空间来实现数据的持久化;

1)搭建NFS存储

本次案例直接在master节点上创建NFS存储!

[[email protected] ~]# yum -y install nfs-utils rpcbind
[[email protected] ~]# vim /etc/exports
/nfsdata *(rw,sync,no_root_squash)
[[email protected] ~]# systemctl start nfs-server
[[email protected] ~]# systemctl start rpcbind
[[email protected] ~]# showmount -e
Export list for master:
/nfsdata *

2)创建PV资源对象

[[email protected] ~]# vim test-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-pv
spec:
  capacity:
    storage: 1Gi          #指定该PV资源分配的容器为1G
  accessModes:         #指定访问模式
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle       #指定回收策略
  storageClassName: nfs           #指定存储类名字
  nfs:                          #需要与存储类名字一致
    path: /nfsdata/test-pv                //指定NFS的目录
    server: 192.168.1.4                  //指定NFS的IP地址

上述yaml文件中,主要字段的解释:
1)accessModes(访问模式):

  • ReadWriteOnce:以读写的方式挂载到单个节点;
  • ReadWriteMany:以读写的方式挂载到多个节点 ;
  • ReadOnlyMany:以只读的方式挂载到多个节点;
    2)persistentVolumeReclaimPolicy(PV的回收策略):
  • Recycle:自动清除PV中的数据,自动回收;
  • Retain:需要手动回收;
  • Delete:删除云存储资源(云存储专用);
[[email protected] ~]# kubectl apply -f test-pv.yaml
[[email protected] ~]# kubectl get pv         #查看PV的状态
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
test-pv   1Gi        RWO            Recycle          Available           nfs                     21s
#注意其PV的状态必须是 Available才可正常使用

3)创建PVC资源对象

[[email protected] ~]# vim test-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:             #定义访问模式,必须与PV定义的访问模式一致
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi            #直接请求i使用最大的容量
  storageClassName: nfs           #定义的名称需与PV定义的名称一致
[[email protected] ~]# kubectl apply -f test-pvc.yaml
[[email protected] ~]# kubectl get pvc          #查看PVC的状态
NAME       STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-pvc   Bound    test-pv   1Gi        RWO            nfs            102s
[[email protected] ~]# kubectl get pv           #查看PV的状态
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE
test-pv   1Gi        RWO            Recycle          Bound    default/test-pvc   nfs                     14m
#注意PV与PVC的状态都是Bound,表示PV与PVC的关联成功

PV和PVC可以通过storageClassName或accessModes进行关联的!

常见的状态有:
1)Available——>闲置状态,没有被绑定到PVC;
2)Bound——>绑定到PVC;
3)Released——>PVC被删除,资源没有被利用;
4)Failed——>自动回收失败;

4)创建一个Pod

[[email protected] ~]# vim test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: test-pod
    image: busybox
    args:
    - /bin/sh
    - -c
    - sleep 300000
    volumeMounts:
    - mountPath: /testdata            #定义容器中的目录
      name: volumedata               #保证与卷的名称一致
  volumes:
    - name: volumedata               #定义卷的名称
      persistentVolumeClaim:
        claimName: test-pvc            #指定逻辑卷对应的PVC名称
[[email protected] ~]# kubectl apply -f  test-pod.yaml
[[email protected] ~]# kubectl get pod      #查看pod的状态
NAME       READY   STATUS              RESTARTS   AGE
test-pod   0/1     ContainerCreating   0         6m26s
#注意其状态为 ContainerCreating,表示容器正在创建,但是查看时间,这么长时间没有创建好,不太正常

当pod状态不正常时,一般我们可以采用以下三种方式进行排错:
1)使用“ kubectl describe pod pod名称”查看pod的详细信息;
2)使用“kubectl logs pod名称“查看pod的日志信息;
3)使用“cat /var/log/messages”查看系统日志;

本次采用第一种方式排错!

[[email protected] ~]# kubectl describe pod test-pod
#最后的一条的信息如下:
mount.nfs: mounting 192.168.1.4:/nfsdata/test-pv failed, reason given by server: No such file or directory
#根据消息提示,指定本地需要挂载的目录不存在
[[email protected] ~]# mkdir  -p  /nfsdata/test-pv
#创建完成目录后,建议查看pod生成的容器运行的节点,将节点上的kubelet服务进行重启,重启完成后,再次查看Pod的状态
[[email protected] ~]# kubectl get pod        //再次查看pod的状态
NAME       READY   STATUS    RESTARTS   AGE
test-pod   1/1     Running   0          32m

5)测试其数据持久化的效果

[[email protected] ~]# kubectl exec -it test-pod /bin/sh
/ # echo "test pv pvc" > /testdata/test.txt
#进入容器,创建文件进行测试
[[email protected] ~]# cat /nfsdata/test-pv/test.txt
test pv pvc
#确认这个文件本地是存在的
[[email protected] ~]# kubectl delete -f test-pod.yaml
#将pod进行删除
[[email protected] ~]# cat /nfsdata/test-pv/test.txt
test pv pvc
#再次查看发现pod的测试文件依然存在
[[email protected] ~]# kubectl delete -f test-pvc.yaml
#将PVC进行删除
[[email protected] ~]# cat /nfsdata/test-pv/tes
cat: /nfsdata/test-pv/tes: 没有那个文件或目录
#再次查看发现pod的测试文件不见了,因为将PVC删除了

总结:由于我们在创建pv这个资源对象时,采用的回收策略是清除PV中的数据,然后自动回收,而PV这个资源对象是由PVC来申请使用的,所以不管是容器也好,pod也好,它们的销毁并不会影响用于实现数据持久化的nfs本地目录下的数据,但是,一旦这个PVC被删除,那么本地的数据就会随着PVC的销毁而不复存在,也就是说,采用PV这种数据卷来实现数据的持久化,它这个数据持久化的生命周期是和PVC的生命周期是一致的。

——————————————本次到此结束,感谢阅读——————————————

原文地址:https://blog.51cto.com/14157628/2469352

时间: 2024-10-08 22:31:10

Kubernetes的存储之Volume的相关文章

20.Kubernetes共享存储

Kubermetes对于有状态的容器应用或者对数据需要持久化的应用,不仅需要将容器内的目录挂载到宿主机的目录或者emptyDir临时存储卷,而且需要更加可靠的存储来保存应用产生的重要数据,以便容器应用在重建之后,仍然可以使用之前的数据.不过,存储资源和计算资源(CPU/内存)的管理方式完全不同.为了能够屏蔽底层存储实现的细节,让用户方便使用,同时能让管理员方便管理, Kubernetes从v1.0版本就引入PersistentVolume和PersistentVolumeClaim两个资源对象来

kubernetes持久化存储,静态存储【pv】,动态存储【StorageClass】(5)

在开始介绍k8s持久化存储前,我们有必要了解一下k8s的emptydir和hostpath.configmap以及secret的机制和用途 1.EmptydirEmptyDir是一个空目录,他的生命周期和所属的 Pod 是完全一致的,pod删掉目录消失 2.HostpathHostpath会把宿主机上的指定卷加载到容器之中,如果 Pod 发生跨主机的重建,其内容就难保证了 3.ConfigmapConfigMap跟Secrets类似,但是ConfigMap可以更方便的处理不包含敏感信息的字符串.

Kubernetes核心概念之Volume存储数据卷详解

在Docker中就有数据卷的概念,当容器删除时,数据也一起会被删除,想要持久化使用数据,需要把主机上的目录挂载到Docker中去,在K8S中,数据卷是通过Pod实现持久化的,如果Pod删除,数据卷也会一起删除,k8s的数据卷是docker数据卷的扩展,K8S适配各种存储系统,包括本地存储EmptyDir,HostPath,网络存储NFS,GlusterFS,PV/PVC等,下面就详细介绍下K8S的存储如何实现. 一.本地存储 1,EmptyDir ①编辑EmptyDir配置文件 vim empt

kubernetes(五)--存储之configmap/secret/volume/Persistent Volume

一.configmap 1.1.configmap简介 ConfigMap 功能在 Kubernetes1.2 版本中引入,许多应用程序会从配置文件.命令行参数或环境变量中读取配置信息.ConfigMap API 给我们提供了向容器中注入配置信息的机制,ConfigMap 可以被用来保存单个属性,也可以用来保存整个配置文件或者 JSON 二进制对象 1.2.ConfigMap 的创建 1.2.1.使用目录创建 [[email protected] dir]# ls game.propertie

Kubernetes之存储卷

存储卷概述 容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题.首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失--容器以干净的状态(镜像最初的状态)重新启动.其次,在 Pod 中同时运行多个容器时,这些容器之间通常需要共享文件.Kubernetes 中的 Volume 抽象就很好的解决了这些问题.在原docker环境中也有存储卷的概念,但docker环境的存储卷调度在宿主机上的目录,当docker重新创建的时候存储卷还会挂载统一宿主机上,但我们

第13章 存储之volume

容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题.首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动.其次,在Pod中同时运行多个容器时,这些容器之间通常需要共享文件.Kubernetes 中的Volume抽象就很好的解决了这些问题 1.背景 Kubernetes 中的卷有明确的寿命 —— 与封装它的 Pod 相同.所f以,卷的生命比 Pod 中的所有容器都长,当这个容器重启时数据仍然得以保存.当然,

Kubernetes 持久化存储之GlusterFS

GlusterFS是一个开源的分布式文件,具有强大的横向扩展能力,可支持数PB存储容量和数千客户端,通过网络互连成一个并行的网络文件系统.具有扩展性.高性能.高可用性等特点. 前提:必须要在实验环境中部署了Gluster FS集群,文中创建了名为:gv0的存储卷 1.创建endpoint,文件名为glusterfs_ep.yaml $ vi glusterfs_ep.yaml apiVersion: v1 kind: Endpoints metadata: name: glusterfs nam

Docker 持久化存储, Data Volume

docker容器, 再启动之后 我们可以对其进行 修改删除等等.如果是一个数据库的容器, 里面的数据 不想随着这个容器的消失, 而消失.  就需要持久化数据存储. Data Volume   这是 docker hub 上面  mysql 的Dockerfile 这里的 VOLUME 意思就是, 将产生的数据 写入到当前主机的 /var/lib/mysql 里面. [[email protected] ~]$ docker images REPOSITORY TAG IMAGE ID CREAT

kubernetes之NFS动态提供Kubernetes后端存储卷

原文地址:https://www.cnblogs.com/lovelinux199075/p/11268414.html