zoukankan      html  css  js  c++  java
  • Kubernetes之持久化Volumes及StorageClass

      Kubernetes 官网对 Volumes的介绍说:On-disk files in a Container are ephemeral, which presents some problems for non-trivial applications when running in Containers. First, when a Container crashes, kubelet will restart it, but the files will be lost - the Container starts with a clean state. Second, when running Containers together in a Pod it is often necessary to share files between those Containers. The Kubernetes Volume abstraction solves both of these problems.

      其意思是:容器中的文件在磁盘上是临时存放的,这给容器中运行的特殊应用程序带来一些问题。 首先,当容器崩溃时,kubelet 将重新启动容器,容器中的文件将会丢失——因为容器会以干净的状态重建。 其次,当在一个 Pod 中同时运行多个容器时,常常需要在这些容器之间共享文件。 Kubernetes 抽象出 Volume 对象来解决这两个问题。

      在 官网的 pod的介绍章节  中也提到,pod内的所有容器共享pod的网络与存储:

    • Networking:Each Pod is assigned a unique IP address. Every container in a Pod shares the network namespace, including the IP address and network ports. Containers inside a Pod can communicate with one another using localhost. When containers in a Pod communicate with entities outside the Pod, they must coordinate how they use the shared network resources (such as ports).
    • Storage:A Pod can specify a set of shared storage Volumes. All containers in the Pod can access the shared volumes, allowing those containers to share data. Volumes also allow persistent data in a Pod to survive in case one of the containers within needs to be restarted. See Volumes for more information on how Kubernetes implements shared storage in a Pod.

    Host类型volume实战:

      其实这里的 volume 跟docker里面的有点像.

    (1)创建资源定义一个Pod,其中包含两个Container,都使用Pod的Volume :volume-pod.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: volume-pod
    spec:
      containers:
      - name: nginx-container
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: volume-pod
          mountPath: /nginx-volume
      - name: busybox-container
        image: busybox
        command: ['sh', '-c', 'echo The app is running! && sleep 3600']
        volumeMounts:
        - name: volume-pod
          mountPath: /busybox-volume
      volumes:
      - name: volume-pod
        hostPath:
          path: /tmp/volume-pod

    (2)查看pod的运行情况 kubectl get pods -o wide

    (3)来到运行的worker节点:

      docker ps | grep volume :查看容器
      ls /tmp/volume-pod :查看该目录下的文件,我这里事先准备了一个文本文件。
      docker exec -it containerid sh :进入容器
      ls /nginx-volume :查看nginx这个容器是否有同步。
      ls /busybox-volume :查看busybox是否同步数据。
      其实我们会发现,这个时候他们已经同时都同步了数据,且实现了数据共享,这个时候在这三个目录下随意更改都会导致其他两个的内容发生变化。

    (4)查看pod中的容器里面的hosts文件,是否一样。发现是一样的,并且都是由pod管理的

    (5)所以一般container中的存储或者网络的内容,不要在container层面修改,而是在pod中修改,比如下面修改一下网络:

    spec:
      hostNetwork: true
      hostPID: true
      hostAliases:
        - ip: "192.168.1.101"
      hostnames:
        - "test.wuzz.com"
      containers:
        - name: nginx-container
        image: nginx

    PersistentVolumes(PV):

      官网 :https://kubernetes.io/docs/concepts/storage/persistent-volumes/

      管理存储与管理计算实例是不同的问题。PersistentVolume子系统为用户和管理员提供了一个API,它从存储的使用方式中抽象出存储提供方式的细节。为此,我们引入了两个新的API资源:PersistentVolume和PersistentVolumeClaim。持久性卷(PV)是集群中的一段存储,由管理员提供或使用存储类动态提供。它是集群中的资源,就像节点是集群资源一样。PV是与卷类似的卷插件,但其生命周期独立于使用PV的任何单独Pod。这个API对象捕获存储的实现细节,无论是NFS、iSCSI还是特定于云提供程序的存储系统。

      PersistentVolumeClaim (PVC)是用户对存储的请求。它类似于pod。pod消耗节点资源,而pvc消耗PV资源。Pods可以请求特定级别的资源(CPU和内存)。索赔可以请求特定的大小和访问模式(例如,它们可以挂载一次读/写或多次只读)。虽然PersistentVolumeClaims允许用户使用抽象的存储资源,但是对于不同的问题,用户通常需要具有不同属性(例如性能)的持久卷。集群管理员需要能够提供各种不同于大小和访问模式的持久性卷,而不需要向用户展示这些卷是如何实现的。对于这些需求,有StorageClass资源。

      说白了,PV是K8s中的资源,volume的plugin实现,生命周期独立于Pod,封装了底层存储卷实现的细节。一个简单的PV的定义如下:

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: my-pv
    spec:
      capacity:
        storage: 5Gi    # 存储空间大小
      volumeMode: Filesystem
      accessModes:
        - ReadWriteOnce     # 只允许一个Pod进行独占式读写操作
      persistentVolumeReclaimPolicy: Recycle
      storageClassName: slow
      mountOptions:
        - hard
        - nfsvers=4.1
      nfs:
        path: /tmp            # 远端服务器的目录
        server: 172.17.0.2    # 远端的服务器

      Kubernetes管理员可以指定附加的挂载选项,以便在节点上挂载持久卷。The following volume types support mount options:

    • AWSElasticBlockStore
    • AzureDisk
    • AzureFile
    • CephFS
    • Cinder (OpenStack block storage)
    • GCEPersistentDisk
    • Glusterfs
    • NFS
    • Quobyte Volumes
    • RBD (Ceph Block Device)
    • StorageOS
    • VsphereVolume
    • iSCSI

    PersistentVolumeClaim(PVC):

      官网 :https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims

      有了PV,那Pod如何使用呢?为了方便使用,我们可以设计出一个PVC来绑定PV,然后把PVC交给Pod来使用即可,每个PVC包含一个规格和状态,这是要求的规格和状态:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: myclaim
    spec:
      accessModes:
        - ReadWriteOnce
      volumeMode: Filesystem
      resources:
        requests:
          storage: 8Gi
      storageClassName: slow
      selector:
        matchLabels:
          release: "stable"
        matchExpressions:
          - {key: environment, operator: In, values: [dev]}

      PVC会匹配满足要求的PV[是根据size和访问模式进行匹配的],进行一一绑定,然后它们的状态都会变成Bound。也就是PVC负责请求PV的大小和访问方式,然后Pod中就可以直接使用PVC咯。

    Pod中如何使用PVC:

      官网 :https://kubernetes.io/docs/concepts/storage/persistent-volumes/#claims-as-volumes

      Pods通过使用声明作为卷访问存储。Claim必须与使用Claim的Pod存在相同的名称空间。集群在Pod的名称空间中找到声明,并使用它获得支持声明的PersistentVolume。然后被安装到host和进入pod。

    apiVersion: v1
    kind: Pod
    metadata:
      name: mypod
    spec:
      containers:
        - name: myfrontend
          image: nginx
          volumeMounts:
          - mountPath: "/var/www/html"
            name: mypd
      volumes:
        - name: mypd
          persistentVolumeClaim:
            claimName: myclaim

    Pod中使用PVC实战:

      使用nginx持久化存储演示

    (1)共享存储使用nfs,我这边只有2台阿里云,比如nfs选择在 master节点
    (2)创建pv和pvc
    (3)nginx pod中使用pvc

    master节点搭建NFS:

      NFS(network file system)网络文件系统,是FreeBSD支持的文件系统中的一种,允许网络中的计算机之间通过TCP/IP网络共享资源。在master节点上搭建一个NFS服务器,目录为/nfs/data

    01 选择master节点作为nfs的server,所以在master节点上
      # 安装nfs 这个最好在w1节点也运行一下
      yum install -y nfs-utils
      # 创建nfs目录
      mkdir -p /nfs/data/
      mkdir -p /nfs/data/mysql
      # 授予权限
      chmod -R 777 /nfs/data
      # 编辑export文件
      vi /etc/exports
      /nfs/data *(rw,no_root_squash,sync)
      # 使得配置生效
      exportfs -r
      # 查看生效
      exportfs
      # 启动rpcbind、nfs服务
      systemctl restart rpcbind && systemctl enable rpcbind
      systemctl restart nfs && systemctl enable nfs
      # 查看rpc服务的注册情况
      rpcinfo -p localhost
      # showmount测试
      showmount -e master-ip
    02 所有node上安装客户端
      yum -y install nfs-utils
      systemctl start nfs && systemctl enable nfs

     创建PV&PVC&Nginx:

    (1)在nfs服务器创建所需要的目录  mkdir -p /nfs/data/nginx
    (2)定义PV,PVC和Nginx的yaml文件 nginx-pv-demo.yaml

    # 定义PV
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: nginx-pv
    spec:
      accessModes:
        - ReadWriteMany
      capacity:
        storage: 2Gi
      nfs:
        path: /nfs/data/nginx
        server: 172.18.113.141
    
    ---
    # 定义PVC,用于消费PV
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: nginx-pvc
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 2Gi
    
    ---
    # 定义Pod,指定需要使用的PVC
    apiVersion: apps/v1beta1
    kind: Deployment
    metadata:
      name: nginx
    spec:
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - image: nginx
            name: nginx
            ports:
            - containerPort: 80
            volumeMounts:
            - name: nginx-persistent-storage
              mountPath: /usr/share/nginx/html
          volumes:
          - name: nginx-persistent-storage
            persistentVolumeClaim:
              claimName: nginx-pvc

    (3)根据yaml文件创建资源并查看资源

      kubectl apply -f nginx-pv-demo.yaml

      kubectl get pv   kubectl get pvc

      kubectl get pods -o wide :查看下pods

      kubectl describe pod nginx-77945f44db-fjbv8 :查看描述

    (4)测试持久化存储:

    01 在/nfs/data/nginx新建文件1.html,写上内容 我这里写入 Hello PVC,
    02 kubectl get pods -o wide  得到nginx-pod的ip地址 如上图是 192.168.190.71。切到w1节点
    03 curl 192.168.190.71/1.html
    04 kubectl exec -it nginx-pod bash  进入/usr/share/nginx/html目录查看
    05 kubectl delete pod nginx-pod
    06 查看新nginx-pod的ip并且访问nginx-pod-ip/1.html

       我们会发现在我们删除后k8s帮我们生成的新的pod内也有这么一个1.html:

       整个流程可以用下图表示:

     

    StorageClass :

      上面手动管理PV的方式还是有点low,能不能更加灵活一点呢?

      官网 :https://kubernetes.io/docs/concepts/storage/storage-classes/

      每个 StorageClass 都包含 provisionerparameters 和 reclaimPolicy 字段, 这些字段会在StorageClass需要动态分配 PersistentVolume 时会使用到。StorageClass 对象的命名很重要,用户使用这个命名来请求生成一个特定的类。 当创建 StorageClass 对象时,管理员设置 StorageClass 对象的命名和其他参数,一旦创建了对象就不能再对其更新。StorageClass声明存储插件,用于自动创建PV。说白了就是创建PV的模板,其中有两个重要部分:PV属性和创建此PV所需要的插件。这样PVC就可以按“Class”来匹配PV。可以为PV指定storageClassName属性,标识PV归属于哪一个Class。

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: standard
    provisioner: kubernetes.io/aws-ebs
    parameters:
      type: gp2
    reclaimPolicy: Retain
    allowVolumeExpansion: true
    mountOptions:
      - debug
    volumeBindingMode: Immediate

      存储分配器:StorageClass 有一个分配器,用来决定使用哪个卷插件分配持久化卷申领。该字段必须指定。其中官方提供的分配器列表如下:

    • 对于PV或者StorageClass只能对应一种后端存储,也就是比如不能既使用 NFS 又使用 aws-ebs
    • 对于手动的情况,一般我们会创建很多的PV,等有PVC需要使用的时候就可以直接使用了,而对于自动的情况,那么就由StorageClass来自动管理创建
    • 如果Pod想要使用共享存储,一般会在创建PVC,PVC中描述了想要什么类型的后端存储、空间等,K8s从而会匹配对应的PV,如果没有匹配成功,Pod就会处于Pending状态。Pod中使用只需要像使用volumes一样,指定名字就可以使用了
    • 一个Pod可以使用多个PVC,一个PVC也可以给多个Pod使用
    • 一个PVC只能绑定一个PV,一个PV只能对应一种后端存储

     

       有了StorageClass之后的PVC可以变成这样

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
    name: test-claim1
    spec:
    accessModes:
        - ReadWriteMany
    resources:
      requests:
        storage: 1Mi
        storageClassName: nfs

      StorageClass之所以能够动态供给PV,是因为Provisioner,也就是Dynamic Provisioning但是NFS这种类型,K8s中默认是没有Provisioner插件的,需要自己创建,但是Github 上给我们提供了这一需求。nfs github :https://github.com/kubernetes-incubator/external-storage/tree/master/nfs

    StorageClass实战:

    (1)准备好NFS服务器[并且确保nfs可以正常工作],创建持久化需要的目录

    path: /nfs/data/wuzz 比如mkdir -p /nfs/data/wuzz

    server: 192.168.1.101

    (2)根据rbac.yaml文件(基于角色的访问控制)创建资源 kubectl apply -f rbac.yaml

    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: nfs-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: ["create", "update", "patch"]
      - apiGroups: [""]
        resources: ["services", "endpoints"]
        verbs: ["get"]
      - apiGroups: ["extensions"]
        resources: ["podsecuritypolicies"]
        resourceNames: ["nfs-provisioner"]
        verbs: ["use"]
    ---
    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: run-nfs-provisioner
    subjects:
      - kind: ServiceAccount
        name: nfs-provisioner
         # replace with namespace where provisioner is deployed
        namespace: default
    roleRef:
      kind: ClusterRole
      name: nfs-provisioner-runner
      apiGroup: rbac.authorization.k8s.io
    ---
    kind: Role
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: leader-locking-nfs-provisioner
    rules:
      - apiGroups: [""]
        resources: ["endpoints"]
        verbs: ["get", "list", "watch", "create", "update", "patch"]
    ---
    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: leader-locking-nfs-provisioner
    subjects:
      - kind: ServiceAccount
        name: nfs-provisioner
        # replace with namespace where provisioner is deployed
        namespace: default
    roleRef:
      kind: Role
      name: leader-locking-nfs-provisioner
      apiGroup: rbac.authorization.k8s.io

    (3)根据deployment.yaml文件创建资源 kubectl apply -f deployment.yaml

      Service account是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: nfs-provisioner
    ---
    kind: Deployment
    apiVersion: extensions/v1beta1
    metadata:
      name: nfs-provisioner
    spec:
      replicas: 1
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            app: nfs-provisioner
        spec:
          serviceAccount: nfs-provisioner
          containers:
            - name: nfs-provisioner
              image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
              volumeMounts:
                - name: nfs-client-root
                  mountPath: /persistentvolumes
              env:
                - name: PROVISIONER_NAME
                  value: example.com/nfs
                - name: NFS_SERVER
                  value: 192.168.1.101 
                - name: NFS_PATH
                  value: /nfs/data/wuzz
          volumes:
            - name: nfs-client-root
              nfs:
                server: 192.168.1.101 
                path: /nfs/data/wuzz

    (4)根据class.yaml创建资源  kubectl apply -f class.yaml

    kind: StorageClass
    apiVersion: storage.k8s.io/v1
    metadata:
      name: example-nfs
    provisioner: example.com/nfs

    (5)根据pvc.yaml创建资源  kubectl apply -f my-pvc.yaml

      kubectl get pvc

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: my-pvc
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 1Mi
      # 这个名字要和上面创建的storageclass名称一致
      storageClassName: example-nfs

    (6)根据nginx-pod创建资源

      kubectl apply -f nginx-pod.yaml

      kubectl exec -it nginx bash

      cd /usr/wuzz # 进行同步数据测试

    kind: Pod
    apiVersion: v1
    metadata:
      name: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
          - name: my-pvc
            mountPath: "/usr/wuzz"
      restartPolicy: "Never"
      volumes:
        - name: my-pvc
          persistentVolumeClaim:
            claimName: my-pvc

    PV的状态和回收策略:

      PV的状态:

    • Available:表示当前的pv没有被绑定
    • Bound:表示已经被pvc挂载
    • Released:pvc没有在使用pv, 需要管理员手工释放pv
    • Failed:资源回收失败

      PV回收策略:

    • Retain:表示删除PVC的时候,PV不会一起删除,而是变成Released状态等待管理员手动清理
    • Recycle:在Kubernetes新版本就不用了,采用动态PV供给来替代
    • Delete:表示删除PVC的时候,PV也会一起删除,同时也删除PV所指向的实际存储空间

      注意 :目前只有NFS和HostPath支持Recycle策略。AWS EBS、GCE PD、Azure Disk和Cinder支持Delete策略

  • 相关阅读:
    Memcached基本架构和思想
    varnish和squid的对比
    常用排序讲解
    数据结构堆的一种比较明白的讲解
    磁盘挂载MOUNT 445问题集
    mysql 如何提高批量导入的速度
    云平台涅槃重生计划
    NumPy、SciPy 等Python包在Windows下的whl安装包下载
    表迁移工具的选型-复制ibd的方法
    下一步的技术研究方向
  • 原文地址:https://www.cnblogs.com/wuzhenzhao/p/12118109.html
Copyright © 2011-2022 走看看