zoukankan      html  css  js  c++  java
  • kubernetes-存储卷(十二)

    为了保证数据的持久性,必须保证数据在外部存储在docker容器中,为了实现数据的持久性存储,在宿主机和容器内做映射,可以保证在容器的生命周期结束,数据依旧可以实现持久性存储。但是在k8s中,由于pod分布在各个不同的节点之上,并不能实现不同节点之间持久性数据的共享,并且,在节点故障时,可能会导致数据的永久性丢失。为此,k8s就引入了外部存储卷的功能。

    Volume

    https://kubernetes.io/docs/concepts/storage/volumes/

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

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

    k8s的存储类型

    [root@k8s-master ~]# kubectl explain pod.spec.volumes #查看k8s支持的存储类型
    KIND:     Pod
    VERSION:  v1
    
    常用分类:
    emptyDir(临时目录):Pod删除,数据也会被清除,这种存储成为emptyDir,用于数据的临时存储。
    hostPath(宿主机目录映射):
    本地的SAN(iSCSI,FC)、NAS(nfs,cifs,http)存储
    分布式存储(glusterfs,rbd,cephfs)
    云存储(EBS,Azure Disk)
    emptyDir

    一个emptyDir 第一次创建是在一个pod被指定到具体node的时候,并且会一直存在在pod的生命周期当中,正如它的名字一样,它初始化是一个空的目录,pod中的容器都可以读写这个目录,这个目录可以被挂在到各个容器相同或者不相同的的路径下。当一个pod因为任何原因被移除的时候,这些数据会被永久删除。注意:一个容器崩溃了不会导致数据的丢失,因为容器的崩溃并不移除pod.

    emptyDir 磁盘的作用:
    (1)普通空间,基于磁盘的数据存储
    (2)作为从崩溃中恢复的备份点
    (3)存储那些那些需要长久保存的数据,例web服务中的数据
    默认的,emptyDir 磁盘会存储在主机所使用的媒介上,可能是SSD,或者网络硬盘,这主要取决于你的环境。当然,我们也可以将emptyDir.medium的值设置为Memory来告诉Kubernetes 来挂在一个基于内存的目录tmpfs,因为
    tmpfs速度会比硬盘块度了,但是,当主机重启的时候所有的数据都会丢失。

    创建emptyDir示例

    [root@k8s-master1 volume]# vim pod-vol-demo.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-demo
      namespace: default
      labels:
        app: myapp
        tier: frontend
    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: {}
    
    [root@k8s-master1 volume]# kubectl apply -f pod-vol-demo.yaml
    pod/pod-demo configured
    [root@k8s-master1 volume]# kubectl get pod -o wide
    NAME       READY   STATUS    RESTARTS   AGE   IP            NODE            NOMINATED NODE   READINESS GATES
    pod-demo   2/2     Running   0          15m   172.17.32.3   192.168.0.125   <none>           <none>

    在上面,我们定义了2个容器,其中一个容器是输入日期到index.html中,然后验证访问nginx的html是否可以获取日期。以验证两个容器之间挂载的emptyDir实现共享。如下访问验证:

    [root@k8s-node01 ~]# curl 172.17.73.3
    Wed Dec 26 09:03:21 UTC 2018
    Wed Dec 26 09:03:23 UTC 2018
    Wed Dec 26 09:03:25 UTC 2018
    Wed Dec 26 09:03:27 UTC 2018
    Wed Dec 26 09:03:29 UTC 2018
    Wed Dec 26 09:03:31 UTC 2018
    Wed Dec 26 09:03:33 UTC 2018
    Wed Dec 26 09:03:35 UTC 2018
    hostPath

    hostPath宿主机路径,就是把pod所在的宿主机之上的脱离pod中的容器名称空间的之外的宿主机的文件系统的某一目录和pod建立关联关系,在pod删除时,存储数据不会丢失。

    [root@k8s-master1 volume]# vim pod-hostpath-vol.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-vol-hostpath
      namespace: default
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
        - name: html
          hostPath:
            path: /data/pod/volume1
            type: DirectoryOrCreate
    
    [root@k8s-master1 volume]# kubectl apply -f pod-hostpath-vol.yaml
    pod/pod-vol-hostpath created
    [root@k8s-master1 volume]# kubectl get pod -o wide
    NAME               READY   STATUS    RESTARTS   AGE   IP            NODE            NOMINATED NODE   READINESS GATES
    pod-vol-hostpath   1/1     Running   0          39s   172.17.73.3   192.168.0.126   <none>           <none>

    访问测试

    [root@k8s-node02 ~]# echo "test hostpath" > /data/pod/volume1/index.html
    [root@k8s-node02 ~]# curl 172.17.73.3
    test hostpath

    nfs共享存储卷

    nfs使的我们可以挂在已经存在的共享到的我们的Pod中,和emptyDir不同的是,emptyDir会被删除当我们的Pod被删除的时候,但是nfs不会被删除,仅仅是解除挂在状态而已,这就意味着NFS能够允许我们提前对数据进行处理,而且这些数据可以在Pod之间相互传递.并且,nfs可以同时被多个pod挂在并进行读写

    准备nfs服务
    [root@localhost ~]# yum install -y nfs-utils
    [root@localhost ~]# mkdir /data/volumes -p
    [root@localhost ~]# vim /etc/exports
    /data/volumes 192.168.0.0/24(rw,no_root_squash)
    [root@localhost ~]# systemctl start nfs
    [root@localhost ~]# showmount -e
    Export list for localhost.localdomain:
    /data/volumes 192.168.0.0/24
    
    node测试挂载
    [root@k8s-node01 ~]# yum install -y nfs-utils
    [root@k8s-node01 ~]# mount -t nfs 192.168.0.122:/data/volumes /mnt
    [root@k8s-node01 ~]# mount
    . . . . .
    192.168.0.122:/data/volumes on /mnt type nfs4 (rw,relatime,vers=4.1,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.0.125,local_lock=none,addr=192.168.0.122)
    [root@k8s-node01 ~]# umount /mnt
    使用nfs存储卷示例
    [root@k8s-master1 volume]# vim pod-nfs-vol.yaml
    
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-vol-nfs
      namespace: default
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html
      volumes:
        - name: html
          nfs:
            path: /data/volumes
            server: 192.168.0.122
    
    [root@k8s-master1 volume]# kubectl apply -f pod-nfs-vol.yaml
    pod/pod-vol-nfs created
    [root@k8s-master1 volume]# kubectl get pod -o wide
    NAME               READY   STATUS    RESTARTS   AGE   IP            NODE            NOMINATED NODE   READINESS GATES
    pod-vol-hostpath   1/1     Running   0          29m   172.17.73.3   192.168.0.126   <none>           <none>
    pod-vol-nfs        1/1     Running   0          13s   172.17.73.4   192.168.0.126   <none>           <none>
    
    在nfs创建index.html,访问测试
    [root@localhost ~]# cat /data/volumes/index.html 
    <h1>nfs test</h1>
    [root@k8s-node01 ~]# curl 172.17.73.4
    <h1>nfs test</h1>

    PVC和PV的概念

    Kubernetes支持持久卷的存储插件:https://kubernetes.io/docs/concepts/storage/persistent-volumes/

    kubernetes提供那么多存储接口,但是首先kubernetes的各个Node节点能管理这些存储,但是各种存储参数也需要专业的存储工程师才能了解,由此我们的kubernetes管理变的更加复杂的。由此kubernetes提出了PV和PVC的概念,这样开发人员和使用者就不需要关注后端存储是什么,使用什么参数等问题。如下图:

    PersistentVolume(PV)是集群中已由管理员配置的一段网络存储。 集群中的资源就像一个节点是一个集群资源。 PV是诸如卷之类的卷插件,但是具有独立于使用PV的任何单个pod的生命周期。 该API对象捕获存储的实现细节,即NFS,iSCSI或云提供商特定的存储系统。

    PersistentVolumeClaim(PVC)是用户存储的请求。PVC的使用逻辑:在pod中定义一个存储卷(该存储卷类型为PVC),定义的时候直接指定大小,pvc必须与对应的pv建立关系,pvc会根据定义去pv申请,而pv是由存储空间创建出来的。pv和pvc是kubernetes抽象出来的一种存储资源。

    PV是集群中的资源。 PVC是对这些资源的请求,也是对资源的索赔检查。 PV和PVC之间的相互作用遵循这个生命周期:

    Provisioning(配置)---> Binding(绑定)--->Using(使用)---> Releasing(释放) ---> Recycling(回收)
    Provisioning

    这里有两种PV的提供方式:静态或者动态

    静态-->直接固定存储空间:
        集群管理员创建一些 PV。它们携带可供集群用户使用的真实存储的详细信息。 它们存在于Kubernetes API中,可用于消费。

    动态-->通过存储类进行动态创建存储空间:
        当管理员创建的静态 PV 都不匹配用户的 PVC 时,集群可能会尝试动态地为 PVC 配置卷。此配置基于 StorageClasses:PVC 必须请求存储类,并且管理员必须已创建并配置该类才能进行动态配置。 要求该类的声明有效地为自己禁用动态配置。

    Binding

    在动态配置的情况下,用户创建或已经创建了具有特定数量的存储请求和特定访问模式的PersistentVolumeClaim。 主机中的控制回路监视新的PVC,找到匹配的PV(如果可能),并将 PVC 和 PV 绑定在一起。 如果为新的PVC动态配置PV,则循环将始终将该PV绑定到PVC。 否则,用户总是至少得到他们要求的内容,但是卷可能超出了要求。 一旦绑定,PersistentVolumeClaim绑定是排他的,不管用于绑定它们的模式。

    如果匹配的卷不存在,PVC将保持无限期。 随着匹配卷变得可用,PVC将被绑定。 例如,提供许多50Gi PV的集群将不匹配要求100Gi的PVC。 当集群中添加100Gi PV时,可以绑定PVC。

    Using

    Pod使用PVC作为卷。 集群检查声明以找到绑定的卷并挂载该卷的卷。 对于支持多种访问模式的卷,用户在将其声明用作pod中的卷时指定所需的模式。

    一旦用户有声明并且该声明被绑定,绑定的PV属于用户,只要他们需要它。 用户通过在其Pod的卷块中包含PersistentVolumeClaim来安排Pods并访问其声明的PV。

    Releasing

    当用户完成卷时,他们可以从允许资源回收的API中删除PVC对象。 当声明被删除时,卷被认为是“释放的”,但是它还不能用于另一个声明。 以前的索赔人的数据仍然保留在必须根据政策处理的卷上.

    Reclaiming

    PersistentVolume的回收策略告诉集群在释放其声明后,该卷应该如何处理。 目前,卷可以是保留,回收或删除。 保留可以手动回收资源。 对于那些支持它的卷插件,删除将从Kubernetes中删除PersistentVolume对象,以及删除外部基础架构(如AWS EBS,GCE PD,Azure Disk或Cinder卷)中关联的存储资产。 动态配置的卷始终被删除

    Recycling

    如果受适当的卷插件支持,回收将对卷执行基本的擦除(rm -rf / thevolume / *),并使其再次可用于新的声明。

    静态创建nfs类型的pv示例
    创建pv
    [root@k8s-master1 volume]# vim pv.yaml 
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: my-pv
    spec:
      capacity:
        storage: 5Gi
      accessModes:
        - ReadWriteMany
      nfs:
        path: /data/volumes/wwwroot
        server: 192.168.0.122
    
        
    [root@k8s-master1 volume]# kubectl get pv
    NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
    my-pv   5Gi        RWX            Retain           Available                                   8s
    
    创建容器应用
    [root@k8s-master1 volume]# cat pod-nfs-pvc.yaml
    apiVersion: apps/v1beta1
    kind: Deployment
    metadata:
      name: nginx-deployment
    spec:
      replicas: 3
      template:
        metadata:
          labels:
            app: 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
    
    ---
    定义pvc:卷需求模板
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: my-pvc
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 5Gi
          
    [root@k8s-master1 volume]# kubectl apply  -f pod-nfs-pvc.yaml
    deployment.apps/nginx-deployment created
    persistentvolumeclaim/my-pvc created
    [root@k8s-master1 volume]# kubectl get pv,pvc        #查看pvc绑定
    NAME                     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE
    persistentvolume/my-pv   5Gi        RWX            Retain           Bound    default/my-pvc                           11m
    
    NAME                           STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    persistentvolumeclaim/my-pvc   Bound    my-pv    5Gi        RWX                           9s
    [root@k8s-master1 volume]# kubectl get pod -o wide
    NAME                                READY   STATUS    RESTARTS   AGE   IP            NODE            NOMINATED NODE   READINESS GATES
    nginx-deployment-57fbd964dc-f5qx9   1/1     Running   0          22s   172.17.32.3   192.168.0.125   <none>           <none>
    nginx-deployment-57fbd964dc-hrlq9   1/1     Running   0          22s   172.17.32.4   192.168.0.125   <none>           <none>
    nginx-deployment-57fbd964dc-qqmh9   1/1     Running   0          22s   172.17.73.3   192.168.0.126   <none>           <none>
    
    访问测试
    [root@localhost volumes]# cat /data/volumes/wwwroot/index.html 
    hello world!
    [root@k8s-node01 ~]# curl 172.17.32.3
    hello world!
    [root@k8s-node01 ~]# curl 172.17.32.4
    hello world!
    [root@k8s-node01 ~]# curl 172.17.73.3
    hello world!

     动态生成nfs类型的pv示例

    Dynamic Provisioning机制工作的核心在于StorageClass的API对象。
    StorageClass声明存储插件,用于自动创建PV。

    参考文档:https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client/deploy/objects

    创建storageclass
    [root@k8s-master1 volume]# vim storageclass-nfs.yaml 
    apiVersion: storage.k8s.io/v1beta1
    kind: StorageClass
    metadata:
      name: managed-nfs-storage
    provisioner: fuseim.pri/ifs
    
    [root@k8s-master1 volume]# kubectl apply -f storageclass-nfs.yaml
    storageclass.storage.k8s.io/managed-nfs-storage created
     创建rbac授权
    [root@k8s-master1 volume]# cat rbac.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: nfs-client-provisioner
    
    ---
    
    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1beta1
    metadata:
      name: nfs-client-provisioner-runner
    rules:
      - apiGroups: [""]
        resources: ["persistentvolumes"]
        verbs: ["get", "list", "watch", "create", "delete"]
      - apiGroups: [""]
        resources: ["persistentvolumeclaims"]
        verbs: ["get", "list", "watch", "update"]
      - apiGroups: ["storage.k8s.io"]
        resources: ["storageclasses"]
        verbs: ["get", "list", "watch"]
      - apiGroups: [""]
        resources: ["events"]
        verbs: ["list", "watch", "create", "update", "patch"]
    
    ---
    
    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1beta1
    metadata:
      name: run-nfs-client-provisioner
    subjects:
      - kind: ServiceAccount
        name: nfs-client-provisioner
        namespace: default
    roleRef:
      kind: ClusterRole
      name: nfs-client-provisioner-runner
      apiGroup: rbac.authorization.k8s.io
    
    [root@k8s-master1 volume]# kubectl apply -f rbac.yaml
    serviceaccount/nfs-client-provisioner created
    clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
    clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created

     运行nfs-client-provisioner

    [root@k8s-master1 volume]# cat deployment-nfs.yaml
    apiVersion: apps/v1beta1 
    kind: Deployment
    metadata:
      name: nfs-client-provisioner
    spec:
      replicas: 1
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: nfs-client-provisioner
        spec:
          imagePullSecrets:
            - name: registry-pull-secret
          serviceAccount: nfs-client-provisioner
          containers:
            - name: nfs-client-provisioner
              image: lizhenliang/nfs-client-provisioner:v2.0.0
              volumeMounts:
                - name: nfs-client-root
                  mountPath: /persistentvolumes
              env:
                - name: PROVISIONER_NAME
                  value: fuseim.pri/ifs
                - name: NFS_SERVER
                  value: 192.168.0.122
                - name: NFS_PATH
                  value: /data/volumes
          volumes:
            - name: nfs-client-root
              nfs:
                server: 192.168.0.122
                path: /data/volumes
                
    [root@k8s-master1 volume]# kubectl apply -f deployment-nfs.yaml 
    deployment.apps/nfs-client-provisioner created
    [root@k8s-master1 volume]# kubectl get storageclass
    NAME                  PROVISIONER      AGE
    managed-nfs-storage   fuseim.pri/ifs   65s
    [root@k8s-master1 volume]# kubectl get pod
    NAME                                    READY   STATUS    RESTARTS   AGE
    nfs-client-provisioner-f69cd5cf-wvwlq   1/1     Running   0          21s
    nginx-deployment-57fbd964dc-f5qx9       1/1     Running   0          7m42s
    nginx-deployment-57fbd964dc-hrlq9       1/1     Running   0          7m42s
    nginx-deployment-57fbd964dc-qqmh9       1/1     Running   0          7m42s
    创建deployment示例
    [root@k8s-master1 volume]# cat deployment-demo.yaml
    apiVersion: apps/v1beta1
    kind: Deployment
    metadata:
      name: nginx-deployment2
    spec:
      replicas: 3
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx
            volumeMounts:
            - name: wwwroot
              mountPath: /usr/share/nginx/html
            ports:
            - containerPort: 80
          volumes:
          - name: wwwroot
            persistentVolumeClaim:
              claimName: my-pvc2
    
    ---
    
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: my-pvc2
    spec:
      accessModes:
        - ReadWriteMany
      storageClassName: managed-nfs-storage
      resources:
        requests:
          storage: 5Gi
          
    [root@k8s-master1 volume]# kubectl apply -f deployment-demo.yaml
    deployment.apps/nginx-deployment2 created
    persistentvolumeclaim/my-pvc2 created
    [root@k8s-master1 volume]# kubectl get pod
    NAME                                    READY   STATUS    RESTARTS   AGE
    nfs-client-provisioner-f69cd5cf-wvwlq   1/1     Running   0          6m14s
    nginx-deployment-57fbd964dc-f5qx9       1/1     Running   0          13m
    nginx-deployment-57fbd964dc-hrlq9       1/1     Running   0          13m
    nginx-deployment-57fbd964dc-qqmh9       1/1     Running   0          13m
    nginx-deployment2-8685f649c9-82zgg      1/1     Running   0          52s
    nginx-deployment2-8685f649c9-tjbdm      1/1     Running   0          52s
    nginx-deployment2-8685f649c9-tkrwq      1/1     Running   0          52s
    [root@k8s-master1 volume]# kubectl get pv,pvc        #查看自动生成my-pvc2
    NAME                                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS          REASON   AGE
    persistentvolume/default-my-pvc2-pvc-c9c9861f-09b4-11e9-b58a-000c298a2b5f   5Gi        RWX            Delete           Bound    default/my-pvc2   managed-nfs-storage            79s
    persistentvolume/my-pv                                                      5Gi        RWX            Retain           Bound    default/my-pvc                                   24m
    
    NAME                            STATUS   VOLUME                                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
    persistentvolumeclaim/my-pvc    Bound    my-pv                                                      5Gi        RWX                                  14m
    persistentvolumeclaim/my-pvc2   Bound    default-my-pvc2-pvc-c9c9861f-09b4-11e9-b58a-000c298a2b5f   5Gi        RWX            managed-nfs-storage   79s
    #查看nfs自动生成的目录
    [root@localhost ~]# ll /data/volumes/
    total 4
    drwxrwxrwx 2 root root  6 Dec 27 16:52 default-my-pvc2-pvc-c9c9861f-09b4-11e9-b58a-000c298a2b5f
    -rw-r--r-- 1 root root 18 Dec 27 09:46 index.html
    drwxr-xr-x 2 root root 24 Dec 27 11:18 wwwroot
  • 相关阅读:
    20209/29
    2020/9/30
    2020/10/1
    ATM测试总结报告
    20201020 千锤百炼软工人
    20201024 千锤百炼软工人
    20201025 千锤百炼软工人
    20201023 千锤百炼软工人
    20201018 千锤百炼软工人
    20201022 千锤百炼软工人
  • 原文地址:https://www.cnblogs.com/yuezhimi/p/10180410.html
Copyright © 2011-2022 走看看