Kubernetes之(十二)存储卷

目录

  • Kubernetes之(十二)存储卷

    • 简介
    • emptyDir存储卷
    • hostPath存储卷
    • nfs共享存储卷
    • PV和PVC
    • NFS使用PV和PVC
      • 配置NFS存储
      • 定义PV
      • 定义PVC
      • 查看验证
      • 测试访问
    • StorageClass

Kubernetes之(十二)存储卷

简介

为了保证数据的持久性,必须保证数据在外部存储在docker容器中,为了实现数据的持久性存储,在宿主机和容器内做映射,可以保证在容器的生命周期结束,数据依旧可以实现持久性存储。但是在k8s中,由于pod分布在各个不同的节点之上,并不能实现不同节点之间持久性数据的共享,并且,在节点故障时,可能会导致数据的永久性丢失。为此,k8s就引入了外部存储卷的功能。
k8s的存储卷类型:

[[email protected] ~]# kubectl explain pods.spec.volumes.
 emptyDir     <Object> # 临时目录。pod删除数据也被删除,用于数据的临时存储。
 hostPath   <Object> #宿主机目录映射 和docker的一样
#以上两种都不能满足持久性存储
本地传统存储:
- SAN(iSCSI,FC)
- NAS(nfs,cifs,http)
分布式存储:
- glusterfs
- cephfs
云存储:
- EBS,Azure Disk

persistentVolumeClaim-->PVC(存储卷创建申请)
当你需要创建一个存储卷时,只需要进行申请对应的存储空间即可使用,这就是PVC。其关联关系如图:

