3、Volume

  • 容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。其次,在Pod 中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的 Volume 抽象就很好的解决了这些问题
  • docker 启动时 命令有 restar 为always时 容器崩溃等重新启动不是以干净的状态启动,而是会恢复到原来的状态
  • Kubernetes 中的卷有明确的寿命 —— 与封装它的 Pod 相同。所f以,卷的生命比 Pod 中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当 Pod 不再存在时,卷也将不复存在。也许更重要的是Kubernetes支持多种类型的卷,Pod 可以同时使用任意数量的卷
  • Kubernetes 支持以下类型的卷
    • awsElasticBlockStore azureDisk azureFile cephfs csi downwardAPI emptyDir
    • fc flocker gcePersistentDisk gitRepo glusterfs hostPath iscsi local nfs
    • persistentVolumeClaim projected portworxVolume quobyte rbd scaleIO secret
    • storageos vsphereVolume

3.1、emptyDir

  • 当 Pod 被分配给节点时,首先创建 emptyDir 卷,并且只要该 Pod 在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入 emptyDir 卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时, emptyDir 中的数据将被永久删除

  • 容器崩溃不会从节点中移除Pod,因此emptyDir中的数据在容器崩溃时安全的

  • 相当于这个卷的生命周期和Pod一样,Pod删除了 该Pod的emptyDir也不复存在

  • emptyDir 的用法

    • 暂存空间,例如用于基于磁盘的合并排序
    • 用作长时间计算崩溃恢复时的检查点
    • Web服务器容器提供数据时,保存内容管理器容器提取的文件
  • 资源文件示例

    • apiVersion: v1
      kind: Pod
      metadata:
      name: empty-dir-pod
      spec:
      containers:
      - image: nginx
      name: nginx-container
      imagePullPolicy: IfNotPresent
      # 选择Pod的卷 并将其挂载至容器内某个位置
      volumeMounts:
      - mountPath: /cache
      name: cache-volume
      - image: centos
      name: centos-container
      imagePullPolicy: IfNotPresent
      # 添加容器启动命令 防止容器重启
      command: [ "ping", "8.8.8.8" ]
      # 选择Pod的卷 并将其挂载至容器内某个位置
      volumeMounts:
      - mountPath: /test
      name: cache-volume
      # 声明空卷
      volumes:
      - name: cache-volume
      emptyDir: {}
    • # 启动pod 并查看 pod
      [root@k8smaster volume]# kubectl apply -f empty-dir-pod.yaml
      pod/empty-dir-pod created
      [root@k8smaster volume]# kubectl get pod -o wide
      NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
      empty-dir-pod 2/2 Running 0 16s 10.244.2.102 k8snode1 <none> <none> # 进入该pod的第一个容器的挂载目录新建a.txt
      [root@k8smaster volume]# kubectl exec -it empty-dir-pod -c nginx-container -- /bin/sh
      # pwd
      /
      # cd /cache
      # ls
      # touch a.txt
      # ls
      a.txt
      # exit # 进入该pod的第二个容器的挂载目录并查看 发现存在a.txt
      [root@k8smaster volume]# kubectl exec -it empty-dir-pod -c centos-container -- /bin/sh
      sh-4.4# pwd
      /
      sh-4.4# cd /test
      sh-4.4# ls
      a.txt
      sh-4.4# exit

