java系统找不到指定文件怎么解决
185
2022-09-11
(九)Kubernetes 存储卷
Kubernetes存储卷概述
Pod本身具有生命周期,这就带了一系列的问题,第一,当一个容器损坏之后,kubelet会重启这个容器,但是文件会丢失-这个容器会是一个全新的状态;第二,当很多容器在同一Pod中运行的时候,很多时候需要数据文件的共享。Docker支持配置容器使用存储卷将数据持久存储于容器自身文件系统之外的存储空间之中,它们可以是节点文件系统或网络文件系统之上的存储空间。相应的,kubernetes也支持类似的存储卷功能,不过,其存储卷是与Pod资源绑定而非容器。
简单来说,存储卷是定义在Pod资源之上、可被其内部的所有容器挂载的共享目录,它关联至某外部的存储设备之上的存储空间,从而独立于容器自身的文件系统,而数据是否具有持久能力取决于存储卷自身是否支持持久机制。Pod、容器与存储卷的关系图如下。
Kubernetes支持的存储卷类型
Kubernetes支持非常丰富的存储卷类型,包括本地存储(节点)和网络存储系统中的诸多存储机制,还支持Secret和ConfigMap这样的特殊存储资源。例如,关联节点本地的存储目录与关联GlusterFS存储系统所需要的配置参数差异巨大,因此指定存储卷类型时也就限定了其关联到的后端存储设备。通过命令# kubectl explain pod.spec可以查看当前kubernetes版本支持的存储卷类型。常用类型如下:非持久性存储emptyDirhostPath网络连接性存储SAN:iscsiNFS:nfs、cfs分布式存储glusterfs、cephfs、rbd云端存储awsElasticBlockStore、azureDisk、gitRepo
存储卷的使用方式
在Pod中定义使用存储卷的配置由两部分组成:一是通过.spec.volumes字段定义在Pod之上的存储卷列表,其支持使用多种不同类型的存储卷且配置参数差别很大;另一个是通过.spce.containers.volumeMounts字段在容器上定义的存储卷挂载列表,它只能挂载当前Pod资源中定义的具体存储卷,当然,也可以不挂载任何存储卷。
在Pod级别定义存储卷时,.spec.volumes字段的值为对象列表格式,每个对象为一个存储卷的定义,由存储卷名称(.spec.volumes.name
......volumes:- name: data emptyDir: {}- name: example gitRepo: repository: revision: master directory:
无论何种类型的存储卷,挂载格式基本上都是相同的,通过命令# kubectl explain pod.spec.containers.volumeMounts 可以进行查看。在容器中顶一个挂载卷时的通用语法形式如下:
......volumeMounts:- name
示例,容器myapp将上面定义的data存储卷挂载于/var/log/myapp,将examply挂载到/webdata/example目录。
spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: data mountPath: /var/log/myapp/ - name: example mountPath: /webdata/example/
存储卷使用示例
下面的所有示例的资源清单文件都放在新建的storage目录中。
[root@k8s-master ~]# mkdir storage[root@k8s-master ~]# cd storage/
emptyDir 存储卷
emptyDir存储卷是Pod对象生命周期中的一个临时目录,类似于Docker上的“docker 挂载卷”,在Pod对象启动时即被创建,而在Pod对象被移除时会被一并删除(永久删除)。Pod中的容器都可以读写这个目录,这个目录可以被挂载到各个容器相同或者不相同的路径下。注意:一个容器崩溃了不会导致数据的丢失,因为容器的崩溃并不移除Pod。emptyDir的作用:普通空间,基于磁盘的数据存储作为从崩溃中恢复的备份点存储那些需要长久保存的数据,例如web服务中的数据
emptyDir字段说明:
[root@k8s-master ~]# kubectl explain pod.spec.volumes.emptyDirmedium
emptyDir示例:
这里定义了一个Pod资源对象(vol-emptydir-pod),在其内部定义了两个容器,其中一个容器是辅助容器sidecar,每隔10秒生成一行信息追加到index.html文件中;另一个是nginx容器,将存储卷挂载到站点家目录。然后访问nginx的html页面验证两个容器之间挂载的emptyDir实现共享。
1)编辑资源清单文件
[root@k8s-master storage]# vim vol-emptydir.yamlapiVersion: v1kind: Podmetadata: name: vol-emptydir-podspec: volumes: #定义存储卷 - name: html #定义存储卷的名称 emptyDir: {} #定义存储卷的类型 containers: - name: nginx image: nginx:1.12 volumeMounts: #在容器中定义挂载存储卷的名和路径 - name: html mountPath: /usr/share/nginx/html - name: sidecar image: alpine volumeMounts: #在容器中定义挂载存储卷的名和路径 - name: html mountPath: /html command: ["/bin/sh", "-c"] args: - while true; do echo $(hostname) $(date) >> /html/index.html; sleep 10; done
2)创建并查看状态
[root@k8s-master storage]# kubectl apply -f vol-emptydir.yaml pod/vol-emptydir-pod created[root@k8s-master storage]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESvol-emptydir-pod 2/2 Running 0 63s 10.244.2.79 k8s-node2
3)访问测试
[root@k8s-master storage]# curl 10.244.2.79vol-emptydir-pod Wed Oct 9 03:32:43 UTC 2019vol-emptydir-pod Wed Oct 9 03:32:53 UTC 2019vol-emptydir-pod Wed Oct 9 03:33:03 UTC 2019vol-emptydir-pod Wed Oct 9 03:33:13 UTC 2019vol-emptydir-pod Wed Oct 9 03:33:23 UTC 2019......#进入vol-emptydir-pod中的sidecar容器中查看挂载目录下的index.html文件[root@k8s-master storage]# kubectl exec vol-emptydir-pod -c sidecar -it -- /bin/sh/ # ls bin etc html media opt root sbin sys usrdev home lib mnt proc run srv tmp var/ # ls /htmlindex.html/ # cat /html/index.html vol-emptydir-pod Wed Oct 9 03:32:43 UTC 2019vol-emptydir-pod Wed Oct 9 03:32:53 UTC 2019vol-emptydir-pod Wed Oct 9 03:33:03 UTC 2019......#进入vol-emptydir-pod中的nginx容器中查看挂载目录下的index.html文件[root@k8s-master storage]# kubectl exec vol-emptydir-pod -c nginx -it -- /bin/sh# cat /usr/share/nginx/html/index.htmlvol-emptydir-pod Wed Oct 9 03:32:43 UTC 2019vol-emptydir-pod Wed Oct 9 03:32:53 UTC 2019vol-emptydir-pod Wed Oct 9 03:33:03 UTC 2019......
hostPath 存储卷
hostPath类型的存储卷是指将工作节点上的某文件系统的目录或文件挂载于Pod中的一种存储卷,独立于Pod资源的生命周期,具有持久性。在Pod删除时,数据不会丢失。
hostPath字段说明:
[root@k8s-master storage]# kubectl explain pod.spec.volumes.hostPathpath
hostPath示例:
1)编辑资源清单文件
[root@k8s-master storage]# vim vol-hostpath.yamlapiVersion: v1kind: Podmetadata: name: pod-vol-hostpath namespace: defaultspec: containers: - name: myapp image: nginx:1.15 imagePullPolicy: IfNotPresent volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /data/pod/volume1 type: DirectoryOrCreate
2)创建并查看状态
[root@k8s-master storage]# kubectl apply -f vol-hostpath.yaml pod/vol-hostpath-pod created[root@k8s-master storage]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESvol-hostpath-pod 1/1 Running 0 7s 10.244.1.83 k8s-node1
3)通过上面查看pod被调度到节点1上面,查看节点1的目录并创建测试文件
[root@k8s-node1 ~]# ll /data/pod/volume1/总用量 0[root@k8s-node1 ~]# echo "
4)访问测试,及删除测试
[root@k8s-master storage]# curl 10.244.1.83
nfs 存储卷
nfs存储卷用于将事先存在的NFS服务器上导出的存储空间挂载到Pod中供容器使用。与emptyDir不同的是,当pod资源删除时emptyDir也会被删除,而NFS在Pod对象删除时仅是被卸载而非删除。这就意味NFS能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间相互传递,并且NFS可以同时被多个Pod挂载并进行读写。
nfs字段说明:
[root@k8s-master ~]# kubectl explain pod.spec.volumes.nfsserver
nfs示例:
1)首先准备一个nfs服务器
[root@storage ~]# yum -y install nfs-utils #安装软件[root@storage ~]# mkdir -p /data/k8s/v1 #创建共享目录[root@storage ~]# vim /etc/exports #编辑配置文件配置共享目录/data/k8s/v1 192.168.1.0/24(rw,no_root_squash)[root@storage ~]# systemctl start rpcbind #启动rpcbind服务(nfs依赖服务)[root@storage ~]# systemctl start nfs #启动nfs[root@k8s-node1 ~]# showmount -e 192.168.1.34 #k8s节点测试能否正常访问到nfs服务器Export list for 192.168.1.34:/data/k8s/v1 192.168.1.0/24
2)编辑资源清单文件
[root@k8s-master storage]# vim vol-nfs.yaml
3)创建并查看状态
[root@k8s-master storage]# kubectl apply -f vol-nfs.yaml pod/vol-nfs-pod created[root@k8s-master storage]# kubectl get pods NAME READY STATUS RESTARTS AGEvol-nfs-pod 1/1 Running 0 45s[root@k8s-master storage]# kubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESvol-nfs-pod 1/1 Running 0 51s 10.244.2.80 k8s-node2
4)测试验证
[root@k8s-master storage]# kubectl exec -it vol-nfs-pod redis-cli127.0.0.1:6379> set mykey "hello test"OK127.0.0.1:6379> get mykey"hello test127.0.0.1:6379> bgsave Background saving started127.0.0.1:6379> exit#为了测试其数据持久化效果,下面删除Pod资源vol-nfs-pod,并于再次重新创建后检测数据是否依然能够访问[root@k8s-master storage]# kubectl delete -f vol-nfs.yaml pod "vol-nfs-pod" deleted[root@k8s-master storage]# kubectl apply -f vol-nfs.yaml pod/vol-nfs-pod created[root@k8s-master storage]# kubectl get pods -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESvol-nfs-pod 1/1 Running 0 47s 10.244.1.84 k8s-node1
通过上面测试可以看出,此前创建的mykey及其数据在Pod资源重建后依然存在,且不论pod资源调度到哪个节点。这表明在删除Pod资源时,其关联的外部存储卷并不会被一同删除。如果需要删除此类的数据,需要用户通过存储系统的管理接口手动进行。
PVC与PV
介绍
前面提到Kubernetes提供那么多存储接口,但是首先Kubernetes的各个Node节点能管理这些存储,但是各种存储参数也需要专业的存储工程师才能了解,由此我们的Kubernetes管理变的更加复杂。由此kubernetes提出了PV和PVC的概念,这样开发人员和使用者就不需要关注后端存储是什么,使用什么参数等问题。如下图:
PV:
PersistentVolume(PV)是集群中已由管理员配置的一段网络存储。集群中的资源就像一个节点是一个集群资源。PV是诸如卷之类的卷插件,但是具有独立于使用PV的任何单个Pod的生命周期。该API对象捕获存储的实现细节,即NFS,ISCSI或云提供商特定的存储系统。
PVC:
PersistentVolumeClaim(PVC)是用户存储的请求。它类似于Pod。Pod消耗节点资源,PVC消耗存储资源。Pod可以请求特定级别的资源(CPU和内存)。权限要求可以请求特定的大小和访问模式。虽然PersistentVolumeClaims允许用户使用抽象存储资源,但是常见的是,用户需要具有不同属性(如性能)的PersistentVolumes,用于不同的问题。集群管理员需要能够提供多种不同于PersistentVolumes的PersistentVolumes,而不仅仅是大小和访问模式,而不会使用户了解这些卷的实现细节。对于这些需求,存在StorageClass资源。StorageClass为管理员提供了一种描述他们提供的存储的“类”的方法。不同的类可能映射到服务质量级别,或备份策略,或者由集群管理员确定的任意策略。Kubernetes本身对于什么类别代表是不言而喻的。这个概念有时在其它存储系统中称为“配置文件”
生命周期
PV是集群中的资源。PVC是对这些资源的请求,也是对资源的索赔检查。PV和PVC之间的相互作用遵循这个生命周期:Provisioning—>Binding—>Using—>Releasing—>Recycling
供应准备Provisioning
绑定Binding
用户创建PVC并指定需要的资源和访问模式。在找到可用PV之前,PVC会保持未绑定状态。
使用Using
用户可在Pod中像volume一样使用PVC。
释放Releasing
用户删除PVC来回收存储资源,PV将变成“released”状态。由于还保留着之前的数据,这些数据要根据不同的策略来处理,否则这些存储资源无法被其它PVC使用
回收Recycling
PV可以设置三种回收策略:保留(Retain)、回收(Recycle)和删除(Delete)。
创建PV
字段说明:
PersistentVolume Spec主要支持以下几个通用字段,用于定义PV的容量、访问模式、和回收策略
[root@k8s-master ~]# kubectl explain pv.speccapacity
创建PVC
字段说明:
PersistentVolumeClaim是存储卷类型的资源,它通过申请占用某个PersistentVolume而创建,它与PV是一对一的关系,用户无须关系其底层实现细节。申请时,用户只需要指定目标空间的大小、访问模式、PV标签选择器和StorageClass等相关信息即可。PVC的Spec字段的可嵌套字段具体如下:
[root@k8s-master ~]# kubectl explain pvc.specaccessModes <[]string> #当前PVC的访问模式,其可用模式与PV相同resources
在Pod中使用PVC
在Pod资源中调用PVC资源,只需要在定义volumes时使用persistentVolumeClaims字段嵌套指定两个字段即可。具体如下:
[root@k8s-master ~]# kubectl explain pod.spec.volumes.persistentVolumeClaimclaimName
示例使用PVC和PV
说明:下面示例中,准备了一台NFS Server创建了几个共享目录提供给Kubernetes作为PV使用。在创建PV的同时指定了不同的大小和不同的访问权限,然后在创建PVC时候指定了大小为6Gi,故满足条件的PV只有pv003~pv005,这里通过标签选择器选择了pv003。Pod中的容器使用了MySQL,并将MySQL的数据目录挂载到PV上。示例图如下:
1)准备NFS服务
(1)创建存储卷对应的目录[root@storage ~]# mkdir /data/volumes/v{1..5} -p(2)修改nfs的配置文件[root@storage ~]# vim /etc/exports/data/volumes/v1 192.168.1.0/24(rw,no_root_squash)/data/volumes/v2 192.168.1.0/24(rw,no_root_squash)/data/volumes/v3 192.168.1.0/24(rw,no_root_squash)/data/volumes/v4 192.168.1.0/24(rw,no_root_squash)/data/volumes/v5 192.168.1.0/24(rw,no_root_squash)(3)查看nfs的配置[root@storage ~]# exportfs -arvexporting 192.168.1.0/24:/data/volumes/v5exporting 192.168.1.0/24:/data/volumes/v4exporting 192.168.1.0/24:/data/volumes/v3exporting 192.168.1.0/24:/data/volumes/v2exporting 192.168.1.0/24:/data/volumes/v1(4)使配置生效[root@storage ~]# showmount -eExport list for storage:/data/volumes/v5 192.168.1.0/24/data/volumes/v4 192.168.1.0/24/data/volumes/v3 192.168.1.0/24/data/volumes/v2 192.168.1.0/24/data/volumes/v1 192.168.1.0/24
2)创建PV;这里创建5个PV,存储大小各不相等,是否可读也不相同
(1)编写资源清单文件[root@k8s-master storage]# vim pv-nfs-demo.yamlapiVersion: v1kind: PersistentVolumemetadata: name: pv-nfs-001 labels: name: pv001spec: nfs: path: /data/volumes/v1 server: 192.168.1.34 readOnly: false accessModes: ["ReadWriteOnce","ReadWriteMany"] capacity: storage: 2Gi persistentVolumeReclaimPolicy: Retain---apiVersion: v1kind: PersistentVolumemetadata: name: pv-nfs-002 labels: name: pv002spec: nfs: path: /data/volumes/v2 server: 192.168.1.34 readOnly: false accessModes: ["ReadWriteOnce"] capacity: storage: 5Gi persistentVolumeReclaimPolicy: Retain---apiVersion: v1kind: PersistentVolumemetadata: name: pv-nfs-003 labels: name: pv003spec: nfs: path: /data/volumes/v3 server: 192.168.1.34 readOnly: false accessModes: ["ReadWriteOnce","ReadWriteMany"] capacity: storage: 10Gi persistentVolumeReclaimPolicy: Retain---apiVersion: v1kind: PersistentVolumemetadata: name: pv-nfs-004 labels: name: pv004spec: nfs: path: /data/volumes/v4 server: 192.168.1.34 readOnly: false accessModes: ["ReadWriteOnce","ReadWriteMany"] capacity: storage: 15Gi persistentVolumeReclaimPolicy: Retain---apiVersion: v1kind: PersistentVolumemetadata: name: pv-nfs-005 labels: name: pv005spec: nfs: path: /data/volumes/v5 server: 192.168.1.34 readOnly: false accessModes: ["ReadWriteOnce","ReadWriteMany"] capacity: storage: 20Gi persistentVolumeReclaimPolicy: Retain (2)创建PV[root@k8s-master storage]# kubectl apply -f pv-nfs-demo.yaml persistentvolume/pv-nfs-001 createdpersistentvolume/pv-nfs-002 createdpersistentvolume/pv-nfs-003 createdpersistentvolume/pv-nfs-004 createdpersistentvolume/pv-nfs-005 created(3)查看PV[root@k8s-master storage]# kubectl get pvNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGEpv-nfs-001 2Gi RWO,RWX Retain Available 2spv-nfs-002 5Gi RWO Retain Available 2spv-nfs-003 10Gi RWO,RWX Retain Available 2spv-nfs-004 15Gi RWO,RWX Retain Available 2spv-nfs-005 20Gi RWO,RWX Retain Available 2s
3)创建PVC,绑定PV
(1)编写资源清单文件[root@k8s-master storage]# vim vol-nfs-pvc.yaml#创建PVCapiVersion: v1kind: PersistentVolumeClaimmetadata: name: nfs-pvcspec: accessModes: ["ReadWriteMany"] resources: requests: storage: 6Gi #指定PVC大小为6Gi selector: #这里通过标签选择器指定了所使用的pv卷为key为name,value为pv003的pv资源 matchLabels: name: pv003---#创建PodapiVersion: v1kind: Podmetadata: name: pvc-mysql labels: app: mysqlspec: containers: - name: pvc-mysql-pod image: mysql:latest imagePullPolicy: IfNotPresent ports: - name: mysqlport containerPort: 3306 volumeMounts: - name: mysqldata mountPath: /var/lib/mysql env: - name: MYSQL_ROOT_PASSWORD value: "mysql" volumes: - name: mysqldata persistentVolumeClaim: #通过该字段定义使用pvc claimName: nfs-pvc #指定pvc的名称 readOnly: false #关闭只读(2)创建PVC和Pod[root@k8s-master storage]# kubectl apply -f vol-nfs-pvc.yaml persistentvolumeclaim/nfs-pvc createdpod/pvc-mysql created
4)查询验证pv和pvc
[root@k8s-master storage]# kubectl get pvc #查看pvc,可以看到该pvc使用的是pv-nfs-003资源NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEnfs-pvc Bound pv-nfs-003 10Gi RWO,RWX 12s[root@k8s-master storage]# kubectl get pv #查看pv,可以看出pv-nfs-003资源的状态从Availabel变成了BoundNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGEpv-nfs-001 2Gi RWO,RWX Retain Available 64mpv-nfs-002 5Gi RWO Retain Available 64mpv-nfs-003 10Gi RWO,RWX Retain Bound default/nfs-pvc 64mpv-nfs-004 15Gi RWO,RWX Retain Available 64mpv-nfs-005 20Gi RWO,RWX Retain Available 64m[root@k8s-master storage]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESpvc-mysql 1/1 Running 0 31s 10.244.2.84 k8s-node2
5)测试验证
#(1)进入到pod连接容器mysql并创建一个数据库[root@k8s-master ~]# kubectl exec -it pvc-mysql -- mysql -u root -pmysql......mysql> mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || sys |+--------------------+4 rows in set (0.01 sec)mysql> create database volumes;Query OK, 1 row affected (0.00 sec)mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || sys || volumes |+--------------------+5 rows in set (0.00 sec)mysql> exitBye#(2)删除pvc和pod和pv[root@k8s-master storage]# kubectl delete -f vol-nfs-pvc.yaml #删除pvcpersistentvolumeclaim "nfs-pvc" deletedpod "pvc-mysql" deleted[root@k8s-master storage]# kubectl delete -f pv-nfs-demo.yaml #删除pv(如果有pv在被使用的状态,需要先删除pvc方可删除pv)persistentvolume "pv-nfs-001" deletedpersistentvolume "pv-nfs-002" deletedpersistentvolume "pv-nfs-003" deletedpersistentvolume "pv-nfs-004" deletedpersistentvolume "pv-nfs-005" deleted[root@storage ~]# ls /data/volumes/v3/ #上面删除了pv和pvc,可以看出存储服务器上面的数据还是存在auto.cnf ca-key.pem ib_buffer_pool ibtmp1 performance_schema server-key.pem volumesbinlog.000001 ca.pem ibdata1 #innodb_temp private_key.pem sysbinlog.000002 client-cert.pem ib_logfile0 mysql public_key.pem undo_001binlog.index client-key.pem ib_logfile1 mysql.ibd server-cert.pem undo_002#(3)重新创建pv和pvc和pod验证数据[root@k8s-master storage]# kubectl apply -f pv-nfs-demo.yaml persistentvolume/pv-nfs-001 createdpersistentvolume/pv-nfs-002 createdpersistentvolume/pv-nfs-003 createdpersistentvolume/pv-nfs-004 createdpersistentvolume/pv-nfs-005 created[root@k8s-master storage]# kubectl apply -f vol-nfs-pvc.yaml persistentvolumeclaim/nfs-pvc createdpod/pvc-mysql created[root@k8s-master ~]# kubectl exec -it pvc-mysql -- mysql -u root -pmysqlmysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || sys || volumes |+--------------------+5 rows in set (0.00 sec)###测试说明:如果删除pvc不删除pv,重新创建同样的pvc,那么pvc状态会处于Pending状态,因为pv的当前状态为Released。这也和上面定义的回收策略息息相关。
人生是条无名的河,是浅是深都要过; 人生是杯无色的茶,是苦是甜都要喝; 人生是首无畏的歌,是高是低都要唱。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~