• Kubernetes 存储


    一、EmptyDir

    1、Volume

    1. 在一个Pod使用过程中,会进行很多操作,修改一些文件,安装一些程序等等。

        但当我们重启容器之后,会发现容器往往有回到了初始的状态,所有的修改都丢失了

    2. 除了希望数据不在Pod 重启后丢失,我们有时候也需要在Pod 间共享文件,因此,kubernetes抽象出来Volume 对象来解决这两个文件 

    2、Volume 类型

    Kubernetes 支持的卷类型非常丰富,包括:
            - NFS 文件系统
            - Cephfs 等分布式存储系统
            - awsElasticBlockStore,azureDisk等公有云存储服务
            - emptyDir,configMap,hostPath等kubernetes内置存储类型
            - ISCSI,FC等等 ... ...

    3、EmptyDir

    1. 当Pod 指定到某个节点上时,首先创建的是一个emptyDir 卷,并且只要Pod 在该节点上运行,卷就一直存在。就像它的名称表示的那样,卷最初是空的。尽管Pod中的容器挂载emptyDir卷的路径可能相同也可能不同,但是这些容器都可以读写emptyDir 卷中相同的文件。当Pod因为某些原因被从节点上删除时,enptyDir卷中的数据也会永久删除

    4、创建一个使用EmptyDir的Pod

    1. 创建使用emptyDir 时需要配置两个参数:

            ① Spec.containers.volumeMounts: 设置volume的挂载点

            ② Spec.volumes: 配置volume

    1. $ kubectl apply -f- <<EOF
    2. apiVersion: v1
    3. kind: Pod
    4. metadata:
    5. name: em
    6. spec:
    7. containers:
    8. - image: ubuntu
    9. name: test-container
    10. volumeMounts:
    11. - mountPath: /cache #容器中的/cache目录
    12. name: cache-volume #挂载的是cache-volume,要和volumes中一致
    13. args:
    14. - /bin/sh
    15. - -c
    16. - sleep 30000
    17. volumes: #定义volume
    18. - name: cache-volume #卷名
    19. emptyDir: {} #卷,没有做限制
    20. EOF
    1. $ kubectl get pod em #查看pod是否创建完成
    2. NAME READY STATUS RESTARTS AGE
    3. em 1/1 Running 0 13m
    4. $ kubectl describe pod em | grep -A 1 Mount #查看把那个卷挂载/cache这个目录
    5. Mounts:
    6. '/cache' from 'cache-volume' (rw)
    7. $ kubectl describe pod em | grep -A 4 ^Volume #查看挂载类型等信息
    8. Volumes:
    9. 'cache-volume:'
    10. #卷的类型、意思是:临时的目录共享给了pod的生命周期中
    11. Type: 'EmptyDir' (a temporary directory that shares a pod's lifetime)
    12. Medium:
    13. SizeLimit: #没有限制大小

    参考文档: 卷 | Kubernetes

    2. 如果保持emptyDir 的默认配置,格式如上。若限制emptyDir容量(1G),需要如下配置

    1. emptyDir:
    2. sizeLimit: 1Gi #容量限制为1G
    3. EOF

    参考文档: Volume | Kubernetes

    5、查看EmptyDir 对应目录

    1. 进入对应目录后,可以发现如果在pod中创建一个文件,在这个目录中也可呈现

    1. $ kubectl exec -it em -- /bin/sh #进入pod
    2. # df -h #
    3. Filesystem Size Used Avail Use% Mounted on
    4. overlay 38G 5.7G 30G 16% /
    5. tmpfs 64M 0 64M 0% /dev
    6. /dev/mapper/ubuntu--vg-ubuntu--lv 38G 5.7G 30G 16% /cache #目录大小与根一样
    7. shm 64M 0 64M 0% /dev/shm
    8. tmpfs 3.8G 12K 3.8G 1% /run/secrets/kubernetes.io/serviceaccount
    9. tmpfs 1.9G 0 1.9G 0% /proc/acpi
    10. tmpfs 1.9G 0 1.9G 0% /proc/scsi
    11. tmpfs 1.9G 0 1.9G 0% /sys/firmware
    12. # touch /cache/my.txt #创建文件
    13. # ls /cache
    14. my.txt
    15. # exit #退出容器
    1. $ kubectl get pods em1
    2. NAME READY STATUS RESTARTS AGE
    3. em1 1/1 Running 0 28s
    4. $ kubectl describe pods em1 | grep -A 4 ^Volumes
    5. Volumes:
    6. cache-volume:
    7. Type: EmptyDir (a temporary directory that shares a pod's lifetime)
    8. Medium:
    9. SizeLimit: 1Gi' #大小限制成了1G

    2. emptyDir 的生命周期与Pod一致,如果将pod删除,可以看到对应的目录也不复存在

    6、EmptyDir容量限制

    1. emptyDir 可以进行容量限制,如限制为1G

    1. $ kubectl apply -f- <<EOF
    2. apiVersion: v1
    3. kind: Pod
    4. metadata:
    5. name: em1
    6. spec:
    7. containers:
    8. - image: ubuntu
    9. name: test-container
    10. volumeMounts:
    11. - mountPath: /cache
    12. name: cache-volume
    13. args:
    14. - /bin/sh
    15. - -c
    16. - sleep 30000
    17. volumes:
    18. - name: cache-volume
    19. # 下 2 行区别
    20. emptyDir:
    21. sizeLimit: 1Gi #容量限制为1G
    22. EOF

    2. 进入Pod 查看分配文件夹的大小,可以看到空间是Host存储空间大小,并非1G

    1. $ kubectl exec -it em1 -- /bin/sh #进入容器
    2. # df -h
    3. Filesystem Size Used Avail Use% Mounted on
    4. overlay 38G 5.7G 30G 16% /
    5. tmpfs 64M 0 64M 0% /dev
    6. /dev/mapper/ubuntu--vg-ubuntu--lv 38G 5.7G 30G 16% /cache #显示大小依然没变
    7. shm 64M 0 64M 0% /dev/shm
    8. tmpfs 3.8G 12K 3.8G 1% /run/secrets/kubernetes.io/serviceaccount
    9. tmpfs 1.9G 0 1.9G 0% /proc/acpi
    10. tmpfs 1.9G 0 1.9G 0% /proc/scsi
    11. tmpfs 1.9G 0 1.9G 0% /sys/firmware

    3. 尝试在容器内写入一个2G 的文件

    1. # dd if=/dev/zero of=/cache/test2g bs=1M count=2048 #制作2G的文件
    2. 2048+0 records in
    3. 2048+0 records out
    4. 2147483648 bytes (2.1 GB, 2.0 GiB) copied, 21.5983 s, 99.4 MB/s
    5. # exit #退出容器
    1. $ kubectl get pods em1 #再次查看发现容器运行异常
    2. NAME READY STATUS RESTARTS AGE
    3. em1 0/1 ContainerStatusUnknown 1 11m
    4. '原因容量限制了1G,结果输入的内容超过了1个G,所有容器变为不可用'

    二、hostPath

    1、HostPath

    1. hostPath 卷能将主机节点文件系统上的文件或目录挂载到Pod中

    2. 但比如希望Pod使用一些docker 引擎或系统已经包含的内部程序的时候,

        会使用到这种方式。如以下为kube-proxy 中配置的hostPath

    参考资料: 卷 | Kubernetes

    3. 查看kube-system命名空间的pod的配置

    1. $ kubectl -n kube-system get pod kube-proxy-5w5bz -o yaml|grep -A 12 volume
    2. volumeMounts: #卷的挂载
    3. - mountPath: /var/lib/kube-proxy #将不同的路径挂载到哪
    4. name: kube-proxy
    5. - mountPath: /run/xtables.lock
    6. name: xtables-lock
    7. - mountPath: /lib/modules
    8. name: lib-modules
    9. readOnly: true
    10. - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
    11. name: kube-api-access-ffznd
    12. readOnly: true #只读权限
    13. dnsPolicy: ClusterFirst
    14. enableServiceLinks: true
    15. --
    16. volumes:
    17. - configMap:
    18. defaultMode: 420
    19. name: kube-proxy
    20. name: kube-proxy
    21. - hostPath:
    22. path: /run/xtables.lock
    23. type: FileOrCreate #文件存在或创建
    24. name: xtables-lock
    25. - hostPath:
    26. path: /lib/modules
    27. type: ""
    28. name: lib-modules

     2、创建使用 hostPath 的 Pod

    1. hostPath 配置与 emptyDir类似,但类型需指定为:

            hostPath

            path 参数需要配置为主机上已存在的目录

            type 指定为目录

    1. $ kubectl apply -f- <<EOF
    2. apiVersion: v1
    3. kind: Pod
    4. metadata:
    5. name: hppod
    6. spec:
    7. containers:
    8. - image: ubuntu
    9. name: hp-container
    10. volumeMounts:
    11. - mountPath: /hp-dir #挂载路径:pod中的/hp-dir
    12. name: hp-volume
    13. args:
    14. - /bin/sh
    15. - -c
    16. - sleep 30000
    17. volumes:
    18. - name: hp-volume #卷名
    19. hostPath:
    20. path: /mnt/hostpathdir #主机路径
    21. type: DirectoryOrCreate #目录或创建
    22. EOF
    23. #优点:当不知道工作节点时,会判断目录是否会存在,不存在时会创建
    1. $ kubectl get pods hppod -o wide #查看pod所在位置
    2. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
    3. hppod 1/1 Running 0 32s 172.16.194.75 k8s-worker1
    4. kiosk@k8s-worker1:~$ ls /mnt/ #查看目录已经创建
    5. hostpathdir
    1. $ kubectl exec -it hppod -- /bin/sh
    2. # ls
    3. bin dev home lib lib64 media opt root sbin sys usr
    4. boot etc hp-dir lib32 libx32 mnt proc run srv tmp var
    5. # ls /hp-dir
    6. # touch /hp-dir/test.txt #创建测试文件
    7. # ls /hp-dir
    8. test.txt
    9. kiosk@k8s-worker1:~$ ls /mnt/hostpathdir/ #查看宿主机中文件已经创建
    10. test.txt
    11. kiosk@k8s-worker1:~$ echo test | sudo tee /mnt/hostpathdir/Test.txt #创建文件
    12. test
    13. # ls /hp-dir/ #pod中可以看到文件已经生成
    14. Test.txt test.txt
    15. 无论是在当前pod中,还是在宿主机中,这两个目录实际是映射的关系

    参考文档: 卷 | Kubernetes

                       为容器设置启动时要执行的命令和参数 | Kubernetes

    3、HostPath 的类型

    1. 创建hostPath时,需要指定类型(type)

    2. 如果选择类型不正确,或主机上不存在对应资源(如不存在指定文件夹),

        kubernetes系统将无法继续创建Pod,创建步骤终止。

        Pod状态长时间处于ContainerCreating中

    取值行为
    空字符串(默认)用于向后兼容,这意味着在安装hostPath卷之前不会执行任何检查
    DirectoryOrCreate如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为0755,具有与 kubelet 相同的组合所有权
    Directory在给定路径上必须存在的目录
    FileOrCreate如果在给定路径上什么都不存在,那么将再那里根据需要创建空文件,权限设置为0644,具有与 Kubelet 相同的组合所有权
    File在给定路径上必须存在的文件
    Socket在给定路径上必须存在的UNIX 套接字
    CharDevice在给定路径上必须存在的字符设备
    BlockDevice在给定路径上必须存在的块设备

    3. 方式缺点 

            数据只能在各节点上,如之后pod运行时换了node,数据在另一个node,那么数据就会找不到;实际是从PV和PVC比较常用

    三、PV 和 PVC

    1、PV 和 PVC 概述

    1. PersistentVolume持久卷 (pv) 和 PersistentVolumeClaim持久卷声明 (pvc)是k8s提供的两种API资源,用于抽象存储细节。管理员关注如何通过pv 提供存储功能而无需关注用户如何使用,同样的用户只需要挂载pvc 到容器中而不需要关注存储卷采用何种技术实现

    PV 是集群中由管理员配置的一块存储空间

            它是集群中的资源,就像节点是集群中的资源一样。PV是卷插件,和之前介绍的volumes类似,但他又一个独立于单个Pod的生命周期。PV的后端可以是NFS,ISCSI或者云存储等等

    PVC是用户的存储请求(PVC与Pod绑定)

            它类似于 Pod:Pod消耗节点资源,而PVC消耗PV资源(PV和PVC是映射关系)。Pod可以请求特定级别的资源(CPU和内存),PVC可以请求PV特定的接入模式(读写等)和大小

    2、创建 PV

    1. kind选择PersistentVolume

    2. name命名为PV,在PVC中可调用

    3. capacity 指定 PV 的容量

    4. accessModes 指定访问模式

            ReadWriteOnce:该卷能够以读写模式被加载到一个节点上

            ReadOnlyMany:该卷能够以只读模式加载到多个结点上

            ReadWriteMany:该卷能够以读写模式被多个节点同时加载       

             ReadWriteOncePod:卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC   

    5. persistentVolumeReclaimPolicy 指定PV的回收策略

            Retain(保留),不删除,需要手动回收

            Recycle(回收),基本擦除,类似 rm -rf ,使其可供其他 PVC 申请

            Delete(删除),关联存储将被删除,如Azure Disk 或 OpenStack Cinder 卷

    6. nfs 字段配置 NFS服务器信息,在创建PV前,已搭建完NFS服务器,服务器的IP地址是192.168.147.102,共享的文件夹是/nfs

            PV支持的挂载选项包括 NFS,iSCSI,Cinder卷,CephFS等

    7.创建 NFS

    1. #安装nfs软件包和创建文件目录
    2. kiosk@k8s-master:~$ sudo apt -y install nfs-kernel-server && sudo mkdir /nfs
    3. #exports意思是将谁共享,共享的权限;
    4. #root具有root的权限,root具有root的权限;
    5. #默认是root_squash(root共享、root访问的时候,变成匿名用户,还想让他就是root,所以设置成no_root_squash)
    6. kiosk@k8s-master:~$ echo '/nfs *(rw,no_root_squash)' | sudo tee /etc/exports
    7. /nfs *(rw,no_root_squash)
    8. kiosk@k8s-master:~$ sudo systemctl enable nfs-server #设置开机自启
    9. kiosk@k8s-master:~$ sudo systemctl restart nfs-server #重启服务
    10. kiosk@k8s-master:~$ showmount -e #查看
    11. Export list for k8s-master:
    12. /nfs *

    8. 创建PV

    1. $ kubectl apply -f- <<EOF
    2. apiVersion: v1
    3. kind: PersistentVolume
    4. metadata:
    5. name: mypv
    6. spec:
    7. capacity:
    8. storage: 1Gi
    9. accessModes:
    10. - ReadWriteOnce
    11. persistentVolumeReclaimPolicy: Recycle
    12. nfs:
    13. path: /nfs
    14. server: 192.168.147.102
    15. EOF
    1. $ kubectl get pv #查询PV
    2. NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
    3. mypv 1Gi RWO Recycle Available

    参考文档: 持久卷 | Kubernetes

    3、创建PVC

    1. 创建NFS

    1. $ kubectl apply -f- <<EOF
    2. apiVersion: v1
    3. kind: PersistentVolumeClaim
    4. metadata:
    5. name: mypvc
    6. spec:
    7. accessModes:
    8. - ReadWriteOnce #访问模式要与pv一致
    9. volumeName: mypv #名称也要和PV对上
    10. resources:
    11. requests:
    12. storage: 1Gi #大小
    13. EOF
    1. $ kubectl get pv #查看状态变为Bound,绑定的default命名空间中的mypvc
    2. NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
    3. mypv 1Gi RWO Recycle Bound default/mypvc 25h
    4. $ kubectl get pvc #查看pvc
    5. NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
    6. mypvc Bound mypv 1Gi RWO 2m25s
    7. $ kubectl describe pv #查看pv的pod名称
    8. $ kubectl get pods recycler-for-mypv #查看pod状态
    9. NAME READY STATUS RESTARTS AGE
    10. recycler-for-mypv 0/1 ContainerCreating 0 40s

    2. Kind,类型指定为PVC

    3. accessModes,保持与PV一致

    4. volumeName,使用的PV名称,用于PVC找到正确的PV

    5. requests:指定PV的容量,如果不存在满足该容量需求的PV,则PVC无法绑定任何PV

    6. 创建Pod时,可以使用该方式定义volumes,使用PV 和 PVC

    4、PV 与 PVC 的状态

    1. PV状态,创建完成后为 Available

    2. PVC状态,创建完成后为Pending

    5、PV回收

    1. 由于创建时选择的回收策略时Recycle,删除PVC 的时候kubernetes会删除原有PV的数据。它采用的方式是创建一个回收专用Pod 来完成这一操作

    2. 如果不希望数据被删除,可以配置回收策略为Retain

        这样即使Pod、PVC删除后,PV的数据仍然存在,PV状态如下:

    1. $ kubectl delete pvc mypvc #删除PVC
    2. persistentvolumeclaim "mypvc" deleted
    3. $ kubectl get pods recycler-for-mypv #删除后会自动重建Pod,可使用describe命令查看pod详细信息
    4. NAME READY STATUS RESTARTS AGE
    5. recycler-for-mypv 0/1 ContainerCreating 0 76s
    6. $ kubectl get pv #状态变为可用
    7. NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
    8. mypv 1Gi RWO Recycle Available 8s
    1. $ kubectl apply -f- <<EOF #创建PV
    2. apiVersion: v1
    3. kind: PersistentVolume
    4. metadata:
    5. name: mypv
    6. spec:
    7. capacity:
    8. storage: 1Gi
    9. accessModes:
    10. - ReadWriteOnce
    11. # 只修改 1 行
    12. persistentVolumeReclaimPolicy: Retain #策略改为保留
    13. nfs:
    14. path: /nfs
    15. server: 192.168.147.102
    16. EOF
    1. $ kubectl get pv #策略变为Retain
    2. NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
    3. mypv 1Gi RWO Retain Available 2m19s
    1. $ kubectl apply -f- <<EOF #创建PVC
    2. apiVersion: v1
    3. kind: PersistentVolumeClaim
    4. metadata:
    5. name: mypvc
    6. spec:
    7. accessModes:
    8. - ReadWriteOnce
    9. volumeName: mypv
    10. resources:
    11. requests:
    12. storage: 1Gi
    13. EOF
    1. $ kubectl get pv #PV状态变为Bound
    2. NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
    3. mypv 1Gi RWO Retain Bound default/mypvc 5m
    4. $ kubectl delete pvc mypvc #删除PVC
    5. persistentvolumeclaim "mypvc" deleted
    6. $ kubectl get pv
    7. NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
    8. mypv 1Gi RWO Retain Released default/mypvc 7m2s
    9. '状态变为释放,数据依然保留'

    3. 数据未被删除,但由于PV处于Released状态,依然无法直接被PVC使用。

        这是由于PV保存了之前关联的PVC状态,如需关联新PVC,需要删除其中ClaimRef参数

    6、PV和PVC的绑定

    1. 如果我们重复PV和PVC的实验,将PVC中volumeName:mypv这一参数删除,可以发现PVC扔能申请到PV。

        那么PVC是以什么机制找到匹配的PV呢?

            ①.  PVC首先根据筛选条件,如容量大小和访问模式筛选掉不符合条件的PV

            ②. 筛选掉不符合volumeName的PV

            ③. 筛选掉不符合StorageClass 的 PV

            ④. 根据其他条件筛选符合的 PV

    7、在创建PV 和 PVC 时使用StorageClass

    1. 创建PV 时指定 storageClassName,可以在PVC中申请该PV

    8、动态卷供给

    1. storageClass 除了能够用上述用法之外,主要使用场景是动态供给PV

    2. 由于kubernetes 集群中存在大量的Pod,也就意味着很可能有大量的PV和PVC,如果需要一个一个手工创建无疑是一个巨大的工程,也不符合自动化的特点

    3. 以nfs为例,使用动态供给功能需要完成以下几个步骤:

            ① 创建 nfs-provisiones,provisioner 用于动态创建符合要求的PV

            ② 创建StorageClass,在配置时指定使用的provisioner

            ③ 创建PVC,只需要指定StorageClass,容量及访问模式即可

    4.如果将一个StorageClass标注为default,

       则PVC在申请时可以不指定StorageClass 而默认使用该 defaultStorageClass

     kubectl patch storageclass <存储类名> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

    -p后的参数必须为json格式

  • 相关阅读:
    深入理解开闭原则、里氏替换原则
    数据结构--二叉树-堆(1)
    AR工业远程巡查系统:实时监控设备状态,及时发现潜在问题
    【GB28181】wvp-GB28181-pro修改分屏监控为16画面(前端)
    活动目录(Active Directory)管理工具
    【机器学习】树模型预剪枝和后剪枝
    Redis实战案例及问题分析之redis实现短信登陆
    在线订餐管理系统
    Java网络编程:构建高性能的TCP/IP服务
    威尔士和英格兰同属英国,但为啥还要在世界杯上进行PK?
  • 原文地址:https://blog.csdn.net/qq_41619571/article/details/127046724