• Kubernetes的故事之持久化存储(十)


    一、Storage

    1.1、Volume

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

     

     通过官网说明大致总结下就是这个volumes在docker中的理解就是我仅仅是通过一个volumes技术可以声名一个变量,然后可以通过这个变量将物理主机的路径和虚拟路径进行一个绑定;简单来说这就是一个持久化技术;在k8s中就可以理解是跟pod的绑定持久化;这块内容的实践在前面的yaml文件中有应用到,有兴趣的可以看前面文章。但这玩意还是有问题的,例如,我应用现在在A节点上,数据持久化也持久化在A节点上,但是,服务迁移后我服务到了B节点上,这时问题就来了。

    1.2、Host类型volume实战

    定义一个Pod,其中包含两个Container,都使用Pod的Volume;pod命名是volume-pod.yml

    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 
    
    
     

    (1)创建资源

    kubectl apply -f volume-pod.yaml

    (2)查看pod的运行情况

    kubectl get pods -o wide

    (3)来到运行的worker节点

    用命令查看容器是否存在

    docker ps | grep volume

    进入docker目录看创建的目录是否存在,会发现nginx-volume和busybox-volume目录是存在的

    docker exec -it containerid sh

    (4)查看pod中的容器里面的hosts文件,是否一样。(将上面两个文件夹里面的东西和宿主机的volume-pod内容对比下就可以了)

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

    1.3 PersistentVolume

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

    这个方案是生产环境推荐的方式;

     前面说的volumes技术是将虚拟盘映射到物理机上,我也说过会有一个问题,那就是系统迁移到另一台服务器上时,虚拟盘和持久盘不在同一个物理主机上,那怎么解决这个问题呢,其实也很简单,我在持久化时不是持久化到物理主机上,而是持久化到一个固定的主机上,然后将固定的主机物理盘做高可用,这样,你虚拟盘怎么浪都可以找到固定的持久化盘位置了。yaml文件如下

    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    # 远端的服务器

    说白了,PV是K8s中的资源,volume的plugin实现,生命周期独立于Pod,封装了底层存储卷实现的细节。

    1.4、PersistentVolumeClaim

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

    有了PV,那Pod如何使用呢?为了方便使用,我们可以设计出一个PVC来绑定PV,然后把PVC交给Pod来使用即可

    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咯。

    1.5、Pod中如何使用PVC

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

    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

    1.6、Pod中使用PVC实战

    场景背景:使用nginx持久化存储演示

    • 共享存储使用nfs,比如选择在m节点
    • 创建pv和pvc
    • nginx pod中使用pvc

    1.6.1 master节点搭建nfs

    在master节点上搭建一个NFS服务器,目录为/nfs/data
    1)选择master节点作为nfs的server,所以在master节点上安装nfs

    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

    2)所有node上安装客户端

    yum -y install nfs-utils
    systemctl start nfs && systemctl enable nfs

    1.6.2 创建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: 121.41.10.13  
        
    ---
    # 定义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: mysql
            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,pvc
    kubectl get pods -o wide

    (4)测试持久化存储

    • 在/nfs/data/nginx新建文件1.html,写上内容
    • kubectl get pods -o wide 得到nginx-pod的ip地址
    • curl nginx-pod-ip/1.html
    • kubectl exec -it nginx-pod bash 进入/usr/share/nginx/html目录查看
    • kubectl delete pod nginx-pod
    • 查看新nginx-pod的ip并且访问nginx-pod-ip/1.html

    1.7、 StorageClass

    上面手动管理PV的方式还是有点low,下面来个更方便的

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

    github:https://github.com/kubernetes-incubator/external-storage/tree/master/nfs

     官网的话简述下意思就是说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,是因为Provisioner,也就是Dynamic Provisioning,但是NFS这种类型,K8s中默认是没有Provisioner插件的,需要自己创建;但我们现在用的就是NFS这种模式,如果NFS不能支持,那我们当面玩的一切的一切就是白玩的,其实我觉得不用太担心,为什么呢,针对开发这种事,总有人愿意挑战,把不可能的事变成可能;下面我在实战中我结合github中大佬提供的NFS插件支持的做法实现上面的理论。

    1.8 StorageClass实战

    github:https://github.com/kubernetes-incubator/external-storage/tree/master/nfs

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

    cd /nfs/data/ghy

    (2)由于创建资源需要APIServer的认证,所以要创建一个帐户跟APIServer交互,所以根据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
    kubectl apply -f rbac.yaml

    (3)根据deployment.yaml文件创建资源,里面会有我们要访问的服务器,大家把里面配置的ip和服务器文件名改成自己的;看这个配置大家也很容易清楚这玩意就是跟NFS服务器进行交互的玩意

    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.0.21  
                - name: NFS_PATH
                  value: /nfs/data/ghy
          volumes:
            - name: nfs-client-root
              nfs:
                server: 192.168.0.21 
                path: /nfs/data/ghy
    kubectl apply -f deployment.yaml

    (4)根据class.yaml创建资源

    kind: StorageClass
    apiVersion: storage.k8s.io/v1
    metadata:
      name: example-nfs
    provisioner: example.com/nfs
    kubectl apply -f class.yaml

    (5)经过前面的步骤,以前我们要创建PV的动作就可以不用了。因为有了storage自动帮我们生成了,接下来我们就应该创建PVC了,但现在又有个问题,那就是PVC不能自动绑定PV,原因就是因为我们现在的方式是不用创建Pv了,pv创建的这个动作由,storage自动帮我们创建,现在我们创建一个PVC然后根据my-pvc.yaml创建资源;

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: my-pvc
    spec:
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 1Mi
      # 这个名字要和上面创建的storageclass名称一致,之所以要一至是因为我们要通过storageclass创建PV,所以要匹配storageclass然后让他动态帮我们创建PV
      storageClassName: example-nfs
    kubectl apply -f my-pvc.yaml
    kubectl get pvc

    (6)经过上面PV和PVC都有了,按照以前的方式就差个Pod了,下面根据nginx-pod.yaml创建资源

    kind: Pod
    apiVersion: v1
    metadata:
      name: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        volumeMounts:
          - name: my-pvc
            mountPath: "/usr/ghy"
      restartPolicy: "Never"
      volumes:
        - name: my-pvc
          persistentVolumeClaim:
            claimName: my-pvc
    kubectl apply -f nginx-pod.yaml
    kubectl exec -it nginx bash

    然后用下面命令修改文件进行验证文件同步问题

    cd /usr/ghy

    上面流程其实总结下可以用下面这张图片总结

    1.9 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策略

  • 相关阅读:
    spring boot 若依系统整合Ueditor,部署时候上传图片错误解决
    JVM学习笔记之栈区
    据说这个是可以撸到2089年的idea2020.2
    小程序监听屏幕滑动事件
    小程序bindinput和bindblur赋值延迟问题解决
    小程序文件下载并保存文件名打开
    数据结构
    Spring JPA 自定义删改
    Spring JPA 查询创建
    Spring JPA 拓展
  • 原文地址:https://www.cnblogs.com/xing1/p/15837432.html
Copyright © 2020-2023  润新知