Kubernetes学习笔记(五):卷

简介#

卷是Pod的一部分,与Pod共享生命周期。它不是独立的Kubernetes对象,因此不能单独创建。

卷提供的存储功能不但可以解决容器重启后数据丢失的问题,还可以使数据在容器间共享。

一些卷的类型:

  • emptyDir:用于存储临时数据的空目录
  • hostPath:用于将目录从工作节点挂载到pod
  • gitRepo:通过检出Git仓库的内容来初始化的卷
  • nfs:挂载到pod中的nfs共享卷
  • configMap、secret、downwardAPI:用于将Kubernetes部分资源和集群信息公开给pod的特殊类型的卷
  • persistentVolumeClaim:一种使用预置或者动态配置的持久存储类型

单个容器可以同时使用不同类型的多个卷。

emptyDir#

emptyDir卷对于在同一个pod中运行的容器之间共享文件特别有用。但也可以被单个容器用于将数据临时写入磁盘。

下面的例子中,Pod包含两个容器,这个两个容器分别将卷html挂载到容器内的不同路径,实现了文件共享。html-generator每隔一秒写入当前时间到index.html,web-server提供web服务使index.html可以被访问。

Copy
# volume-share-pod.yaml apiVersion: v1 kind: Pod metadata: name: volume-share spec: containers: - image: alpine # 容器镜像一 name: html-generator volumeMounts: # 将名为html的卷挂载到容器的/var/html - name: html mountPath: /var/html command: ["sh","-c","mkdir /var/html; while :; do echo $(date) > /var/html/index.html;sleep 1;done"] - image: nginx:alpine #容器镜像二 name: web-server volumeMounts: # 与上面相同的卷卷挂载到容器的/usr/share/nginx/html - name: html mountPath: /usr/share/nginx/html readOnly: true ports: - containerPort: 80 volumes: # 创建一个名为html的卷 - name: html emptyDir: {}

创建pod,设置端口转发

Copy
-> [root@kube0.vm] [~] k create -f volume-share-pod.yaml pod/volume-share created -> [root@kube0.vm] [~] k port-forward volume-share 80:80 Forwarding from 127.0.0.1:80 -> 80 Forwarding from [::1]:80 -> 80

发出请求

Copy
-> [root@kube0.vm] [~] curl http://localhost Sun May 24 01:14:48 UTC 2020 -> [root@kube0.vm] [~] curl http://localhost Sun May 24 01:14:49 UTC 2020

如果进行下面的改动,emptyDir的内容会存在内存中

Copy
volumes: - name: html emptyDir: medium: Memory

gitRepo#

gitRepo卷基本上也是一个emptyDir卷,它在容器启动前从git仓库检出填充数据。

当git仓库内容发生改变时,对已存在的Pod内的gitRepo卷是不可见的。但启动新的Pod时会检出最新的。

下面的例子中,该pod创建了一个名为html的gitRepo卷的,创建一个提供web服务的容器web-server,并将卷html挂载到web-server的/usr/share/nginx/html。

Copy
# volume-gitrepo-pod.yaml apiVersion: v1 kind: Pod metadata: name: volume-gitrepo spec: containers: - image: nginx:alpine name: web-server volumeMounts: - name: html mountPath: /usr/share/nginx/html readOnly: true ports: - containerPort: 80 volumes: # 创建一个名为html的gitRepo卷 - name: html gitRepo: repository: https://github.com/orccn/kube-dockerfile.git # 仓库地址 revision: master # 分支 directory: . # 检出到卷的根目录

创建pod,设置端口转发

Copy
-> [root@kube0.vm] [~] k create -f volume-gitrepo-pod.yaml pod/volume-gitrepo created -> [root@kube0.vm] [~] k port-forward volume-gitrepo 80:80 Forwarding from 127.0.0.1:80 -> 80 Forwarding from [::1]:80 -> 80

发出请求

Copy
-> [root@kube0.vm] [~] curl http://localhost/etcd/Dockerfile FROM k8s.gcr.io/etcd:3.4.3-0

hostPath#

hostPath卷提供的是映射到工作节点本地持久存储。所以应仅当需要在工作节点上读写文件时才使用hostPath

下例中,Pod中创建一个名为html的hostPath卷挂载到工作节点的 /tmp/html,容器volume-hostpath将卷html挂载到/var/html,并且向其中写入文件。

