为什么需要存储卷
容器部署过程中一般有以下三种数据:

数据卷概述
数据卷类型大致分类:
-
本地(hostPath,emptyDir等)
-
网络(NFS,Ceph,GlusterFS等)
-
公有云(AWS EBS等)
-
K8S资源(configmap,secret等)
支持的数据劵类型:https://kubernetes.io/docs/concepts/storage/volumes/
数据卷:emptyDir
emptyDir卷:是一个临时存储卷,与Pod生命周期绑定一起,如果 Pod删除了卷也会被删除。
应用场景:Pod中容器之间数据共享
示例:Pod内容器之前共享数据
vim emptyDir.yaml
apiVersion: v1 kind: Pod metadata: name: emptydir-pod spec: containers: - name: write image: centos command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"] volumeMounts: - name: data mountPath: /data - name: read image: centos command: ["bash","-c","tail -f /data/hello"] volumeMounts: - name: data mountPath: /data
volumes: - name: data emptyDir: {}
|
验证查看
kubectl apply -f emptyDir.yaml kubectl get pod kubectl exec -it emptydir-pod -c write -- bash
kubectl exec -it emptydir-pod -c read -- bash
kubectl get pod -o wide
docker ps -l /var/lib/kubelet/pods/53d07406-364b-4d85-90b9-e3a6dca15427/volumes/kubernetes.io~empty-dir/data
|
数据卷:hostPath
hostPath卷:挂载Node文件系统(Pod所在节点)上文件或者目 录到Pod中的容器。
应用场景:Pod中容器需要访问宿主机文件
示例:将宿主机/tmp目录挂载到容器/data目录
vim hostpath.yaml
apiVersion: v1 kind: Pod metadata: name: hostpath-pod spec: containers: - name: busybox image: busybox args: - /bin/sh - -c - sleep 36000 volumeMounts: - name: data mountPath: /data
volumes: - name: data hostPath: path: /tmp type: Directory
|
验证查看
kubectl apply -f hostpath.yaml kubectl get pod -o wide kubectl exec -it hostpath-pod -- sh
在pod所在节点的/tmp目录下创建文件,验证pod中/data目录下能否看见 touch /tmp/xiaozhe.txt
|
数据卷:NFS
NFS数据卷:提供对NFS挂载支持,可以自动将NFS共享 路径挂载到Pod中
NFS:是一个主流的文件共享服务器。

yum install nfs-utils
mkdir -p /nfs/kubernetes
vim /etc/exports /nfs/kubernetes *(rw,no_root_squash)
systemctl start nfs systemctl enable nfs
mount -t nfs 192.168.0.13:/nfs/kubernetes /mnt/
touch /mnt/index.html ls /nfs/kubernetes/
|
示例:将网站程序通过NFS数据卷共享,让所有Pod使用
vim nfs.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nfs-deployment spec: selector: matchLabels: app: nfs-nginx replicas: 3 template: metadata: labels: app: nfs-nginx spec: containers: - name: nginx image: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html ports: - containerPort: 80
volumes: - name: wwwroot nfs: server: 192.168.0.13 path: /nfs/kubernetes
|
验证查看
kubectl apply -f nfs.yaml kubectl get pod -o wide
echo hello > index.html curl 10.244.36.74 hello
|
持久卷概述
PersistentVolume(PV):对存储资源创建和使用的抽象,使得存储作为集群中的资源管理 • PersistentVolumeClaim(PVC):让用户不需要关心具体的Volume实现细节
PV与PVC使用流程

支持持久卷的存储插件:https://kubernetes.io/docs/concepts/storage/persistent-volumes/
vim pv.yaml
apiVersion: v1 kind: PersistentVolume metadata: name: my-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteMany nfs: path: /nfs/kubernetes server: 192.168.0.13
|
vim pvc-deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: pvc-deployment spec: selector: matchLabels: app: pvc-nginx replicas: 3 template: metadata: labels: app: pvc-nginx spec: containers: - name: nginx image: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html ports: - containerPort: 80
volumes: - name: wwwroot persistentVolumeClaim: claimName: my-pvc --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi
|
验证访问
kubectl apply -f pv.yaml kubectl apply -f pvc-deployment.yaml kubectl get pv,pvc kubectl get pod -o wide curl 10.244.169.139 hello
|

