数据卷与持久数据卷
2401字约8分钟
2024-09-29
为什么需要存储卷
容器部署过程中一般有以下三种数据:
- 启动时需要的初始数据,例如配置文件 
- 启动过程中产生的临时数据,该临时数据需要多个容器间共享 
- 启动过程中产生的持久化数据,例如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.13vim 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.htmlvim 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.13vim 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目录下的内容
444PV 动态供给(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  # 查看存储类#修改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: 12Gikubectl 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.yamlQ:PV与PVC什么关系?
A:一对一
Q:PVC与PV怎么匹配的?
A:访问模式和存储容量
Q:容量匹配策略
A:匹配就近的符合的容量(向上)
Q:存储容量是真的用于限制吗?
A:存储容量取决于后端存储,容量字段主要还是用于匹配
1、使用Ingress暴露应用对外访问
2、创建一个configmap,使用环境变量和数据卷方式引用
3、创建一个pv,再创建一个pod使用该pv
4、配置PV自动供给,再创建一个pod使用该pv
注:自由发挥,实现需求即可