(图片来源: https://www.cnblogs.com/linuxk/)

在Pod上定义一个PVC,该PVC要关联到当前名称空间的PVC资源,该PVC只是一个申请,PVC需要和PV进行关联。PV属于存储上的一部分存储空间。但是该方案存在的问题是,我们无法知道用户是什么时候去创建Pod,也不知道创建Pod时定义多大的PVC,那么如何实现按需创建?

不需要PV层,把所有存储空间抽象出来,这一个抽象层称为存储类,当用户创建PVC需要用到PV时,可以向存储类申请对应的存储空间,存储类会按照需求创建对应的存储空间,这就是PV的动态供给,如图:

(图片来源: https://www.cnblogs.com/linuxk/)

PV的动态供给,重点是在存储类的定义,其分类大概是对存储的性能进行分类的。

总结:
k8s要使用存储卷,需要2步:
1、在pod定义volume,并指明关联到哪个存储设备
2、在容器使用volume mount进行挂载

emptyDir存储卷

emptyDir 第一次创建是在一个pod被指定到具体node的时候,并且会一直存在在pod的生命周期当中,它初始化是一个空的目录,pod中的容器都可以读写这个目录,这个目录可以被挂在到各个容器相同或者不相同的的路径下。当一个pod因为任何原因被移除的时候,这些数据会被永久删除。注意:一个容器崩溃了不会导致数据的丢失,因为容器的崩溃并不移除pod.

emptyDir 磁盘的作用:
(1)普通空间,基于磁盘的数据存储
(2)作为从崩溃中恢复的备份点
(3)存储那些那些需要长久保存的数据,例web服务中的数据
默认的,emptyDir 磁盘会存储在主机所使用的媒介上,可能是SSD,或者网络硬盘,这主要取决于你的环境。当然,我们也可以将emptyDir.medium的值设置为Memory来表示挂在一个基于内存的目录tmpfs,因为tmpfs速度会比硬盘快,但是,当主机重启的时候所有的数据都会丢失。

[[email protected] manifests]# mkdir volume &&cd volume
[[email protected] volume]# vim  pod-vol-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
  annotations:
    white/created-by: "white"
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    volumeMounts: #容器内挂载存储卷
    - name: html
      mountPath: /usr/share/nginx/html/
  - name: busybox
    image: busybox
    volumeMounts:  #容器内挂载存储卷
    - name: html
      mountPath: /data/
    command: [ '/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done']
  volumes:
  - name: html  #存储卷命名
    emptyDir: {} #定义存储卷类型

[[email protected] volume]# kubectl apply -f pod-vol-demo.yaml
pod/pod-demo created

上述配置用我们使用Pod内的busybox容器每隔两秒把当前时间写入容器内/data/index.html文件,由于容器busybox和容器myapp都挂载到名未html的存储卷,所以容器myapp的/usr/share/nginx/html/主页目录内会存在index.html文件,内容是切入的日期,验证:

[[email protected] volume]# kubectl apply -f pod-vol-demo.yaml
pod/pod-demo created
[[email protected] volume]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
filebeat-ds-h8rwk                    1/1     Running   0          20h     10.244.1.39   node01   <none>           <none>
filebeat-ds-kzhxw                    1/1     Running   0          20h     10.244.2.44   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          159m    10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          159m    10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          159m    10.244.2.48   node02   <none>           <none>
pod-demo                             2/2     Running   0          7s      10.244.2.53   node02   <none>           <none>
readiness-httpget-pod                1/1     Running   0          3d18h   10.244.2.18   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          97m     10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          97m     10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          97m     10.244.1.45   node01   <none>           <none>

[[email protected] volume]# curl 10.244.2.53
Tue Apr 2 03:35:30 UTC 2019
Tue Apr 2 03:35:32 UTC 2019
Tue Apr 2 03:35:34 UTC 2019
Tue Apr 2 03:35:36 UTC 2019
Tue Apr 2 03:35:38 UTC 2019
Tue Apr 2 03:35:40 UTC 2019
Tue Apr 2 03:35:42 UTC 2019
Tue Apr 2 03:35:44 UTC 2019
Tue Apr 2 03:35:46 UTC 2019
Tue Apr 2 03:35:48 UTC 2019
Tue Apr 2 03:35:50 UTC 2019
Tue Apr 2 03:35:52 UTC 2019
Tue Apr 2 03:35:54 UTC 2019

hostPath存储卷

hostPath宿主机路径,就是把pod所在的宿主机之上的脱离pod中的容器名称空间的之外的宿主机的文件系统的某一目录和pod建立关联关系,在pod删除时,存储数据不会丢失。

[[email protected] volume]# kubectl explain pods.spec.volumes.hostPath.
KIND:     Pod
VERSION:  v1

FIELDS:
   path <string> -required-

   type <string>
     Type for HostPath Volume Defaults to "" More info:
     https://kubernetes.io/docs/concepts/storage/volumes#hostpath

[[email protected] volume]# kubectl explain pods.spec.volumes.hostPath.type.
KIND:     Pod
VERSION:  v1

FIELD:    type <string>
e/volumes#hostpath

type多种类型:

  • DirectoryOrCreate:目录不存在则创建
  • Directory: 目录一定要存在,不存在会报错
  • FileOrCreate:文件存在则创建
  • File:文件一定要存在,不存在会报错
  • Socket:必须存在Soeket文件
  • CharDevice:必须存在char文件
  • BlockDevice: 必须存在块设备文件

配置清单

[[email protected] volume]# vimpod-hostpath-vol.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-hostpath-vol
  namespace: default
spec:
  containers:
  - name: myapp
    iamge: ikubernetes/myapp:v1
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: html
    hostPath:
      path: /data/pod/volume1/
      type: DirectoryOrCreate

为了演示效果,提前在node上创建/data/pod/volume1目录

[[email protected] ~]# mkdir /data/pod/volume1/ -p && echo 'node01.com'>>/data/pod/volume1/index.html
[[email protected] ~]#  mkdir /data/pod/volume1/ -p && echo 'node02.com'>>/data/pod/volume1/index.html

创建Pod

[[email protected] volume]# kubectl apply -f pod-hostpath-vol.yaml
pod/pod-hostpath-vol created
[[email protected] volume]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
filebeat-ds-h8rwk                    1/1     Running   0          23h     10.244.1.39   node01   <none>           <none>
filebeat-ds-kzhxw                    1/1     Running   0          23h     10.244.2.44   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          5h25m   10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          5h25m   10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          5h25m   10.244.2.48   node02   <none>           <none>
pod-hostpath-vol                     1/1     Running   0          80s     10.244.1.48   node01   <none>           <none>
readiness-httpget-pod                1/1     Running   0          3d21h   10.244.2.18   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          4h23m   10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          4h23m   10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          4h23m   10.244.1.45   node01   <none>           <none>

查看可知,pod-hostpath-vol运行在 node01上

[[email protected] volume]# curl 10.244.1.48
node01.com

删除Pod后重新创建,查看

[[email protected] volume]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          5h29m   10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          5h29m   10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          5h29m   10.244.2.48   node02   <none>           <none>
pod-hostpath-vol                     1/1     Running   0          4s      10.244.2.54   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          4h28m   10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          4h28m   10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          4h28m   10.244.1.45   node01   <none>           <none>

此时pod-hostname-vol在node02上,IP为10.244.2.54

[[email protected] volume]# curl 10.244.2.54
node02.com

hostPath可以实现持久存储,但是在node节点故障时,也会导致数据的丢失。

nfs共享存储卷

nfs使的我们可以挂在已经存在的共享到的我们的Pod中,和emptyDir不同的是,emptyDir会被删除当我们的Pod被删除的时候,但是nfs不会被删除,仅仅是解除挂在状态而已,这就意味着NFS能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间相互传递.并且,nfs可以同时被多个pod挂在并进行读写

注意:必须先保证NFS服务器正常运行在我们进行挂在nfs的时候
配置NFS
集群外部主机

主机名 IP地址 系统版本 虚拟机配置 部署软件
nfs 10.0.0.14 Centos 7.5 1804 1核1G nfs-utils
[[email protected] ~]# yum install nfs-utils -y
[[email protected] ~]# mkdir /data/volumes -pv
[[email protected] ~]# vim /etc/exports
/data/volumes 10.0.0.0/24(rw,no_root_squash)
[[email protected] ~]# systemctl start nfs
[[email protected] ~]# showmount -e
Export list for nfs:
/data/volumes 10.0.0.0/24

在node01和node02节点上安装nfs-utils,并测试挂载,挂载正常后卸载

[[email protected] ~]# mount -t nfs nfs:/data/volumes /mnt

[[email protected] ~]# df -h |grep mnt
nfs:/data/volumes   25G  1.9G   23G    8% /mnt
#测试正常
[[email protected] ~]# umount /mnt

配置清单

[[email protected] volume]# vim pod-nfs-vol.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nfs-vol
  namespace: default
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: html
    nfs:
      path: /data/volumes  #挂载路径
      server: nfs   #此处需提前做好host解析,否则使用IP

运行并查看

[[email protected] volume]# kubectl apply -f pod-nfs-vol.yaml
pod/pod-nfs-vol created
[[email protected] volume]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          5h50m   10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          5h50m   10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          5h50m   10.244.2.48   node02   <none>           <none>
pod-hostpath-vol                     1/1     Running   0          20m     10.244.2.54   node02   <none>           <none>
pod-nfs-vol                          1/1     Running   0          4s      10.244.2.55   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          4h49m   10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          4h49m   10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          4h49m   10.244.1.45   node01   <none>           <none>

在NFS服务器挂载目录内创建index.html文件,验证

[[email protected] volumes]#  echo 'this is nfs-vol!!!'>> index.html
[[email protected] volumes]# cat index.html
this is nfs-vol!!!

#回到kubernetes集群内
[[email protected] volume]# curl 10.244.2.55
this is nfs-vol!!!

验证持久性,删除pod后查看nfs服务器文件是否存在,重新启动pod后查看

[[email protected] volume]# kubectl delete -f pod-nfs-vol.yaml
pod "pod-nfs-vol" deleted

[[email protected] volumes]# pwd &&ls
/data/volumes
index.html

[[email protected] volume]# kubectl apply -f pod-nfs-vol.yaml
pod/pod-nfs-vol created
[[email protected] volume]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          5h55m   10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          5h55m   10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          5h55m   10.244.2.48   node02   <none>           <none>
pod-hostpath-vol                     1/1     Running   0          25m     10.244.2.54   node02   <none>           <none>
pod-nfs-vol                          1/1     Running   0          5s      10.244.2.56   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          4h53m   10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          4h53m   10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          4h53m   10.244.1.45   node01   <none>           <none>

[[email protected] volume]# curl 10.244.2.56
this is nfs-vol!!!

此时发现无论重启pod还是删除pod,文件都存在,实现了持久化存储。

PV和PVC

我们前面提到kubernetes提供那么多存储接口,但是首先kubernetes的各个Node节点能管理这些存储,但是各种存储参数也需要专业的存储工程师才能了解,由此我们的kubernetes管理变的更加复杂的。由此kubernetes提出了PV和PVC的概念,这样开发人员和使用者就不需要关注后端存储是什么,使用什么参数等问题。如下图:

(图片来源https://www.cnblogs.com/linuxk/)

PersistentVolume(PV)是集群中已由管理员配置的一段网络存储。 集群中的资源就像一个节点是一个集群资源。 PV是诸如卷之类的卷插件,但是具有独立于使用PV的任何单个pod的生命周期。 该API对象捕获存储的实现细节,即NFS,iSCSI或云提供商特定的存储系统。

(图片来源https://www.cnblogs.com/linuxk/)

PersistentVolumeClaim(PVC)是用户存储的请求。PVC的使用逻辑:在pod中定义一个存储卷(该存储卷类型为PVC),定义的时候直接指定大小,pvc必须与对应的pv建立关系,pvc会根据定义去pv申请,而pv是由存储空间创建出来的。pv和pvc是kubernetes抽象出来的一种存储资源。

虽然PersistentVolumeClaims允许用户使用抽象存储资源,但是常见的需求是,用户需要根据不同的需求去创建PV,用于不同的场景。而此时需要集群管理员提供不同需求的PV,而不仅仅是PV的大小和访问模式,但又不需要用户了解这些卷的实现细节。 对于这样的需求,此时可以采用StorageClass资源。这个在前面就已经提到过此方案。

PV是集群中的资源。 PVC是对这些资源的请求,也是对资源的索赔检查。 PV和PVC之间的相互作用遵循这个生命周期:
Provisioning(配置)---> Binding(绑定)--->Using(使用)---> Releasing(释放) ---> Recycling(回收)

Provisioning
这里有两种PV的提供方式:静态或者动态

静态-->直接固定存储空间:
????集群管理员创建一些 PV。它们携带可供集群用户使用的真实存储的详细信息。 它们存在于Kubernetes API中,可用于消费。

动态-->通过存储类进行动态创建存储空间:
????当管理员创建的静态 PV 都不匹配用户的 PVC 时,集群可能会尝试动态地为 PVC 配置卷。此配置基于 StorageClasses:PVC 必须请求存储类,并且管理员必须已创建并配置该类才能进行动态配置。 要求该类的声明有效地为自己禁用动态配置。

Binding
在动态配置的情况下,用户创建或已经创建了具有特定数量的存储请求和特定访问模式的PersistentVolumeClaim。 主机中的控制回路监视新的PVC,找到匹配的PV(如果可能),并将 PVC 和 PV 绑定在一起。 如果为新的PVC动态配置PV,则循环将始终将该PV绑定到PVC。 否则,用户总是至少得到他们要求的内容,但是卷可能超出了要求。 一旦绑定,PersistentVolumeClaim绑定是排他的,不管用于绑定它们的模式。

如果匹配的卷不存在,PVC将保持无限期。 随着匹配卷变得可用,PVC将被绑定。 例如,提供许多50Gi PV的集群将不匹配要求100Gi的PVC。 当集群中添加100Gi PV时,可以绑定PVC。

Using
Pod使用PVC作为卷。 集群检查声明以找到绑定的卷并挂载该卷的卷。 对于支持多种访问模式的卷,用户在将其声明用作pod中的卷时指定所需的模式。

一旦用户有声明并且该声明被绑定,绑定的PV属于用户,只要他们需要它。 用户通过在其Pod的卷块中包含PersistentVolumeClaim来安排Pods并访问其声明的PV。

Releasing
当用户完成卷时,他们可以从允许资源回收的API中删除PVC对象。 当声明被删除时,卷被认为是“释放的”,但是它还不能用于另一个声明。 以前的索赔人的数据仍然保留在必须根据政策处理的卷上.

Reclaiming
PersistentVolume的回收策略告诉集群在释放其声明后,该卷应该如何处理。 目前,卷可以是保留,回收或删除。 保留可以手动回收资源。 对于那些支持它的卷插件,删除将从Kubernetes中删除PersistentVolume对象,以及删除外部基础架构(如AWS EBS,GCE PD,Azure Disk或Cinder卷)中关联的存储资产。 动态配置的卷始终被删除.

Recycling
如果受适当的卷插件支持,回收将对卷执行基本的擦除(rm -rf / thevolume / *),并使其再次可用于新的声明。

NFS使用PV和PVC

查看pv和pvc规格

[[email protected] ~]# kubectl explain pv.spec.
spec:
  nfs #定义存储类型
    path #定义挂载卷路径
    server #定义服务器名称
  accessModes#定义访问模型,有以下三种访问模型,以列表的方式存在,也就是说可以定义多个访问模式
    ReadWriteOnce  #单节点读写 RWO
    ReadOnlyMany  #多节点只读 ROX
    ReadWriteMany  #多节点读写 RWX
  capacity #定义PV空间的大小
    storage #指定大小

[[email protected] ~]# kubectl explain pvc.spec.
spec:
  accessModes #定义访问模式,必须是PV的访问模式的子集
  resources #定义申请资源的大小#
    requests:
      storage: 

配置NFS存储

[[email protected] volumes]# mkdir v{1..5} -p
[[email protected] volumes]# ll
总用量 4
-rw-r--r-- 1 root root 19 4月   2 14:49 index.html
drwxr-xr-x 2 root root  6 4月   2 16:42 v1
drwxr-xr-x 2 root root  6 4月   2 16:42 v2
drwxr-xr-x 2 root root  6 4月   2 16:42 v3
drwxr-xr-x 2 root root  6 4月   2 16:42 v4
drwxr-xr-x 2 root root  6 4月   2 16:42 v5

[[email protected] volumes]# vim /etc/exports
/data/volumes/v1 10.0.0.0/24(rw,no_root_squash)
/data/volumes/v2 10.0.0.0/24(rw,no_root_squash)
/data/volumes/v3 10.0.0.0/24(rw,no_root_squash)
/data/volumes/v4 10.0.0.0/24(rw,no_root_squash)
/data/volumes/v5 10.0.0.0/24(rw,no_root_squash)
[[email protected] volumes]# exportfs -rv
exporting 10.0.0.0/24:/data/volumes/v5
exporting 10.0.0.0/24:/data/volumes/v4
exporting 10.0.0.0/24:/data/volumes/v3
exporting 10.0.0.0/24:/data/volumes/v2
exporting 10.0.0.0/24:/data/volumes/v1
[[email protected] volumes]# showmount -e
Export list for nfs:
/data/volumes/v5 10.0.0.0/24
/data/volumes/v4 10.0.0.0/24
/data/volumes/v3 10.0.0.0/24
/data/volumes/v2 10.0.0.0/24
/data/volumes/v1 10.0.0.0/24

定义PV

这里定义5个PV,并且定义挂载的路径以及访问模式,还有PV划分的大小。

[[email protected] volume]# vim pv-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
  labels:
    name: pv001
#pv不能定义名称空间,属于整个集群,pvc需要定义名称空间
spec:
  nfs:
    path: /data/volumes/v1/
    server: nfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002
  labels:
    name: pv002
spec:
  nfs:
    path: /data/volumes/v2/
    server: nfs
  accessModes: ["ReadWriteOnce"]
  capacity:
    storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
  labels:
    name: pv003
spec:
  nfs:
    path: /data/volumes/v3/
    server: nfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv004
  labels:
    name: pv004
spec:
  nfs:
    path: /data/volumes/v4/
    server: nfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 4Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv005
  labels:
    name: pv005
spec:
  nfs:
    path: /data/volumes/v5/
    server: nfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 4Gi

1Gi=1024Mi=1024Ki
1G=1000M=1000K
创建PV

[[email protected] volume]# kubectl apply -f pv-demo.yaml
persistentvolume/pv001 created
persistentvolume/pv002 created
persistentvolume/pv003 created
persistentvolume/pv004 created
persistentvolume/pv005 created
[[email protected] volume]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv001   1Gi        RWO,RWX        Retain           Available                                   3s
pv002   2Gi        RWO            Retain           Available                                   3s
pv003   2Gi        RWO,RWX        Retain           Available                                   3s
pv004   4Gi        RWO,RWX        Retain           Available                                   3s
pv005   4Gi        RWO,RWX        Retain           Available                                   3s

定义PVC

[[email protected] volume]# vim pod-pvc-vol.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
  namespace: default
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-pvc-vol
  namespace: default
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: html
    persistentVoumeClaim:
      claimName: mypvc

创建PVC

[[email protected] volume]# kubectl apply -f pod-pvc-vol.yaml
persistentvolumeclaim/mypvc created
pod/pod-nfs-vol created

查看验证

[[email protected] volume]# kubectl get pvc
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    pv005    4Gi        RWO,RWX                       26s
[[email protected] volume]#  kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM           STORAGECLASS   REASON   AGE
pv001   1Gi        RWO,RWX        Retain           Bound       default/mypvc                           14m
pv002   2Gi        RWO            Retain           Available                                           14m
pv003   2Gi        RWO,RWX        Retain           Available                                           14m
pv004   4Gi        RWO,RWX        Retain           Released    default/mypvc                           14m
pv005   4Gi        RWO,RWX        Retain           Released    default/mypvc                           14m

测试访问

[[email protected] volume]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          8h      10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          8h      10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          8h      10.244.2.48   node02   <none>           <none>
pod-hostpath-vol                     1/1     Running   0          179m    10.244.2.54   node02   <none>           <none>
pod-pvc-vol                          1/1     Running   0          4s      10.244.2.58   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          7h27m   10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          7h27m   10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          7h27m   10.244.1.45   node01   <none>           <none>

在存储服务器上创建index.html,并写入数据,通过访问Pod进行查看,可以获取到相应的页面。

[[email protected] v1]# pwd
/data/volumes/v1
[[email protected] v1]# echo $(date)>>./index.html
[[email protected] v1]# echo $(date)>>./index.html
[[email protected] v1]# echo $(date)>>./index.html

[[email protected] volume]# curl 10.244.2.58
2019年 04月 02日 星期二 17:26:57 CST
2019年 04月 02日 星期二 17:27:08 CST
2019年 04月 02日 星期二 17:27:08 CST

StorageClass

在pv和pvc使用过程中存在的问题,在pvc申请存储空间时,未必就有现成的pv符合pvc申请的需求,上面nfs在做pvc可以成功的因素是因为我们做了指定的需求处理。那么当PVC申请的存储空间不一定有满足PVC要求的PV事,又该如何处理呢???为此,Kubernetes为管理员提供了描述存储"class(类)"的方法(StorageClass)。举个例子,在存储系统中划分一个1TB的存储空间提供给Kubernetes使用,当用户需要一个10G的PVC时,会立即通过restful发送请求,从而让存储空间创建一个10G的image,之后在我们的集群中定义成10G的PV供给给当前的PVC作为挂载使用。在此之前我们的存储系统必须支持restful接口,比如ceph分布式存储,而glusterfs则需要借助第三方接口完成这样的请求.

[[email protected] ~]# kubectl explain storageclass
KIND:     StorageClass
VERSION:  storage.k8s.io/v1

FIELDS:
   allowVolumeExpansion <boolean>

   allowedTopologies    <[]Object>

     feature.

   apiVersion   <string>

   kind <string>

   metadata     <Object>

   mountOptions <[]string>   #挂载选项

   parameters   <map[string]string> #参数,取决于分配器,可以接受不同的参数。 例如,参数 type 的值 io1 和参数 iopsPerGB 特定于 EBS PV。当参数被省略时,会使用默认值。  

   provisioner  <string> -required- #存储分配器,用来决定使用哪个卷插件分配 PV。该字段必须指定。

   reclaimPolicy        <string> #回收策略,可以是 Delete 或者 Retain。如果 StorageClass 对象被创建时没有指定 reclaimPolicy ,它将默认为 Delete。 

   volumeBindingMode    <string>   #卷的绑定模式

StorageClass 中包含 provisioner、parameters 和 reclaimPolicy 字段,当 class 需要动态分配 PersistentVolume 时会使用到。由于StorageClass需要一个独立的存储系统,此处就不再演示。

参考资料

https://www.cnblogs.com/linuxk
马永亮. Kubernetes进阶实战 (云计算与虚拟化技术丛书)
Kubernetes-handbook-jimmysong-20181218

原文地址:https://www.cnblogs.com/wlbl/p/10694348.html

时间: 2024-10-08 02:39:38

Kubernetes之(十二)存储卷的相关文章

Kubernetes学习之路(十六)之存储卷

一.存储卷的概念和类型 为了保证数据的持久性,必须保证数据在外部存储在docker容器中,为了实现数据的持久性存储,在宿主机和容器内做映射,可以保证在容器的生命周期结束,数据依旧可以实现持久性存储.但是在k8s中,由于pod分布在各个不同的节点之上,并不能实现不同节点之间持久性数据的共享,并且,在节点故障时,可能会导致数据的永久性丢失.为此,k8s就引入了外部存储卷的功能. k8s的存储卷类型: [[email protected] ~]# kubectl explain pod.spec.vo

Kubernetes 存储卷管理 PV&amp;PVC(十)

为了持久化保存容器的数据,可以使用 Kubernetes Volume. Volume 的生命周期独立于容器,Pod 中的容器可能被销毁和重建,但 Volume 会被保留. 本质上,Kubernetes Volume 是一个目录,这一点与 Docker Volume 类似.当 Volume 被 mount 到 Pod,Pod 中的所有容器都可以访问这个 Volume.Kubernetes Volume 也支持多种 backend 类型,包括 emptyDir.hostPath.GCE Persi

Kubernetes部署(十二):helm部署harbor企业级镜像仓库

相关内容: Kubernetes部署(一):架构及功能说明Kubernetes部署(二):系统环境初始化Kubernetes部署(三):CA证书制作Kubernetes部署(四):ETCD集群部署Kubernetes部署(五):Haproxy.Keppalived部署Kubernetes部署(六):Master节点部署Kubernetes部署(七):Node节点部署Kubernetes部署(八):Flannel网络部署Kubernetes部署(九):CoreDNS.Dashboard.Ingre

现代&ldquo;十二要素应用&rdquo;与 Kubernetes

"十二要素应用"为开发SaaS应用提供了方法上的指导,而Docker能够提供打包依赖,解耦后端服务等特性,使得两者非常吻合.这篇文章介绍了Docker特性怎样满足了开发"十二要素应用"的对应要点. "十二要素应用"为构建SaaS应用提供了方法论,是由知名PaaS云计算平台Heroku的创始人Adam Wiggins提出的.请参考这篇 Heroku 创始人 Adam Wiggins 发布十二要素应用宣言. Dockerfile 与k8s/helm

C Primer Plus (第五版) 第十二章 存储类、链接和内存管理 编程练习

第十二章 存储类.链接和内存管理 编程练习 1.Q不使用全局变量,重写程序清单13.4 #include <stdio.h>; int critic(int u); int main(void) { int units; printf("How many pounds to a firkin of butter?\n"); scanf_s("%d", &units); while (units != 56) critic(units); prin

Kubernetes之存储卷

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

Kubernetes 学习12 kubernetes 存储卷

一.概述 1.我们此前讲过根据应用本身是否需要持久存储数据以及某一次请求和之前的请求是否有联系,可以分为四类应用 a.有状态,要存储 b.有状态,无持久存储 c.无状态,要存储 d.无状态,无持久存储 其中,大多数和数据存储服务相关的应用和有状态应用几乎都是需要持久存储数据的.在docker中说过,容器有生命周期,为了使容器将来终结以后可以把其删除,甚至是编排到其它节点上去运行,意味着我们数据不能放在容器本地,不能放在容器自己的名称空间中.注意这是两套逻辑,以k8s为例,pod运行时应该是运行在

Go语言开发(十二)、Go语言常用标准库二

Go语言开发(十二).Go语言常用标准库二 一.os 1.os简介 os 包提供了不依赖平台的操作系统函数接口,设计像Unix风格,但错误处理是go风格,当os包使用时,如果失败后返回错误类型而不是错误数量. 2.os常用接口 func Hostname() (name string, err error) // Hostname返回内核提供的主机名 func Environ() []string // Environ返回表示环境变量的格式为"key=value"的字符串的切片拷贝 f

k8s实践(七):存储卷和数据持久化(Volumes and Persistent Storage)

环境说明: 主机名 操作系统版本 ip docker version kubelet version 配置 备注 master Centos 7.6.1810 172.27.9.131 Docker 18.09.6 V1.14.2 2C2G master主机 node01 Centos 7.6.1810 172.27.9.135 Docker 18.09.6 V1.14.2 2C2G node节点 node02 Centos 7.6.1810 172.27.9.136 Docker 18.09.