PV 生命周期
ACCESS MODES(访问模式):
AccessModes 是用来对 PV 进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:
-
ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
-
ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
-
ReadWriteMany(RWX):读写权限,可以被多个节点挂载
RECLAIM POLICY(回收策略):
目前 PV 支持的策略有三种:
-
Retain(保留): 保留数据,需要管理员手工清理数据
-
Recycle(回收):清除 PV 中的数据,效果相当于执行 rm -rf /ifs/kuberneres/*
-
Delete(删除):与 PV 相连的后端存储同时删除
STATUS(状态):
一个 PV 的生命周期中,可能会处于4中不同的阶段:
-
Available(可用):表示可用状态,还未被任何 PVC 绑定
-
Bound(已绑定):表示 PV 已经被 PVC 绑定
-
Released(已释放):PVC 被删除,但是资源还未被集群重新声明
-
Failed(失败): 表示该 PV 的自动回收失败
现在PV使用方式称为静态供给,需要K8s运维工程师提前创 建一堆PV,供开发者使用。

在nfs服务器共享目录下创建多个目录,供下面引用不同的pv匹配不同的pv目录
cd /nfs/kubernetes/ mkdir pv{2,3,4} cd pv2/ echo 222 >index.html cd ../pv4/ echo 444 >index.html
|
vim pv234.yaml
apiVersion: v1 kind: PersistentVolume metadata: name: pv2 spec: capacity: storage: 3Gi accessModes: - ReadWriteMany nfs: path: /nfs/kubernetes/pv2 server: 192.168.0.13 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv3 spec: capacity: storage: 5Gi accessModes: - ReadWriteMany nfs: path: /nfs/kubernetes/pv3 server: 192.168.0.13 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv4 spec: capacity: storage: 10Gi accessModes: - ReadWriteMany nfs: path: /nfs/kubernetes/pv4 server: 192.168.0.13
|
vim pvc234-deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: pvc234-deployment spec: selector: matchLabels: app: pvc234-nginx replicas: 3 template: metadata: labels: app: pvc234-nginx spec: containers: - name: nginx image: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html ports: - containerPort: 80
volumes: - name: wwwroot persistentVolumeClaim: claimName: pv2 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pv2 spec: accessModes: - ReadWriteMany resources: requests: storage: 8Gi
|
验证查看
kubectl apply -f pv234.yaml kubectl apply -f pvc234-deployment.yaml kubectl get pv,pvc
|

从上面pvc234-deployment.yaml 文件配置可以看到,配置文件指定的pvc是pv2,使用最大容量是8Gi,但是pv2的容量可以看到是3Gi,并不满足你要使用的容量,但是为了尽可能的分配给你,所以它将pv4指定了给你使用,pv4的容量是10Gi。
访问
kubectl get pod -o wide curl 10.244.36.76 444
|
PV 动态供给(StorageClass)
PV静态供给明显的缺点是维护成本太高了!
因此,K8s开始支持PV动态供给,使用StorageClass对象实现。

支持动态供给的存储插件:https://kubernetes.io/docs/concepts/storage/storage-classes/

部署NFS实现自动创建PV插件:
git clone https://github.com/kubernetes-incubator/external-storage cd nfs-client/deploy kubectl apply -f rbac.yaml kubectl apply -f deployment.yaml kubectl apply -f class.yaml
kubectl get sc
|
nfs-client.zip
#修改deployment.yaml 修改里面NFS服务器地址与共享目录

vim sc-deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: sc-deployment spec: selector: matchLabels: app: sc-nginx replicas: 3 template: metadata: labels: app: sc-nginx spec: containers: - name: nginx image: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html ports: - containerPort: 80
volumes: - name: wwwroot persistentVolumeClaim: claimName: nfs-pvc --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-pvc spec: storageClassName: "managed-nfs-storage" accessModes: - ReadWriteMany resources: requests: storage: 12Gi
|
kubectl apply -f sc-deployment.yaml kubectl get pv,pvc
|

从上图可以看出当我们使用kubectl创建一个deployment时,它会请求managed-nfs-storage(nfs存储类),然后managed-nfs-storage调用nfs-client-provisioner插件(pod),帮我们自动创建pv。
访问
cd /nfs/kubernetes/default-nfs-pvc-pvc-2a62f7d8-b356-45d0-87cb-018c10447595 echo sc > index.html kubectl get pod -o wide curl 10.244.169.142 sc
|
删除deployment
kubectl delete -f sc-deployment.yaml
|
在nfs服务器上的共享目录查看



从上面可以看出,nfs的回收策略是deployment删除后端的存储也同时删除,但是当我们把deployment删除之后,数据共享目录还在,并没有删除,它只是帮我们把数据共享目录归档了,如果要删除需要修改class.yaml 配置文件中的archiveOnDelete为false,这时就会帮我们删除后端数据共享目录。

kubectl apply -f class.yaml kubectl delete -f sc-deployment.yaml kubectl apply -f sc-deployment.yaml
cd /nfs/kubernetes/default-nfs-pvc-pvc-d5ca3b6e-7045-4868-8fdf-17063bc19e13 echo 123456 > index.html kubectl get pod -o wide curl 10.244.169.142 123456
kubectl delete -f sc-deployment.yaml
|
Q:PV与PVC什么关系?
A:一对一
Q:PVC与PV怎么匹配的?
A:访问模式和存储容量
Q:容量匹配策略
A:匹配就近的符合的容量(向上)
Q:存储容量是真的用于限制吗?
A:存储容量取决于后端存储,容量字段主要还是用于匹配
1、使用Ingress暴露应用对外访问
2、创建一个configmap,使用环境变量和数据卷方式引用
3、创建一个pv,再创建一个pod使用该pv
4、配置PV自动供给,再创建一个pod使用该pv
注:自由发挥,实现需求即可