一,简介
我们知道默认情况下容器的数据都是非持久化的,在容器消亡以后数据也跟着丢失,所以 Docker 提供了 Volume 机制以便将数据持久化存储。类似的,Kubernetes 提供了更强大的 Volume 机制和丰富的插件,解决了容器数据持久化和容器间共享数据的问题。
与 Docker 不同,Kubernetes Volume 的生命周期与 Pod 绑定容器挂掉后 Kubelet 再次重启容器时,Volume 的数据依然还在而 Pod 删除时,Volume 才会清理。数据是否丢失取决于具体的 Volume 类型,比如 emptyDir 的数据会丢失,而 PV 的数据则不会丢
1,volume类型
目前kubernetes支持一下volume类型:
注意,这些 volume 并非全部都是持久化的,比如 emptyDir、secret、gitRepo 等,这些 volume 会随着 Pod 的消亡而消失。
二,示例
1,emptyDir
概念:
emptyDir是最基础的Volume类型,用于存储临时数据的简单空目录。如果Pod设置了emptyDir类型Volume,Pod被分配到Node上时候,会创建emptyDir,只要Pod运行在Node上,emptyDir都会存在(容器挂掉不会导致emptyDir丢失数据),但是如果Pod从Node上被删除(Pod被删除,或者Pod发生迁移),emptyDir也会被删除,并且永久丢失。
面将用emptyDir卷实现在同一pod中两个容器之间的文件共享
[root@k8s-master volumes]# cat pod-volume.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-volume
namespace: default
labels:
app: myapp
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: html
mountPath: /data/
command:
- "/bin/sh"
- "-c"
- "while true; do echo $(date) >>/data/index.html; sleep 2; done"
volumes:
- name: html
emptyDir: {}
查看pod
[root@k8s-master volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-volume 2/2 Running 0 2m13s 10.244.1.74 k8s-node1 <none> <none>
#使用curl 命令查看我们重定向到网页文件的内容
[root@k8s-master volumes]# curl 10.244.1.74
Thu Mar 18 08:26:58 UTC 2021
Thu Mar 18 08:27:00 UTC 2021
Thu Mar 18 08:27:02 UTC 2021
Thu Mar 18 08:27:04 UTC 2021
2,hostPath
概念:
hostPath允许挂载Node上的文件系统到Pod里面去。如果Pod需要使用Node上的文件,可以使用hostPath。在同一个节点上运行并在其hostPath卷中使用相同路径的pod可以看到相同的文件。
hostPath指定的type:
#在node 上创建存储目录
mkdir -p /data/volume
echo "hello" >/data/volume/index.html
[root@k8s-master volumes]# cat pod-volume-hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-volume-hostpath
namespace: default
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
hostPath:
path: /data/volume
type: DirectoryOrCreate
#创建pod
kubectl apply -f pod-volume-hostpath.yaml
[root@k8s-master volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-volume-hostpath 1/1 Running 0 10s 10.244.1.75 k8s-node1 <none> <none>
#访问网页文件
[root@k8s-master volumes]# curl 10.244.1.75
hello
#hostpath类型删除pod后重新创建pod被调度到该node节点上数据依然不会变,如果node节点宕了则存储卷也会删除,数据会消失,
3,NFS
概念:
NFS是Network File System的缩写,即网络文件系统。Kubernetes中通过简单地配置就可以挂载NFS到Pod中,而NFS中的数据是可以永久保存的,同时NFS支持同时写操作。
emptyDir可以提供不同容器间的文件共享,但不能存储;hostPath可以为不同容器提供文件的共享并可以存储,但受制于节点限制,不能跨节点共享;这时需要网络存储 (NAS),即既可以方便存储容器又可以从任何集群节点访问,本文以NFS为例做测试
首先准备一台机器同一局域网的机器做为nfs-server(关闭firewalld.service和selinux)
安装nfs软件
[root@docker-ce ~]# yum install -y nfs-utils
创建共享目录:
mkdir -p /data/volumes
[root@docker-ce ~]# cat /etc/exports
/data/volumes 10.0.0.0/24(rw,no_root_squash)
在node节点上安装nfs-utils
[root@k8s-node2 ~]# yum install -y nfs-utils
创建NFS的pods
[root@k8s-master volumes]# cat volume-nfs.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nfs
namespace: default
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
volumes:
- name: html
nfs:
path: /data/volumes
server: 10.0.0.100
创建pod
[root@k8s-master volumekubectl apply -f volume-nfs.yaml
[root@k8s-master volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-nfs 1/1 Running 0 9s 10.244.1.77 k8s-node1 <none> <none>
去存储节点创建文件:
[root@docker volumes]# cat /data/volumes/index.html
<h1>NFS docker</h1
#然后去访问pod的文件
[root@k8s-master volumes]# curl 10.244.1.77
<h1>NFS docker</h1
#删掉pod后在重建pod后数据依然在但是如果nfs宕了数据依然会丢失。
4,pv && pvc
概念:
PersistentVolume (持久卷, 简称 PV)和Persistent VolumeClaim(持久卷声明,简称 PVC)使得K8s集群具备了存储的逻辑抽象能力,使得在配置Pod的逻辑里可以忽略对实际后台存储技术的配置,而把这项配置的工作交给PV的配置者,即集群的管理者。存储的PV和PVC的这种关系,跟计算的Node和Pod的关系是非常类似的;PV和Node是资源的提供者,根据集群的基础设施变化而变化,由K8s集群管理员配置;而PVC和Pod是资源的使用者,根据业务服务的需求变化而变化,由K8s集群的使用者即服务的管理员来配置。
当集群用户需要在其pod中使用持久化存储时,他们首先创建PVC清单,指定所需要的最低容量要求和访问模式,然后用户将待久卷声明清单提交给Kubernetes API服务器,Kubernetes将找到可匹配的PV并将其绑定到PVC。PVC可以当作pod中的一个卷来使用,其他用户不能使用相同的PV,除非先通过删除PVC绑定来释放。
1,创建pv
准备环境
在nfs存储机器上创建目录
[root@docker ~]# mkdir /data/volumes/v{1..5}
[root@docker ~]# cat /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)
显示正常导出:
[root@docker ~]# exportfs -avr
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
#
[root@docker ~]# showmount -e
Export list for docker:
/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
定义一个nfs的pv
定义pv不能定义在namespace中,应为pv是属于集群级别的资源,同样创建namespace是也不能指定名称空间,这两都是属于集群级别的资源
#创建了5个pv
[root@k8s-master volumes]# cat pv-deom.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
- ReadWriteMany
nfs:
path: /data/volumes/v1
server: 10.0.0.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv002
spec:
capacity:
storage: 8Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
- ReadWriteMany
nfs:
path: /data/volumes/v2
server: 10.0.0.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv003
spec:
capacity:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
- ReadWriteMany
nfs:
path: /data/volumes/v3
server: 10.0.0.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv004
spec:
capacity:
storage: 15Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
- ReadWriteMany
nfs:
path: /data/volumes/v4
server: 10.0.0.100
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv005
spec:
capacity:
storage: 20Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
- ReadWriteMany
nfs:
path: /data/volumes/v5
server: 10.0.0.100
查看pv
[root@k8s-master volumes]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 5Gi RWO,RWX Retain Available 89s
pv002 8Gi RWO,RWX Retain Available 89s
pv003 10Gi RWO,RWX Retain Available 89s
pv004 15Gi RWO,RWX Retain Available 89s
pv005 20Gi RWO,RWX Retain Available 89s
创建pvc
[root@k8s-master volumes]# cat pvc-demo.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 8Gi
---
apiVersion: v1
kind: Pod
metadata:
name: pvc-pod
namespace: default
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
volumes:
- name: html
persistentVolumeClaim:
claimName: mypvc
#创建pvc
[root@k8s-master volumes]# kubectl apply -f pvc-demo.yaml
#查看pvc
[root@k8s-master volumes]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mypvc Bound pv002 8Gi RWO,RWX 18s
[root@k8s-master volumes]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 5Gi RWO,RWX Retain Available 74m
pv002 8Gi RWO,RWX Retain Bound default/mypvc 74m
pv003 10Gi RWO,RWX Retain Available 74m
pv004 15Gi RWO,RWX Retain Available 74m
pv005 20Gi RWO,RWX Retain Available 74m
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
#access modes 使用参考:
https://v1-19.docs.kubernetes.io/docs/concepts/storage/persistent-volumes/