3.2、hostPath

  • hostPath 卷将主机节点的文件系统中的文件或目录挂载到集群中

  • hostPath 的用途如下

    • 运行需要访问 Docker 内部的容器;使用 /var/lib/docker 的 hostPath
    • 在容器中运行 cAdvisor;使用 /dev/cgroups 的 hostPath
    • 允许 pod 指定给定的 hostPath 是否应该在 pod 运行之前存在,是否应该创建,以及它应该以什么形式存在
  • 除了所需的 path 属性之外,用户还可以为 hostPath 卷指定 type

    • 行为
      空字符串(默认)用于向后兼容,这意味着在挂载 hostPath 卷之前不会执行任何检查
      DirectoryOrCreate 如果在给定的路径上没有任何东西存在,那么将根据需要在那里创建一个空目录,权限设置为 0755,与 Kubelet 具有相同的组和所有权
      Directory 给定的路径下必须存在目录
      FileOrCreate 如果在给定的路径上没有任何东西存在,那么会根据需要创建一个空文件,权限设置为 0644,与 Kubelet 具有相同的组和所有权
      File 给定的路径下必须存在文件
      Socket 给定的路径下必须存在 UNIX 套接字
      CharDevice 给定的路径下必须存在字符设备
      BlockDevice 给定的路径下必须存在块设备
  • 使用这种卷类型是请注意

    • 由于每个节点上的文件都不同,具有相同配置(例如从 podTemplate 创建的)的 pod 在不同节点上的行为可能会有所不同,需要保证node节点的挂载目录 下的文件必须要相同,因为Pod会创建在不同的node上,如果目录下的文件不一直,Pod的行为将会发生改变
    • 当 Kubernetes 按照计划添加资源感知调度时,将无法考虑 hostPath 使用的资源
    • 在底层主机上创建的文件或目录只能由 root 写入。您需要在特权容器中以 root 身份运行进程,或修改主机上的文件权限以便写入 hostPath 卷
  • 资源清单示例

    • apiVersion: v1
      kind: Pod
      metadata:
      name: host-path-pod
      spec:
      containers:
      - image: nginx
      name: test-container
      volumeMounts:
      - mountPath: /test-pd
      name: test-volume
      # 声明Pod中的卷
      volumes:
      - name: test-volume
      # 使用主机中目录
      hostPath:
      # 需要保证data目录在每个node必须存在,否则创建失败,因为pod创建在哪个节点上不确定的(目前情况下)
      path: /data
      # data目录必须存在
      type: Directory
    • # 启动pod 并查看 发现该pod在node1上
      [root@k8smaster volume]# kubectl get pod -o wide
      NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
      empty-dir-pod 1/2 CrashLoopBackOff 12 40m 10.244.1.87 k8snode2 <none> <none>
      host-path-pod 1/1 Running 0 66s 10.244.2.77 k8snode1 <none> <none> # 进入node1的 目录操作 date 为当期时间
      [root@k8snode1 ~]# cd /data/
      [root@k8snode1 data]# touch aaa.html
      [root@k8snode1 data]# date > aaa.html
      [root@k8snode1 data]# date >> aaa.html
      [root@k8snode1 data]# cat aaa.html
      Thu Dec 17 18:28:54 CST 2020
      Thu Dec 17 18:29:19 CST 2020 # 进入pod容器内查看 并修改aaa.html
      [root@k8smaster volume]# kubectl exec -it host-path-pod -- /bin/sh
      # cd /test-pd
      # ls
      aaa.html
      # date >> aaa.html
      # cat aaa.html
      Thu Dec 17 18:28:54 CST 2020
      Thu Dec 17 18:29:19 CST 2020
      Thu Dec 17 10:30:55 UTC 2020 # 在node1上查看aaa.html 发现已经修改
      [root@k8snode1 data]# cat aaa.html
      Thu Dec 17 18:28:54 CST 2020
      Thu Dec 17 18:29:19 CST 2020
      Thu Dec 17 10:30:55 UTC 2020

4、PV和PVC

  • PersistentVolume (PV)

    • 是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。 PV 是Volume 之类的卷插件,但具有独立于使用PV的Pod 的生命周期。此 API 对象包含存储实现的细节,即 NFS、iSCSI 或特定于云供应商的存储系统
    • 其他存储资源挂载到k8s集群中
  • PersistentVolumeClaim (PVC)

    • 是用户存储的请求。它与 Pod 相似。Pod 消耗节点资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或 只读多次模式挂载)
    • Pod选择PV的规则,如果有多个满足条件的PV,则会选择一个消耗最小的PV
  • PV分类

    • 静态 pv

      • 集群管理员创建一些 PV。它们带有可供群集用户使用的实际存储的细节。它们存在于 Kubernetes API 中,可用于消费
    • 动态
      • 在云供应商商请求PV,比较费钱和实现难度大
      • 当管理员创建的静态 PV 都不匹配用户的 PersistentVolumeClaim 时,集群可能会尝试动态地为 PVC 创建卷。此配置基于 StorageClasses :PVC 必须请求 [存储类],并且管理员必须创建并配置该类才能进行动态创建。声明该类为 "" 可以有效地禁用其动态配置
      • 要启用基于存储级别的动态存储配置,集群管理员需要启用 API server 上的 DefaultStorageClass [准入控制器]。例如,通过确保 DefaultStorageClass 位于 API server 组件的 --admission-control 标志,使用逗号分隔的有序值列表中,可以完成此操作
  • 绑定

    • master 中的控制环路监视新的 PVC,寻找匹配的 PV(如果可能),并将它们绑定在一起。如果为新的 PVC 动态调配 PV,则该环路将始终将该 PV 绑定到 PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦 PV 和 PVC 绑定后, PersistentVolumeClaim 绑定是排他性的,不管它们是如何绑定的。 PVC 跟PV 绑定是一对一的映射
    • PV和PVC一一对应
  • 持久化卷声明的保护

    • PVC 保护的目的是确保由 pod 正在使用的 PVC 不会从系统中移除,因为如果被移除的话可能会导致数据丢失当启用PVC 保护 alpha 功能时,如果用户删除了一个 pod 正在使用的 PVC,则该 PVC 不会被立即删除。PVC 的删除将被推迟,直到 PVC 不再被任何 pod 使用
    • Pod删除后,PVC和PV还是绑定的 ,防止该POd的数据丢失
  • 持久化卷类型

    • PersistentVolume 类型以插件形式实现。Kubernetes 目前支持以下插件类型

      • GCEPersistentDisk AWSElasticBlockStore AzureFile AzureDisk FC (Fibre Channel)
      • FlexVolume Flocker NFS iSCSI RBD (Ceph Block Device) CephFS
      • Cinder (OpenStack block storage) Glusterfs VsphereVolume Quobyte Volumes
      • HostPath VMware Photon Portworx Volumes ScaleIO Volumes StorageOS
  • 资源清单示例

    • apiVersion: v1
      kind: PersistentVolume
      metadata:
      name: pv0003
      spec:
      # PV申请存储的大小
      capacity:
      storage: 5Gi
      # 卷的模式
      volumeMode: Filesystem
      # 卷访问模式 ReadWriteOnce只允许一个PVC读写
      accessModes:
      - ReadWriteOnce
      # 回收策略
      persistentVolumeReclaimPolicy: Recycle
      # 存储类名 匹配的PV需要有该类名
      storageClassName: slow
      # 其他说明 可不指定
      mountOptions:
      - hard
      - nfsvers=4.1
      nfs:
      # nfs的目录
      path: /tmp
      # 那个服务器
      server: 172.17.0.2

