简介
卷是 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 可以被访问.
- # 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, 设置端口转发
- -> [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
发出请求
- -> [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 的内容会存在内存中
- 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.
- # 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, 设置端口转发
- -> [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
发出请求
- -> [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, 并且向其中写入文件.
- # 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, 查看其部署在哪个节点.
- -> [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
- -> [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 的大小, 访问模式, 实际存储类型, 路径等.
- # 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 并查看
- -> [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 中直接使用, 需要先声明一个.
- # pvc.YAML
- apiVersion: v1
- kind: PersistentVolumeClaim
- metadata:
- name: mypvc
- spec:
- resources:
- requests:
- storage: 10Mi
- accessModes:
- - ReadWriteOnce
- storageClassName: ""
PVC 创建好后, Kubernetes 会寻找适当的 PV 将其绑定到 PVC. 持久卷必须要足够大, 并且包含声明中指定的访问模式.
- -> [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
- # 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
- -> [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 查看是否写入了内容
- -> [root@kube1.vm] [~] cat /tmp/pv/index.HTML
- Sun May 24 06:43:02 UTC 2020
回收 PV
删除 PVC 后, 查看 PV, 可以看到此时的状态是 Released, 而不是之前的 Available.
- -> [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 需要手动删除重建才能恢复可用.
- -> [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
- # storageclass-fast.YAML
- apiVersion: storage.k8s.io/v1
- kind: StorageClass
- metadata:
- name: fast
- provisioner: k8s.io/minikube-hostpath
- parameters:
- type: pd-ssd
运行查看
- -> [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
- # 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 的都一致.
- -> [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.
来源: https://www.cnblogs.com/flhs/p/12945406.html