持久化存储Volumes、PV、PVC

一.Volumes

Volumes:官方文档   https://kubernetes.io/docs/concepts/storage/volumes/
Volumes:中文文档 https://kubernetes.io/zh/docs/concepts/storage/volumes/

  • Container(容器)中的磁盘文件是短暂的,当容器崩溃时,kubelet会重新启动容器,但最初的文件将丢失,Container会以最干净的状态启动。另外,当一个Pod运行多个Container时,各个容器可能需要共享一些文件。Kubernetes Volume可以解决这两个问题。
  • 一些需要持久化数据的程序才会用到Volumes,或者一些需要共享数据的容器需要volumes。
    Redis-Cluster:nodes.conf
  • 日志收集的需求:需要在应用程序的容器里面加一个sidecar,这个容器是一个收集日志的容器,比如filebeat,它通过pvolumes共享应用程序的日志文件目录。
  • Docker也有卷的概念,但是在Docker中卷只是磁盘上或另一个Container中的目录,其生命周期不受管理。虽然目前Docker已经提供了卷驱动程序,但是功能非常有限,例如从Docker 1.7版本开始,每个Container只允许一个卷驱动程序,并且无法将参数传递给卷。
  • 另一方面,Kubernetes卷具有明确的生命周期,与使用它的Pod相同。因此,在Kubernetes中的卷可以比Pod中运行的任何Container都长,并且可以在Container重启或者销毁之后保留数据。Kubernetes支持多种类型的卷,Pod可以同时使用任意数量的卷。
  • 从本质上讲,卷只是一个目录,可能包含一些数据,Pod中的容器可以访问它。要使用卷Pod需要通过.spec.volumes字段指定为Pod提供的卷,以及使用.spec.containers.volumeMounts 字段指定卷挂载的目录。从容器中的进程可以看到由Docker镜像和卷组成的文件系统视图,卷无法挂载其他卷或具有到其他卷的硬链接,Pod中的每个Container必须独立指定每个卷的挂载位置。
  • 1.emptyDir

    • 和上述volume不同的是,如果删除Pod,emptyDir卷中的数据也将被删除,一般emptyDir卷用于Pod中的不同Container共享数据。它可以被挂载到相同或不同的路径上。
    • 默认情况下,emptyDir卷支持节点上的任何介质,可能是SSD、磁盘或网络存储,具体取决于自身的环境。可以将emptyDir.medium字段设置为Memory,让Kubernetes使用tmpfs(内存支持的文件系统),虽然tmpfs非常快,但是tmpfs在节点重启时,数据同样会被清除,并且设置的大小会被计入到Container的内存限制当中。

    使用emptyDir卷的示例,直接指定emptyDir为{}即可:

    [root@k8s-master01 volumes]# vim nginx-deploy.yaml    //编辑一个deployment
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations:
        deployment.kubernetes.io/revision: "1"
      creationTimestamp: "2020-09-19T02:41:11Z"
      generation: 1
      labels:
        app: nginx
      name: nginx
      namespace: default
    spec:
      progressDeadlineSeconds: 600
      replicas: 2
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: nginx
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: nginx
        spec:
          containers: 
          - image: nginx:1.15.2        
            imagePullPolicy: IfNotPresent
            name: nginx                 //nginx1
            resources: {}
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
            volumeMounts:
            - mountPath: /opt        //挂载的路径/opt 
              name: share-volume     //调用emptyDir的名称
          - image: nginx:1.15.2
            imagePullPolicy: IfNotPresent
            name: nginx2            //nginx2
            command:                //预防同POD端口冲突,设置睡眠
            - sh
            - -c
            - sleep 3600
            resources: {}
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
            volumeMounts:
            - mountPath: /mnt        //挂载的路径/mnt       
              name: share-volume     //调用emptyDir的名称  
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
          volumes:                   //设置volumes:
          - name: share-volume       //设置emptyDir的名称
            emptyDir: {}             //设置emptyDir,指定 {}即可
              #medium: Memory        //可以使用内存做存储,根据实际情况是否启用
    
    [root@k8s-master01 volumes]# kubectl create -f nginx-deploy.yaml   //启动
    deployment.apps/nginx created
    [root@k8s-master01 volumes]# kubectl get pod      //查看成功启动
    NAME                     READY   STATUS    RESTARTS   AGE
    dp-cm-6f98c85ff5-pxhbc   1/1     Running   2          43h
    nginx-67948c7d6b-djwgx   2/2     Running   0          33s
    nginx-67948c7d6b-xg29c   2/2     Running   0          33s
    

    验证:先从1pod中的nginx1容器里面挂载的/opt里面写入数据,然后进入nginx2容器挂载的/mnt目录下查看文件是否存在。

    [root@k8s-master01 volumes]# kubectl exec -it nginx-67948c7d6b-djwgx -c nginx -- bash  //进入nginx1
    root@nginx-67948c7d6b-djwgx:/# cd /opt/
    root@nginx-67948c7d6b-djwgx:/opt# echo '1234qwe' > test.txt
    root@nginx-67948c7d6b-djwgx:/opt# exit
    exit
    
    [root@k8s-master01 volumes]# kubectl exec -it nginx-67948c7d6b-djwgx -c nginx2 -- bash  //进入nginx2
    root@nginx-67948c7d6b-djwgx:/# cd /mnt && cat test.txt
    1234qwe
    

    2.hostPath

    • hostPath卷可将节点上的文件或目录挂载到Pod上,用于Pod自定义日志输出或访问Docker内部的容器等。
      使用hostPath卷的示例。将主机的/data目录挂载到Pod的/test-pd目录:
    [root@k8s-master01 volumes]# vim nginx-deploy.yaml
    ..........   //省略,和上述一致
           volumeMounts:
            - mountPath: /mnt
              name: share-volume
            - mountPath: /etc/timezone    //挂载pod的路径,只设置挂载到nginx2的路径,nginx1没挂载
              name: timezone              //调用hostPath的名称
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
          volumes:
          - name: share-volume
            emptyDir: {}
              #medium: Memory
          - name: timezone        //设置hostPath名称
            hostPath:             
              path: /etc/timezone    //设置宿主机的文件
              type: File             //类型,File表示文件
    

    验证:nginx1原文件,nginx2为挂载的路径

    [root@k8s-master01 volumes]# kubectl replace -f nginx-deploy.yaml 
    deployment.apps/nginx replaced
    
    [root@k8s-master01 volumes]# kubectl exec  nginx-78bcb8886d-rfb69 -c nginx -- cat /etc/timezone  //nginx1原文件
    Etc/UTC
    [root@k8s-master01 volumes]# kubectl exec  nginx-78bcb8886d-rfb69 -c nginx2 -- cat /etc/timezone  //nginx2为挂载的路径
    Asia/Shanghai
    

    hostPath卷常用的type(类型)如下:

    • type为空字符串:默认选项,意味着挂载hostPath卷之前不会执行任何检查。
    • DirectoryOrCreate:如果给定的path不存在任何东西,那么将根据需要创建一个权限为0755的空目录,和Kubelet具有相同的组和权限。
    • Directory:目录必须存在于给定的路径下。
    • FileOrCreate:如果给定的路径不存储任何内容,则会根据需要创建一个空文件,权限设置为0644,和Kubelet具有相同的组和所有权。
    • File:文件,必须存在于给定路径中。
    • Socket:UNIX套接字,必须存在于给定路径中。
    • CharDevice:字符设备,必须存在于给定路径中。
    • BlockDevice:块设备,必须存在于给定路径中。
    
    

    3.nfs挂载

    这边测试挂载到nfs上,如果生产环境推荐用云平台的NAS等高性能存储,nfs受性能影响比较大。
    安装nfs服务器:node01
    安装nfs安装包:其他所有节点,挂载nfs需要识别NFS,装安装包即可,无需配置
    所有节点:

    [root@k8s-node01 ~]# yum -y install nfs-utils  //安装nfs
    

    node01节点:

    [root@k8s-master01 ~]# mkdir -p /data/nfs/test 创建共享路径
    [root@k8s-node01 ~]# systemctl enable --now nfs-server   //开机启动+启动
    [root@k8s-node01 nfs]# vim /etc/exports     //修改配置文件添加其他节点访问权限
    /data/nfs/ 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
    [root@k8s-node01 ~]# systemctl restart nfs-server    //重启服务
    
    回到master01
    [root@k8s-master01 volumes]# mount -t nfs 192.168.1.103:/data/nfs /mnt   //挂载测试
    [root@k8s-master01 mnt]# df -h
    [root@k8s-master01 volumes]# cd /mnt/ && touch 123    //测试正常
    [root@k8s-master01 mnt]#cd ~ && umount /mnt   //测试正常后,退出目录取消挂载
    

    然后挂载到deployment

    [root@k8s-master01 volumes]# vim nginx-deploy.yaml
    ................    //参考上面yaml,省略
          - image: nginx:1.15.2
            imagePullPolicy: IfNotPresent
            name: nginx2
            command:
            - sh
            - -c
            - sleep 3600
            resources: {}
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
            volumeMounts:
            - mountPath: /mnt
              name: share-volume
            - mountPath: /opt       //添加挂载到/opt
              name: nfs-volume      //调用挂载nfs的名称nfs-volume
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
          volumes:
          - name: share-volume
            emptyDir: {}
              #medium: Memory
    
          - name: timezone
            hostPath:
              path: /etc/timezone
              type: File
          - name: nfs-volume        //设置nfs名称
            nfs:                    
              server: 192.168.0.204     //设置挂载的IP路径
              path: /data/nfs/test-dp     //设置挂载的源路径
    

    验证:更新deployment后,进容器查看挂载是否成功,再写入文件测试。

    [root@k8s-master01 volumes]# kubectl replace -f nginx-deploy.yaml 
    deployment.apps/nginx replaced
    
    [root@k8s-master01 volumes]# kubectl exec -it nginx-ddd4487f8-5jdkw -c nginx2  -- bash
    root@nginx-ddd4487f8-5jdkw:/# df -h    //已挂载了
    Filesystem                    Size  Used Avail Use% Mounted on
    overlay                        17G  3.8G   14G  23% /
    tmpfs                          64M     0   64M   0% /dev
    tmpfs                         978M     0  978M   0% /sys/fs/cgroup
    /dev/mapper/centos-root        17G  3.8G   14G  23% /mnt
    192.168.1.103:/data/nfs/test   17G  3.3G   14G  20% /opt
    root@nginx-ddd4487f8-5jdkw:/# cd /opt/
    root@nginx-ddd4487f8-5jdkw:/opt# touch 123
    回到node01查看文件,能正常使用
    [root@k8s-node01 nfs]# cd test/
    [root@k8s-node01 test]# ls
    123
    

    二.Pv&Pvc

    volume无法解决的问题

    • 当某个数据卷不再被挂载使用时,里面数据不好处理。
    • 实现不了设置权限挂载,比如只读挂载。
    • 实现不了只能一个POD挂载。
    • 设置挂载的空间大小

    官方文档:https://kubernetes.io/docs/concepts/storage/persistent-volumes/

    PV:PersistentVolume,简称PV,是由Kubernetes管理员设置的存储,可以配置Ceph、NFS、GlusterFS等常用存储配置,相对于Volume配置,提供了更多的功能,比如生命周期的管理、大小的限制。PV分为静态和动态。

    PVC:PersistentVolumeClaim,简称PVC,是对存储PV的请求,表示需要什么类型的PV,需要存储的技术人员只需要配置PVC即可使用存储,或者Volume配置PVC的名称即可。

    1.Pv的回收策略

    • 1.Retain:保留,该策略允许手动回收资源,当删除PVC时,PV仍然存在,PV被视为已释放,管理员可以手动回收卷。
    • 2.Recycle:回收,如果Volume插件支持,Recycle策略会对卷执行rm -rf清理该PV,并使其可用于下一个新的PVC,但是本策略将来会被弃用,目前只有NFS和HostPath支持该策略。
    • 3.Delete:删除,如果Volume插件支持,删除PVC时会同时删除PV,动态卷默认为Delete,目前支持Delete的存储后端包括AWS EBS, GCE PD, Azure Disk, or OpenStack Cinder等。
    • 可以通过persistentVolumeReclaimPolicy: Recycle字段配置

    2.Pv的访问策略

    官方文档:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes

    • ReadWriteOnce:可以被单节点以读写模式挂载,命令行中可以被缩写为RWO。
    • ReadOnlyMany:可以被多个节点以只读模式挂载,命令行中可以被缩写为ROX。
    • ReadWriteMany:可以被多个节点以读写模式挂载,命令行中可以被缩写为RWX。

    3.创建NFS(NAS)类型和HostPath类型的PV

    按照上述volume的NFS挂载,node01装好nfs,设置好挂载目录,确保其他节点能挂载到NFS服务器。
    yaml配置详解:
    capacity:容量配置

  • volumeMode:卷的模式,目前支持Filesystem(文件系统) 和 Block(块),其中Block类型需要后端存储支持,默认为文件系统
  • accessModes:该PV的访问模式
  • storageClassName:PV的类,一个特定类型的PV只能绑定到特定类别的PVC;
  • persistentVolumeReclaimPolicy:回收策略
  • mountOptions:非必须,新版本中已弃用
  • nfs:NFS服务配置,包括以下两个选项
  • path:NFS上的共享目录
  • server:NFS的IP地址
    [root@k8s-master01 pv]# vim pv-nfs.yaml
    apiVersion: v1
    kind: PersistentVolume      //简称PV
    metadata:
      name: pv-nfs              //pv的资源名称
    spec:
      capacity:
        storage: 5Gi
      volumeMode: Filesystem       //卷的模式,文件系统和块
      accessModes:
        - ReadWriteOnce            //pv的访问模式
      persistentVolumeReclaimPolicy: Recycle    //pv的回收策略
      storageClassName: nfs-slow            //存储类的名称,PVC绑定pv的名称
      mountOptions:
        - hard
        - nfsvers=4.1
      nfs:                           //pv的类型
        path: /data/nfs/test        //nfs的共享目录
        server: 192.168.1.103       //nfs的IP地址
    
    [root@k8s-master01 pv]# kubectl create -f pv-nfs.yaml
    [root@k8s-master01 pv]# kubectl get pv   //查看pv
    NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
    pv-nfs   5Gi        RWO            Recycle          Available           nfs-slow                8s
    

    HostPath类型:把宿主机的目录挂载到PV中。

    [root@k8s-master01 pv]# vim pv-hostpath.yaml
    kind: PersistentVolume
    apiVersion: v1
    metadata:
      name: task-pv-volume
      labels:
        type: local
    spec:
      storageClassName: hostpath
      capacity:
        storage: 10Gi
      accessModes:
        - ReadWriteOnce
      hostPath:
        path: "/mnt/test"
    
    [root@k8s-master01 pv]# kubectl create -f pv-hostpath.yaml     //创建
    persistentvolume/task-pv-volume created
    [root@k8s-master01 pv]# kubectl get pv 
    NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
    pv-nfs           5Gi        RWO            Recycle          Available           nfs-slow                32m
    task-pv-volume   10Gi       RWO            Retain           Available           hostpath                5s
    

    4.pv的状态

  • Available:可用,没有被PVC绑定的空闲资源。
  • Bound:已绑定,已经被PVC绑定。
  • Released:已释放,PVC被删除,但是资源还未被重新使用。
  • Failed:失败,自动回收失败
  • 5.pcv绑定到pv

    a.创建一个PVC,绑定到POD中
    [root@k8s-master01 pv]# vim pvc-nfs.yaml
    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: task-pvc-claim
    spec:
      storageClassName: nfs-slow    //引用pv的storageClassName名称
      accessModes:
        - ReadWriteOnce             //与PV的访问策略一致
      resources:
        requests:
          storage: 3Gi         //小于PV的容量
    
    [root@k8s-master01 pv]# kubectl create -f pvc-nfs.yaml     //创建PVC
    persistentvolumeclaim/task-pvc-claim created
    [root@k8s-master01 pv]# kubectl get pvc      //查看PVC
    NAME             STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    task-pvc-claim   Bound    pv-nfs   5Gi        RWO            nfs-slow       5s
    [root@k8s-master01 pv]# kubectl get pv     //查看PVC绑定到了PV
    NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                    STORAGECLASS   REASON   AGE
    pv-nfs           5Gi        RWO            Recycle          Bound       default/task-pvc-claim   nfs-slow                4d22h
    task-pv-volume   10Gi       RWO            Retain           Available                            hostpath                4d21h
    

    创建一个挂载的POD

    [root@k8s-master01 pv]# vim pvc-nfs-pod.yaml     //创建挂载pod的pvc
    kind: Pod
    apiVersion: v1
    metadata:
      name: task-pv-pod
    spec:
      volumes:
        - name: task-pv-storage    //volume的名称
          persistentVolumeClaim:     //pvc
           claimName: task-pvc-claim     //调用pvc的名称
      containers:
        - name: task-pv-container
          image: nginx
          ports:
            - containerPort: 80
              name: "http-server"
          volumeMounts:
            - mountPath: "/usr/share/nginx/html"    //挂载的路径
              name: task-pv-storage         //上volume的名称
    
    [root@k8s-master01 pv]# kubectl create -f pvc-nfs-pod.yaml 
    pod/task-pv-pod created
    [root@k8s-master01 pv]# kubectl exec -it task-pv-pod -- bash
    root@task-pv-pod:/# df -Th   //进容器查看挂载
    Filesystem                   Type     Size  Used Avail Use% Mounted on
    192.168.1.103:/data/nfs/test nfs4      17G  3.5G   14G  21% /usr/share/nginx/html
    
    [root@k8s-node01 test]# echo '123' > index.html   //nfs的源挂载路径创建index文件测试
    
    root@task-pv-pod:/usr/share/nginx/html# ls      //回到pod中,发现已经创建
    123  index.html
    
    b.绑定pvc到deployment中

    绑定PVC到POD和绑定pvc到deployment类似
    一个是定义spec下的volumes,一个是定义containers下的volumeMounts。
    首先定义挂载pvc的deploy的yaml

    [root@k8s-master01 pv]# vim pvc-nfs-deploy.yaml   
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: nginx
      name: nginx
      namespace: default
    spec:
      replicas: 2
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: nginx
      strategy:
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 0
        type: RollingUpdate
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: nginx
        spec:
          volumes:
          - name: task-pv-storage      //volume名称
            persistentVolumeClaim:     //pvc
              claimName: task-pvc-claim     //pvc的名称
          containers:
          - env:
            - name: TZ
              value: Asia/Shanghai
            - name: LANG
              value: C.UTF-8
            image: nginx
            imagePullPolicy: IfNotPresent
            name: nginx
            volumeMounts:
            - mountPath: "/usr/share/nginx/html"   //挂载路径
              name: task-pv-storage       //pvc的名称
    

    创建deployment,并进入pod验证挂载是否共享。

    [root@k8s-master01 pv]# kubectl create -f pvc-nfs-deploy.yaml 
    deployment.apps/nginx created
    [root@k8s-master01 pv]# kubectl get pod 
    NAME                     READY   STATUS    RESTARTS   AGE
    nginx-66cfc7f7d5-jkmvh   1/1     Running   0          4s
    nginx-66cfc7f7d5-zdk4r   1/1     Running   0          4s
    [root@k8s-master01 pv]# kubectl exec -it nginx-66cfc7f7d5-jkmvh -- bash   //进入第一个pod
    root@nginx-66cfc7f7d5-jkmvh:/# df -Th  //查看挂载
    192.168.1.103:/data/nfs/test nfs4      17G  3.5G   14G  21% /usr/share/nginx/html
    
    root@nginx-66cfc7f7d5-jkmvh:/# cd /usr/share/nginx/html/
    root@nginx-66cfc7f7d5-jkmvh:/usr/share/nginx/html# echo 'dp-123' > index.html  //修改index.html
    root@nginx-66cfc7f7d5-jkmvh:/usr/share/nginx/html# exit   //退出
    exit
    [root@k8s-master01 pv]# kubectl exec -it nginx-66cfc7f7d5-zdk4r -- bash   //进入第二个Pod
    root@nginx-66cfc7f7d5-zdk4r:/# cd /usr/share/nginx/html/
    root@nginx-66cfc7f7d5-zdk4r:/usr/share/nginx/html# cat index.html    //查看再第一个pod修改的文件,说明目录已经共享
    dp-123
    

    6.pvc创建和挂载失败的原因

    a.PVC一直Pending的原因:
  • PVC的空间申请大小大于PV的大小
  • PVC的StorageClassName没有和PV的一致
  • PVC的accessModes和PV的不一致
  • b.挂载PVC的Pod一直处于Pending:
  • PVC没有创建成功/PVC不存在
  • PVC和Pod不在同一个Namespace
  • 暂无评论

    发送评论 编辑评论

    
    				
    |´・ω・)ノ
    ヾ(≧∇≦*)ゝ
    (☆ω☆)
    (╯‵□′)╯︵┴─┴
     ̄﹃ ̄
    (/ω\)
    ∠( ᐛ 」∠)_
    (๑•̀ㅁ•́ฅ)
    →_→
    ୧(๑•̀⌄•́๑)૭
    ٩(ˊᗜˋ*)و
    (ノ°ο°)ノ
    (´இ皿இ`)
    ⌇●﹏●⌇
    (ฅ´ω`ฅ)
    (╯°A°)╯︵○○○
    φ( ̄∇ ̄o)
    ヾ(´・ ・`。)ノ"
    ( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
    (ó﹏ò。)
    Σ(っ °Д °;)っ
    ( ,,´・ω・)ノ"(´っω・`。)
    ╮(╯▽╰)╭
    o(*////▽////*)q
    >﹏<
    ( ๑´•ω•) "(ㆆᴗㆆ)
    😂
    😀
    😅
    😊
    🙂
    🙃
    😌
    😍
    😘
    😜
    😝
    😏
    😒
    🙄
    😳
    😡
    😔
    😫
    😱
    😭
    💩
    👻
    🙌
    🖕
    👍
    👫
    👬
    👭
    🌚
    🌝
    🙈
    💊
    😶
    🙏
    🍦
    🍉
    😣
    Source: github.com/k4yt3x/flowerhd
    颜文字
    Emoji
    小恐龙
    花!
    上一篇
    下一篇