Copy
# volume-hostpath-pod.yaml apiVersion: v1 kind: Pod metadata: name: volume-hostpath spec: containers: - image: alpine name: volume-hostpath command: ["sh","-c","mkdir /var/html; while :; do echo $(date) > /var/html/index.html;sleep 1;done"] volumeMounts: - name: html mountPath: /var/html volumes: - name: html hostPath: path: /tmp/html

创建volume-hostpath,查看其部署在哪个节点。

Copy
-> [root@kube0.vm] [~] k create -f volume-hostpath-pod.yaml pod/volume-hostpath created -> [root@kube0.vm] [~] k get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES volume-hostpath 1/1 Running 0 9m32s 10.244.1.11 kube1.vm <none> <none>

进入节点kube1.vm

Copy
-> [root@kube1.vm] [~] cat /tmp/html/index.html Sun May 24 02:26:14 UTC 2020

PV与PVC#

PV(PersistentVolume持久卷)也是一种资源,并且不属于任何命名空间。它的功能与卷类似,但是它的生命周期是独立于Pod的。PV由集群管理员创建,并被Pod通过PVC(PersistentVolumeClaim,持久卷声明)使用。

在创建PV时,管理员可以指定其大小和支持的访问模式:

  • ReadWriteOnce(RWO):仅允许单个节点挂载读写
  • ReadOnlyMany(ROX):允许多个节点挂载只读
  • ReadWriteMany(RWX):允许多个节点挂载读写

一个卷不论支持多少种访问模式,同时只能以一种访问模式加载。

创建PV#

管理员在创建PV时需要指定,PV的大小、访问模式、实际存储类型、路径等。

Copy
# pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: mypv spec: capacity: storage: 10Mi # 定义大小 accessModes: # 支持单个客户端挂在为读写模式或者多个客户端只读模式 - ReadWriteOnce - ReadOnlyMany persistentVolumeReclaimPolicy: Retain # 当声明被释放后,PV将被保留 hostPath: path: /tmp/pv

条件有限,所以存储类型只能先选hostPath用着,接下来创建pv并查看

Copy
-> [root@kube0.vm] [~] k create -f pv.yaml persistentvolume/volume-pv created -> [root@kube0.vm] [~] k get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv 10Mi RWO,ROX Retain Available 4s

创建PVC#

假设要部署一个需要持久化存储的Pod,将要用到持久卷,但是不能在Pod中直接使用,需要先声明一个。

Copy
# pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mypvc spec: resources: requests: storage: 10Mi accessModes: - ReadWriteOnce storageClassName: ""

PVC创建好后,Kubernetes会寻找适当的PV将其绑定到PVC。持久卷必须要足够大,并且包含声明中指定的访问模式。

Copy
-> [root@kube0.vm] [~] k create -f pvc.yaml persistentvolumeclaim/mypvc created -> [root@kube0.vm] [~] k get pv,pvc NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE persistentvolume/mypv 10Mi RWO,ROX Retain Bound default/mypvc 7m11s NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/mypvc Bound mypv 10Mi RWO,ROX 9s

可以看到持久卷被绑定到default/mypvc声明上,default是mypvc的命名空间。PV不存在命名空间的概念,但是PVC只能在特定命名空间创建。

Pod中使用PVC#

Copy
# use-pvc-pod.yaml apiVersion: v1 kind: Pod metadata: name: use-pvc spec: containers: # 这里的内容与volume-share.yaml的一样,所以功能不再赘叙, - image: alpine name: html-generator volumeMounts: - name: html mountPath: /var/html command: ["sh","-c","mkdir /var/html; while :; do echo $(date) > /var/html/index.html;sleep 1;done"] volumes: - name: html persistentVolumeClaim: # 这里使用了PVC类型,制定了PVC的名字 claimName: mypvc

创建Pod

Copy
-> [root@kube0.vm] [~] k create -f use-pvc-pod.yaml pod/use-pvc created -> [root@kube0.vm] [~] k get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES use-pvc 1/1 Running 0 4m1s 10.244.1.12 kube1.vm <none> <none>

与kube1.vm查看是否写入了内容

Copy
-> [root@kube1.vm] [~] cat /tmp/pv/index.html Sun May 24 06:43:02 UTC 2020

回收PV#

删除PVC后,查看PV,可以看到此时的状态是Released,而不是之前的Available。

Copy
-> [root@kube0.vm] [~] k delete pvc mypvc persistentvolumeclaim "mypvc" deleted -> [root@kube0.vm] [~] k get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv 10Mi RWO,ROX Retain Released default/mypvc 35s

