为什么需要存储卷

容器部署过程中一般有以下三种数据:

  • 启动时需要的初始数据,例如配置文件

  • 启动过程中产生的临时数据,该临时数据需要多个容器间共享

  • 启动过程中产生的持久化数据,例如MySQL的data目录

数据卷概述

  • Kubernetes中的Volume提供了在容器中挂载外部存储的能力

  • Pod需要设置卷来源(spec.volume)和挂载点(spec.containers.volumeMounts)两个信息后才可以使用相应的Volume

数据卷类型大致分类:

  • 本地(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 #写容器
# ls /data/
kubectl exec -it emptydir-pod -c read -- bash #读容器
# ls /data/
# tail -f /data/hello

#数据目录存放在本地的路径
kubectl get pod -o wide #查看该pod在哪个节点,对应节点查看数据卷目录
#data的存放目录路径
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 #查看该pod所在节点
kubectl exec -it hostpath-pod -- sh
# ls /data/

在pod所在节点的/tmp目录下创建文件,验证pod中/data目录下能否看见
touch /tmp/xiaozhe.txt

数据卷:NFS

NFS数据卷:提供对NFS挂载支持,可以自动将NFS共享 路径挂载到Pod中

NFS:是一个主流的文件共享服务器。

#安装nfs安装包(每个k8s节点都要安装)
yum install nfs-utils

#创建nfs共享目录
mkdir -p /nfs/kubernetes

#修改nfs配置文件
vim /etc/exports
/nfs/kubernetes *(rw,no_root_squash)

#启动nfs并加入开机自启
systemctl start nfs
systemctl enable nfs

#尝试在别的K8s节点挂载nfs共享目录
mount -t nfs 192.168.0.13:/nfs/kubernetes /mnt/

#在/mnt下新建文件,验证在nfs服务器共享目录下能否看到该文件
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

#在nfs服务器上修改nfs的共享目录下index.html里面的内容
echo hello > index.html
curl 10.244.36.74 #访问nfs的任意pod的IP,验证数据是否共享
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 #访问该pod对应的IP
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    #查看该pod对应的IP
curl 10.244.36.76 #可以看到结果是pv4目录下的内容
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 # 授权访问apiserver
kubectl apply -f deployment.yaml # 部署插件,需修改里面NFS服务器地址与共享目录
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" #在创建pvc时指定存储类名称
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。

访问

#在nfs服务器共享目录下新建文件
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 #删除再创建

#再次在nfs服务器共享目录下新建文件
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

#删除deployment后,验证在nfs服务器上查看是否删除了数据共享目录下的pv目录
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

注:自由发挥,实现需求即可