4.1、PV访问模式

  • PersistentVolume 可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个PV 的访问模式都将被设置为该卷支持的特定模式。例如,NFS 可以支持多个读/写客户端,但特定的 NFS PV 可能以只读方式导出到服务器上。每个 PV 都有一套自己的用来描述特定功能的访问模式

    • ReadWriteOnce——该卷可以被单个节点以读/写模式挂载,命令行中RWO
    • ReadOnlyMany——该卷可以被多个节点以只读模式挂载,命令行中ROX
    • ReadWriteMany——该卷可以被多个节点以读/写模式挂载,命令行中RWX
  • 常用插件的访问模式

4.2、PV的回收策略

  • Retain(保留)——手动回收 等待管理员手动回收
  • Recycle(回收)——基本擦除( rm -rf /thevolume/* )删除卷下的内容 最新k8s版本已经废弃
  • Delete(删除)——关联的存储资产(例如 AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 卷)将被删除 关联删除
  • 当前,只有 NFS 和 HostPath 支持回收策略。AWS EBS、GCE PD、Azure Disk 和 Cinder 卷支持删除策略

4.3、PV状态

  • Available(可用)——一块空闲资源还没有被任何声明绑定
  • Bound(已绑定)——卷已经被声明绑定
  • Released(已释放)——声明被删除,但是资源还未被集群重新声明
  • Failed(失败)——该卷的自动回收失败

4.4、StatefulSet和nfs联合使用

  1. 创建nfs服务器(由于限制,我们采用node1作物nfs的服务器)

    • # 安装nfs服务
      yum install -y nfs-common(这个找不到) nfs-utils rpcbind # 创建目录
      mkdir /nfs # 更改目录权限和组 按实际来
      chmod 777 /nfs/
      chown nfsnobody /nfs/ (执行失败) # 创建该文件并写入 可读可写 root权限 同步方式
      cat /etc/exports
      /nfs *(rw,no_root_squash,no_all_squash,sync) # 启动rpcbind和nfs 开机自启 centos8使用 不同版本启动命令不同
      systemctl start rpcbind
      systemctl start nfs-server
      systemctl enable rpcbind
      systemctl enable nfs-server
  2. 安装nfs客户端(所有k8s节点都安装)

    • yum install -y nfs-utils rpcbind

    • 在master节点上测试是否可以挂载

      • # 查看某个服务其可以挂载的目录
        [root@k8smaster volume]# showmount -e 192.168.47.161
        Export list for 192.168.47.161:
        /nfs * # 将192.168.47.161的 nfs目录挂至 /test目录下
        [root@k8smaster /]# mount -t nfs 192.168.47.161:/nfs /test
        [root@k8smaster /]# cd test
        [root@k8smaster test]# ls
        [root@k8smaster test]# touch a.txt # 在192.168.47.161的 nfs目录 查看已经存在了a.txt
        [root@k8snode1 nfs]# ls
        a.txt # 取消挂载,注意取消挂载时需要退出挂载的目录
        [root@k8smaster /]# umount /test
      • 注意:如果挂载的目录(/test)下原来有文件,挂载了之后就只能看见nfs-server中的文件,取消挂载之后又能看见自己的文件,并且nfs-server中文件继续保存

  3. 创建PV

    • 资源清单示例

      • apiVersion: v1
        kind: PersistentVolume
        metadata:
        name: nfspv1
        spec:
        # 申请的内存大小
        capacity:
        storage: 1Gi
        # 访问策略
        accessModes:
        - ReadWriteOnce
        # 回收策略 手动回收
        persistentVolumeReclaimPolicy: Retain
        # 存储类名
        storageClassName: nfs
        # nfs服务
        nfs:
        # nfs-server上的目录
        path: /nfs
        # nfs-server地址
        server: 192.168.47.161
      • # 创建PV并查看
        [root@k8smaster pv]# kubectl apply -f nfspv1.yaml
        persistentvolume/nfspv1 created [root@k8smaster pv]# kubectl get pv -o wide
        NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
        nfspv1 1Gi RWO Retain Available nfs 22s Filesystem
    • 注意:PV创建成功后就可以直接在Pod中挂载,但一般不这么干,结合PVC来使用

  4. 创建StatefulSet和PVC

    • 资源清单示例

      • # headless service stateful 必须要用的
        apiVersion: v1
        kind: Service
        metadata:
        name: nginx
        labels:
        app: nginx
        spec:
        ports:
        - port: 80
        name: web
        clusterIP: None
        selector:
        app: nginx ---
        # StatefulSet的控制器 必须使用无头服务
        apiVersion: apps/v1
        kind: StatefulSet
        metadata:
        name: web
        spec:
        selector:
        matchLabels:
        app: nginx
        # 选择无头服务的名称
        serviceName: "nginx"
        replicas: 3
        template:
        metadata:
        labels:
        app: nginx
        spec:
        containers:
        - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        name: web
        # 该容器挂载的卷
        volumeMounts:
        - name: www
        # 挂载的目录相当于nginx的欢迎目录
        mountPath: /usr/share/nginx/html
        # PVC的模板 格式同 PVC
        volumeClaimTemplates:
        - metadata:
        name: www
        spec:
        # 需要PV的访问策略,也会筛选PV 硬性指标
        accessModes: [ "ReadWriteOnce" ]
        # 需要的类名 该类名去匹配PV 硬性指标
        storageClassName: "nfs"
        resources:
        # 所需空间大小 满足类名 会去选择一个大于该存储中 最小的一个
        requests:
        storage: 1Gi
    • 在node1节点上(也就是nfs-server多创建几个挂载卷,看PVC的选择情况) 本次创建了4个卷

      • # 修改/etc/exports文件 并创建 nfs2,nfs3,nfs4文件夹
        [root@k8snode1 /]# cat /etc/exports
        /nfs *(rw,no_root_squash,no_all_squash,sync)
        /nfs2 *(rw,no_root_squash,no_all_squash,sync)
        /nfs3 *(rw,no_root_squash,no_all_squash,sync)
        /nfs4 *(rw,no_root_squash,no_all_squash,sync) # 重启nfs-server
        systemctl restart rpcbind
        systemctl restart nfs-server # 在其他节点查询挂载点
        [root@k8smaster pv]# showmount -e 192.168.47.161
        Export list for 192.168.47.161:
        /nfs4 *
        /nfs3 *
        /nfs2 *
        /nfs *
      • 创建对应的PV

        • apiVersion: v1
          kind: PersistentVolume
          metadata:
          name: nfspv2
          spec:
          # 申请的内存大小
          capacity:
          storage: 3Gi
          # 访问策略
          accessModes:
          - ReadOnlyMany
          # 回收策略 手动回收
          persistentVolumeReclaimPolicy: Retain
          # 存储类名
          storageClassName: nfs
          # nfs服务
          nfs:
          # nfs-server上的目录
          path: /nfs2
          # nfs-server地址
          server: 192.168.47.161
          ---
          apiVersion: v1
          kind: PersistentVolume
          metadata:
          name: nfspv3
          spec:
          # 申请的内存大小
          capacity:
          storage: 5Gi
          # 访问策略
          accessModes:
          - ReadWriteMany
          # 回收策略 手动回收
          persistentVolumeReclaimPolicy: Retain
          # 存储类名
          storageClassName: nfs
          # nfs服务
          nfs:
          # nfs-server上的目录
          path: /nfs3
          # nfs-server地址
          server: 192.168.47.161
          ---
          apiVersion: v1
          kind: PersistentVolume
          metadata:
          name: nfspv4
          spec:
          # 申请的内存大小
          capacity:
          storage: 1Gi
          # 访问策略
          accessModes:
          - ReadWriteMany
          # 回收策略 手动回收
          persistentVolumeReclaimPolicy: Retain
          # 存储类名(和上述几个不同)
          storageClassName: slow
          # nfs服务
          nfs:
          # nfs-server上的目录
          path: /nfs4
          # nfs-server地址
          server: 192.168.47.161
        • # 查看PV 我们目前一共有四个 PV
          [root@k8smaster pv]# kubectl get pv -o wide
          NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
          nfspv1 1Gi RWO Retain Available nfs 44m Filesystem
          nfspv2 3Gi ROX Retain Available nfs 6m24s Filesystem
          nfspv3 5Gi RWX Retain Available nfs 6m18s Filesystem
          nfspv4 1Gi RWX Retain Available slow 4s Filesystem
    • 创建StatefulSet

      • # 创建StatefulSet
        [root@k8smaster pv]# kubectl apply -f StatefulSet.yaml
        service/nginx created
        statefulset.apps/web created # 查看 svc
        [root@k8smaster pv]# kubectl get svc -o wide
        NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
        kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16h <none>
        nginx ClusterIP None <none> 80/TCP 69s app=nginx # 查看 statefulset 发现只启动了一个Pod
        [root@k8smaster pv]# kubectl get statefulset -o wide
        NAME READY AGE CONTAINERS IMAGES
        web 1/3 93s nginx nginx # 查看 Pod 发现第二个是挂起
        [root@k8smaster pv]# kubectl get pod -o wide
        NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
        web-0 1/1 Running 0 2m4s 10.244.1.88 k8snode2 <none> <none>
        web-1 0/1 Pending 0 119s <none> <none> <none> <none> # 查看PVC 只有一个选择了 PV 绑定了 nfspv1
        [root@k8smaster pv]# kubectl get pvc -o wide
        NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
        www-web-0 Bound nfspv1 1Gi RWO nfs 3m50s Filesystem
        www-web-1 Pending nfs 3m46s Filesystem # 查看PV nfspv1 的状态已经绑定 PVC的名称是 www-web-0(这是根据PVC的选择而决定选择哪个PV)
        [root@k8smaster pv]# kubectl get pv -o wide
        NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
        nfspv1 1Gi RWO Retain Bound default/www-web-0 nfs 68m Filesystem
        nfspv2 3Gi ROX Retain Available nfs 30m Filesystem
        nfspv3 5Gi RWX Retain Available nfs 30m Filesystem
        nfspv4 1Gi RWX Retain Available slow 24m Filesystem # 查看被挂起Pod的描述,发现是选择不到合适的PV,因为我们有三个副本,而满足条件的PV只有一个,所以Pod只启动了一个,剩下的处于挂起状态
        [root@k8smaster pv]# kubectl describe pod web-1
        Events:
        Type Reason Age From Message
        ---- ------ ---- ---- -------
        Warning FailedScheduling <unknown> default-scheduler running "VolumeBinding" filter plugin for pod "web-1": pod has unbound immediate PersistentVolumeClaims
        Warning FailedScheduling <unknown> default-scheduler running "VolumeBinding" filter plugin for pod "web-1": pod has unbound immediate PersistentVolumeClaims
      • 发现第二挂起之后,第三个pod都没有启动,这就说明了stateful中的pod是按顺序启动的,上一个就绪之后,才会启动下一个

  5. 修改PV (nfspv2,nfspv4 的 accessModes 和 storageClassName) 使三个Pod都能正常启动

    • # 直接编辑PV
      [root@k8smaster pv]# kubectl edit pv nfspv2
      persistentvolume/nfspv2 edited
      [root@k8smaster pv]# kubectl edit pv nfspv4
      persistentvolume/nfspv4 edited # 查看PV 修改或的PV都已绑定 为什么nfspv2先被选择? 因为我们先修改的nfspv2,修改完后满足条件的就只有nfspv2 被挂起的PVC就会选择该PV
      NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
      nfspv1 1Gi RWO Retain Bound default/www-web-0 nfs 92m Filesystem
      nfspv2 3Gi RWO Retain Bound default/www-web-1 nfs 54m Filesystem
      nfspv3 5Gi RWX Retain Available nfs 54m Filesystem
      nfspv4 1Gi RWO Retain Bound default/www-web-2 nfs 48m Filesystem # 查看PVC 均已绑定
      [root@k8smaster pv]# kubectl get pvc -o wide
      NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
      www-web-0 Bound nfspv1 1Gi RWO nfs 35m Filesystem
      www-web-1 Bound nfspv2 3Gi RWO nfs 35m Filesystem
      www-web-2 Bound nfspv4 1Gi RWO nfs 3m51s Filesystem # 查看Pod 均已运行
      [root@k8smaster pv]# kubectl get pod -o wide
      NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
      web-0 1/1 Running 0 35m 10.244.1.88 k8snode2 <none> <none>
      web-1 1/1 Running 0 35m 10.244.2.78 k8snode1 <none> <none>
      web-2 1/1 Running 0 4m7s 10.244.2.79 k8snode1 <none> <none> # 查看Pod使用的PVC 和 PVC使用PV
      [root@k8smaster pv]# kubectl describe pod web-0
      ClaimName: www-web-0 # 查看PVC使用PV
      [root@k8smaster pv]# kubectl describe pvc www-web-0
      Name: www-web-0
      Namespace: default
      StorageClass: nfs
      Status: Bound
      Volume: nfspv1
      Labels: app=nginx
      Annotations: pv.kubernetes.io/bind-completed: yes
      pv.kubernetes.io/bound-by-controller: yes
      Finalizers: [kubernetes.io/pvc-protection]
      Capacity: 1Gi
      Access Modes: RWO
      VolumeMode: Filesystem
      Mounted By: web-0
      Events: <none> # 查看PV使用的挂载目录 这样就找见了 我们Pod在PV上的挂载目录
      [root@k8smaster pv]# kubectl describe pv nfspv1
      Name: nfspv1
      Labels: <none>
      Annotations: pv.kubernetes.io/bound-by-controller: yes
      Finalizers: [kubernetes.io/pv-protection]
      StorageClass: nfs
      Status: Bound
      Claim: default/www-web-0
      Reclaim Policy: Retain
      Access Modes: RWO
      VolumeMode: Filesystem
      Capacity: 1Gi
      Node Affinity: <none>
      Message:
      Source:
      Type: NFS (an NFS mount that lasts the lifetime of a pod)
      Server: 192.168.47.161
      Path: /nfs # 修改 192.168.47.161 节点上 /nfs 目录下的内容
      [root@k8snode1 nfs]# echo aaaaa > index.html
      [root@k8snode1 nfs]# cat index.html
      aaaaa # 通过Pod进行访问 获取到了index.html 的内容 ,因为我们挂载的容器类目录就是存放nginx欢迎页的目录 其余Pod都可按此方式测试
      [root@k8smaster pv]# kubectl get pod -o wide
      NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
      web-0 1/1 Running 0 35m 10.244.1.88 k8snode2 <none> <none>
      web-1 1/1 Running 0 35m 10.244.2.78 k8snode1 <none> <none>
      web-2 1/1 Running 0 4m7s 10.244.2.79 k8snode1 <none> <none>
      [root@k8smaster pv]# curl 10.244.1.88
      aaaaa # 删除web-0 Pod(发现Pod的Ip已经改变,但是名称没变,用coredns解析域名方式寻找到的Pod) 再访问发现正常 数据没有丢失
      [root@k8smaster pv]# kubectl delete pod web-0
      pod "web-0" deleted
      [root@k8smaster pv]# kubectl get pod -o wide
      NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
      web-0 1/1 Running 0 3s 10.244.1.89 k8snode2 <none> <none>
      web-1 1/1 Running 0 52m 10.244.2.78 k8snode1 <none> <none>
      web-2 1/1 Running 0 20m 10.244.2.79 k8snode1 <none> <none>
      [root@k8smaster pv]# curl 10.244.1.89
      aaaaa

4.5、关于StatefulSet

  • 匹配 Pod name ( 网络标识 ) 的模式为:$(statefulset名称)-$(序号),比如上面的示例:web-0,web-1,web-2,Pod的命名规则,$(statefulset名称)-$(序号)

  • StatefulSet 为每个 Pod 副本创建了一个 DNS 域名,这个域名的格式为: $(podname).(headless servername),也就意味着服务间是通过Pod域名来通信而非 Pod IP,因为当Pod所在Node发生故障时, Pod 会被飘移到其它 Node 上,Pod IP 会发生变化,但是 Pod 域名不会有变化,用coredns解析域名,需要在Pod中使用,主机不可用

  • StatefulSet 使用 Headless 服务来控制 Pod 的域名,这个域名的 FQDN 为:$(servicename).$(namespace).svc.cluster.local,其中,“cluster.local” 指的是集群的域名,headless service也是通过域名来进行访问的,没有IP,用coredns解析域名,使用dig命令 参考前文service转发

  • 根据 volumeClaimTemplates,为每个 Pod 创建一个 pvc,pvc 的命名规则匹配模式:(volumeClaimTemplates.name)-(pod_name),比如上面的 volumeMounts.name=www, Podname=web-[0-2],因此创建出来的 PVC 是 www-web-0、www-web-1、www-web-2,

  • 删除 Pod 不会删除其 pvc,手动删除 pvc 将自动释放 pv

  • Statefulset的启停顺序

    • 有序部署:部署StatefulSet时,如果有多个Pod副本,它们会被顺序地创建(从0到N-1)并且,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态
    • 有序删除:当Pod被删除时,它们被终止的顺序是从N-1到0
    • 有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态
  • StatefulSet使用场景

    • 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于 PVC 来实现
    • 稳定的网络标识符,即 Pod 重新调度后其 PodName 和 HostName 不变
    • 有序部署,有序扩展,基于 init containers 来实现 , 选择init c的原因是,不会破坏现在的结构
    • 有序收缩
  • 删除上述的Pod和statefulset(删除文件也会删除Pod等)

    • # 查看Pod PV PVC 发现PVC仍然存在 PVC和PV的绑定关系依然存在
      [root@k8smaster pv]# kubectl get pod
      No resources found in default namespace.
      [root@k8smaster pv]# kubectl get pvc -o wide
      NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
      www-web-0 Bound nfspv1 1Gi RWO nfs 81m Filesystem
      www-web-1 Bound nfspv2 3Gi RWO nfs 81m Filesystem
      www-web-2 Bound nfspv4 1Gi RWO nfs 50m Filesystem
      [root@k8smaster pv]# kubectl get pv -o wide
      NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
      nfspv1 1Gi RWO Retain Bound default/www-web-0 nfs 141m Filesystem
      nfspv2 3Gi RWO Retain Bound default/www-web-1 nfs 104m Filesystem
      nfspv3 5Gi RWX Retain Available nfs 103m Filesystem
      nfspv4 1Gi RWO Retain Bound default/www-web-2 nfs 97m Filesystem # 删除所有的PVC 查看PV 发现PV的状态为Released状态 声明被删除,但是资源还未被集群重新声明
      [root@k8smaster pv]# kubectl delete pvc --all
      persistentvolumeclaim "www-web-0" deleted
      persistentvolumeclaim "www-web-1" deleted
      persistentvolumeclaim "www-web-2" deleted
      [root@k8smaster pv]# kubectl get pv -o wide
      NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
      nfspv1 1Gi RWO Retain Released default/www-web-0 nfs 142m Filesystem
      nfspv2 3Gi RWO Retain Released default/www-web-1 nfs 104m Filesystem
      nfspv3 5Gi RWX Retain Available nfs 104m Filesystem
      nfspv4 1Gi RWO Retain Released default/www-web-2 nfs 98m Filesystem
    • 手动删除nfs-server相关目录下的所有文件,发现PV状态还是Released,说明PV并不会检测相关目录下是否有文件,需要我们手动编辑删除绑定者的信息

    • # 编辑PV 删除删除绑定者的信息
      [root@k8smaster pv]# kubectl edit pv nfspv2 # 删除 PV yml中的以下内容
      claimRef:
      apiVersion: v1
      kind: PersistentVolumeClaim
      name: www-web-1
      namespace: default
      resourceVersion: "1553351"
      uid: 44ba4f3e-661b-494d-8080-5a544188dcae # 查看PV 发现nfspv2状态已经是Available
      [root@k8smaster pv]# kubectl get pv -o wide
      NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
      nfspv1 1Gi RWO Retain Released default/www-web-0 nfs 4h25m Filesystem
      nfspv2 3Gi RWO Retain Available nfs 3h48m Filesystem
      nfspv3 5Gi RWX Retain Available nfs 3h47m Filesystem
      nfspv4 1Gi RWO Retain Released default/www-web-2 nfs 3h41m Filesystem

4.6、Pod中使用PVC

  • PVC资源清单示例

    • apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
      name: mypvc
      namespace: default
      spec:
      accessModes: ["ReadWriteMany"]
      resources:
      requests:
      storage: 6Gi
  • Pod的资源清单示例

    • apiVersion: v1
      kind: Pod
      metadata:
      name: vol-pvc
      namespace: default
      spec:
      volumes:
      - name: html
      # 卷挂载方式为PVC
      persistentVolumeClaim:
      # PVC 的名称
      claimName: mypvc
      containers:
      - name: myapp
      image: nginx
      volumeMounts:
      - name: html
      mountPath: /usr/share/nginx/html/

4.k8s存储之Volume、PV、PVC和StatefulSet的更多相关文章

  1. 6.k8s.存储Volume.PV.PVC

    #Volume Volume 解决数据持久化和容器间共享数据 Kubernetes支持几十种类型的后端存储卷 #hostPath挂载实例,挂载Node节点/tmp/test-volume目录到容器/t ...

  2. Kubernetes 存储卷管理 PV&PVC(十)

    目录 一.emptyDir 二.hostPath 三.PV & PVC 1.NFS PersistentVolume 2.创建 PVC 3.创建 Pod 进行挂载 为了持久化保存容器的数据,可 ...

  3. K8s存储卷、pv和pvc的使用

    emptyDIR 临时目录 hostPath :使用主机的路径 网络存储: 传统的设备存储:NAS,SAN 分布式存储:glusterfs,rbd,cephfs 云存储:EBS,Azure,阿里云的 ...

  4. k8-s存储

    原文 https://mp.weixin.qq.com/s/6yg_bt5mYKWdXS0CidY6Rg 从用户角度看,存储就是一块盘或者一个目录,用户不关心盘或者目录如何实现,用户要求非常" ...

  5. k8s的持久化存储PV&&PVC

    1.PV和PVC的引入 Volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足. 拿前面 AWS EBS 的例子来说,要使用 Volume,Pod 必须事先知道如下信息: 当前 Volu ...

  6. K8S系列第九篇(持久化存储,emptyDir、hostPath、PV/PVC)

    更多k8s内容,请关注威信公众好:新猿技术生态圈 一.数据持久化 Pod是由容器组成的,而容器宕机或停止之后,数据就随之丢了,那么这也就意味着我们在做Kubernetes集群的时候就不得不考虑存储的问 ...

  7. k8s存储 pv pvc ,storageclass

    1.  pv  pvc 现在测试 glusterfs  nfs  可读可写, 多个pod绑定到同一个pvc上,可读可写. 2. storageclass  分成两种 (1)  建立pvc, 相当于多个 ...

  8. k8s集群,使用pvc方式实现数据持久化存储

    环境: 系统 华为openEulerOS(CentOS7) k8s版本 1.17.3 master 192.168.1.244 node1 192.168.1.245 介绍: 在Kubernetes中 ...

  9. kubernetes存储类与PV与PVC关系及实践

    StorageClass & PV & PVC关系图 Volumes是最基础的存储抽象,其支持多种类型,包括本地存储.NFS.FC以及众多的云存储,我们也可以编写自己的存储插件来支持特 ...

随机推荐

  1. 基于gin的golang web开发:服务间调用

    微服务开发中服务间调用的主流方式有两种HTTP.RPC,HTTP相对来说比较简单.本文将使用 Resty 包来实现基于HTTP的微服务调用. Resty简介 Resty 是一个简单的HTTP和REST ...

  2. 在iframe中获取另一个iframe中的元素

    $(top.parent.iframeId).contents().find("#selector") //iframeId为iframe的id名称

  3. caffe源码 全连接层

    图示全连接层 如上图所示,该全链接层输入n * 4,输出为n * 2,n为batch 该层有两个参数W和B,W为系数,B为偏置项 该层的函数为F(x) = W*x + B,则W为4 * 2的矩阵,B ...

  4. CSP-S2020复赛游记

    [本文经过删改] 前一个月 没做什么 NOIP 的题,感觉这些题对我这个做黄题封顶的人不是很友好. 前一天 考了场模拟赛,全场最低分 89,感觉信心满满. 退役那天 到了 XJ,发现没人可以面基,想着 ...

  5. 【Codeforces 715C】Digit Tree(点分治)

    Description 程序员 ZS 有一棵树,它可以表示为 \(n\) 个顶点的无向连通图,顶点编号从 \(0\) 到 \(n-1\),它们之间有 \(n-1\) 条边.每条边上都有一个非零的数字. ...

  6. 【Django admin 中文配置】

    打开settings.py文件,找到语言编码.时区的设置项,将内容改为如下: [其中 zh-Hans是简体中文 zh-Hant是繁体中文] LANGUAGE_CODE = 'zh-Hans' # LA ...

  7. 20201207-2 openpyxl 库与模块导入

    1-1 import openpyxl # 通过文件路径,打开工作簿 wb1 = openpyxl.load_workbook('./demo_excel.xlsx') # 用 Workbook() ...

  8. Maven笔记之核心概念及常用命令

    Maven的核心概念 Maven是一款服务于java平台的自动化构建工具. 自动化构建工具还有:make->ant->maven->gradle       1.约定的目录  2.P ...

  9. remmina 软件rdp协议链接windows失败

    remmina 1.42  链接 win10 提示失败......其他版本win还没有测试过. 忘记了在那个论坛有是说加密问题,照着改确实可以.具体原因是默认设置加密方式这一项不知道为什么不起作用,手 ...

  10. SQL精华总结索引类型优化SQL优化事务大表优化思维导图❤️

    索引类型 从数据结构角度: B+树索引, hash索引,基于哈希表实现,只有全值匹配才有效.以链表的形式解决冲突.查找速度非常快 O(1) 全文索引,查找的是文本中的关键词,而不是直接比较索引中的值, ...