这时候在创建PVC,会发现mypvc的状态一直是Pending,因为没有可用的PV。所以,persistentVolumeReclaimPolicy设置为Retain的PV需要手动删除重建才能恢复可用。

Copy
-> [root@kube0.vm] [~] k create -f pvc.yaml persistentvolumeclaim/mypvc created -> [root@kube0.vm] [~] k get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mypvc Pending 16s

persistentVolumeReclaimPolicy用来设置回收策略,其他两种是Recycle和Delete。可以在现有的PV上更改卷回收策略,比如开始设置为Delete,可以改为Retain。

PV与PVC的声明周期,以及在Pod中的使用#

StorageClass#

使用PV与PVC可以使开发人员不用关心实际的存储技术,但是仍然需要集群管理人员来支持实际的存储。可以通过创建StorageClass资源解决此问题。

StorageClass的作用是:为引用它的PVC在创建的时候通过置备程序创建一个PV。

工作流程简介:

  • 集群管理员根据不同性能及特性创建若干个StorageClass
  • 开发人员创建一个引用StorageClass的PVC
  • Kubernetes查找引用的StorageClass置备程序,并按照PVC的访问模式和存储大小置备新的PV

因为环境问题,下面的例子使用minikube运行。

创建StorageClass#

Copy
# storageclass-fast.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: k8s.io/minikube-hostpath parameters: type: pd-ssd

运行查看

Copy
-> [feifei@ffmac.local] [~/work/k8s] kubectl create -f storageclass-fast.yaml storageclass.storage.k8s.io/fast created -> [feifei@ffmac.local] [~/work/k8s] kubectl get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE fast k8s.io/minikube-hostpath Delete Immediate false 114m standard (default) k8s.io/minikube-hostpath Delete Immediate false 117m

创建PVC引用StorageClass#

Copy
# pvc-storageclass.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-sc spec: resources: requests: storage: 10Mi accessModes: - ReadWriteOnce storageClassName: fast # 引用了上面名为fast的StorageClass

可以看到,成功创建了一个名为pvc-be95fa9c-0666-4e3b-a2e2-a68c0bbea6f6的持久卷,绑定的持久卷声明是default/pvc-sc。访问模式与存储大小与pvc-sc的都一致。

Copy
-> [feifei@ffmac.local] [~/work/k8s] kubectl create -f pvc-storageclass.yaml persistentvolumeclaim/pvc-sc created -> [feifei@ffmac.local] [~/work/k8s] kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-be95fa9c-0666-4e3b-a2e2-a68c0bbea6f6 10Mi RWO Delete Bound default/pvc-sc fast 3m36s -> [feifei@ffmac.local] [~/work/k8s] kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc-sc Bound pvc-be95fa9c-0666-4e3b-a2e2-a68c0bbea6f6 10Mi RWO fast 3m40s

不指定存储类的动态配置#

如果将PVC配置中的storageClassName设置为空,那么创建PVC时将优先绑定到预先配置的PV,而不是由StorageClass配置新的PV。

流程图#

小结#

  • 卷是Pod的一部分,与Pod共享生命周期。它不是独立的Kubernetes对象,因此不能单独创建。
  • 卷提供的存储功能不但可以解决容器重启后数据丢失的问题,还可以使数据在容器间共享。
  • gitRepo卷基本上相当于emptyDir,它在容器启动前从git仓库检出填充数据。但git仓库与gitRepo的内容并不保持同步。
  • hostPath卷提供的是映射到工作节点本地持久存储
  • PV是一种资源,并且不属于任何命名空间。它的功能与卷类似,但是它的生命周期是独立于Pod的。PV由集群管理员创建,并被Pod通过PVC使用。
  • PVC创建好后,Kubernetes会寻找适当的PV将其绑定到PVC。持久卷必须要足够大,并且包含声明中指定的访问模式。
  • 可以在现有的PV上更改卷回收策略,比如开始设置为Delete,可以改为Retain。
  • StorageClass为引用它的PVC在创建的时候通过置备程序创建一个PV
  • 如果将PVC配置中的storageClassName设置为空,那么创建PVC时将优先绑定到预先配置的PV,而不是由StorageClass配置新的PV。
posted @   虾敏四把刀  阅读(508)  评论(1编辑  收藏  举报
编辑推荐:
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
阅读排行:
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
· 程序员转型AI:行业分析
点击右上角即可分享
微信分享提示
CONTENTS