Volume

发布时间: 更新时间: 总字数:2258 阅读时间:5m 作者: IP上海 分享 网址

Kubernetes 中 Volume 用来储存数据,它被定义在 Pod 上,可以被 Pod 里的多个容器挂载。

介绍

一般存储分分以下几类:

  • SAN: iSCSI, …
  • NAS: NFS, CIFS, …
  • 分布式存储:GlusterFS, Ceph RBD, CephFS, …
  • 云存储:EBS, Cinder Volume, …

Volume 类型

Kubernetes 存储类型包括:

  • emptyDir
  • hostPath
  • persistentVolumeClaim
  • awsElasticBlockStore
  • azureDisk
  • azureFile
  • cephfs
  • cinder
  • configMap
  • csi(Container Storage Interface)
  • ephemeral
  • fc
  • flexVolume
  • flocker
  • gcePersistentDisk
  • gitRepo
  • glusterfs
  • hostPath
  • iscsi
  • nfs
  • photonPersistentDisk
  • portworxVolume
  • quobyte
  • rbd
  • scaleIO
  • secret
  • storageos
  • vsphereVolume

查看帮助:kubectl explain pod.spec.volumes

Volume 架构

kubernetes volume arch

说明:

  • Storage 有 Storage Admin 管理
  • PV 有 Cluster Admin 管理
  • PVC 由 Users and Developers 管理

Volume 生命周期

  • Volume 与 Pod 的生命周期相同,与 Pod 中容器的生命周期不相关,即容器终止或重启时,Volume 中的数据也不会丢失
  • 当 Pod 被删除时,Volume 的数据可能被清理,这与 Volume 的类型相关,其中
    • emptyDir 类型的 Volume 数据会丢失
    • PV 类型的数据则不会丢失

Volume 资源使用

spec:
  volumes:
    ...
  containers:
    volumeMounts:
      ...

emptyDir

emptyDir 是一个空目录,它的生命周期和所属的 Pod 是完全一致的。emptyDir 类型的 Volume 在 Pod 分配到 Node 上时会被创建,Kubernetes 会在 Node 上自动分配一个目录或内存。这个目录的初始内容为空,当 Pod 从 Node 上移除(Pod 被删除或者 Pod 发生迁移)时,emptyDir 中的数据会被永久删除。

  • pod-emptyDir-vol.yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-ed-pod
  namespace: default
spec:
  containers:
  - name: nginx
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: cache-v1
      mountPath: /cache
  volumes:
  - name: cache-v1
    emptyDir: {}
  • 查看
$ kubectl exec -it volume-ed-pod -- sh
# cat /proc/mounts | grep cache
/dev/sda2 /cache xfs rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota 0 0
$ kubectl describe pod volume-ed-pod
...
Volumes:
  cache-v1:
    Type:       EmptyDir (a temporary directory that shares a pod's lifetime)
    Medium:
    SizeLimit:  <unset>
...

说明:

  • 容器崩溃并不会导致 Pod 被从节点上移除,因此容器崩溃时 emptyDir 卷中的数据是安全的。

hostPath

hostPath 类型的 Volume 允许用户挂载 Node 宿主机上的文件或目录到 Pod 中

  • 由于每个节点上的文件都不同,具有相同配置(例如:从 podTemplate 创建的)的 Pod 在不同节点上的行为可能会有所不同。
  • 在底层主机上创建的文件或目录只能由 root 写入。您需要在特权容器中以 root 身份运行进程,或修改主机上的文件权限才可以写入 hostPath 卷。

场景中:

  • 运行中的容器需要访问 Docker 内部的容器,使用 /var/lib/docker 来做为 hostPath 让容器内应用可以直接访问 Docker 的文件系统。
  • 在容器中运行 cAdvisor,使用 /dev/cgroups 来做为 hostPath。
  • 和 DaemonSet 搭配使用,用来操作主机文件。例如:日志采集方案 FLK 中的 FluentD 就采用这种方式来加载主机的容器日志目录,达到收集本主机所有日志的目的。

下面演示示例:

  • pod-hostpath-vol.yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-hp-pod
  namespace: default
spec:
  containers:
  - name: nginx
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: cache-hp
      mountPath: /cache
  volumes:
  - name: cache-hp
    hostPath:
      path: /data/pod/volume
      type: DirectoryOrCreate

NFS

  • 搭建 NFS 服务器,参考:NFS 环境搭建,并创建共享目录 /data/nfs/volume,域名为:nfs.kb.cx

  • pod-nfs-vol.yaml

apiVersion: v1
kind: Pod
metadata:
  name: volume-nfs-pod
  namespace: default
spec:
  containers:
  - name: nginx
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: cache-nfs
      mountPath: /cache
  volumes:
  - name: cache-nfs
    nfs:
      path: /data/nfs/volume
      server: nfs.kb.cx
  • 查看
$ kubectl describe pod volume-nfs-pod
...
Volumes:
  cache-nfs:
    Type:      NFS (an NFS mount that lasts the lifetime of a pod)
    Server:    nfs.kb.cx
    Path:      /data/nfs/volume
    ReadOnly:  false
...

# 对应的 node 节点
root@k8s-node-1:~# docker inspect id
...
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/95e8a281-79ea-4383-ac1c-6e8914dc468d/volumes/kubernetes.io~nfs/cache-nfs",
                "Destination": "/cache",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
...
root@k8s-node-1:~# ls /var/lib/kubelet/pods/95e8a281-79ea-4383-ac1c-6e8914dc468d/volumes/kubernetes.io~nfs/cache-nfs
root@k8s-node-1:~# cat /proc/mounts | grep nfs.kb.cx
nfs.kb.cx:/data/nfs/volume /var/lib/kubelet/pods/95e8a281-79ea-4383-ac1c-6e8914dc468d/volumes/kubernetes.io~nfs/cache-nfs nfs4 rw,relatime,vers=4.2,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=172.20.0.82,local_lock=none,addr=172.20.0.132 0 0

说明:

  • 使用 NFS 时,kubelet 先将 NFS 共享盘挂载到宿主机,然后 mount 到对用的容器上
  • path 也可以是子目录,且必须在 NFS 中存在的子目录,如在 yaml 中配置 path: /data/nfs/volume/abc 时,挂载情况为:
root@k8s-node-1:~# nfs.kb.cx:/data/nfs/volume/abc /var/lib/kubelet/pods/1d3867a9-7401-4c9f-a0b7-38a3cc67d477/volumes/kubernetes.io~nfs/cache-nfs nfs4 rw,relatime,vers=4.2,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=172.20.0.82,local_lock=none,addr=172.20.0.132 0 0

Local Persistent Volume

Local Persistent Volume(本地持久化存储) 指的就是利用机器上的磁盘来存放业务需要持久化的数据

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: local-test
spec:
  serviceName: "local-service"
  replicas: 3
  selector:
    matchLabels:
      app: local-test
  template:
    metadata:
      labels:
        app: local-test
    spec:
      containers:
      - name: test-container
        image: k8s.gcr.io/busybox
        command:
        - "/bin/sh"
        args:
        - "-c"
        - "sleep 100000"
        volumeMounts:
        - name: local-vol
          mountPath: /usr/test-pod
  volumeClaimTemplates:
  - metadata:
      name: local-vol
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "local-storage"
      resources:
        requests:
          storage: 368Gi
$ kubectl get pvc
NAMESPACE   NAME             STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS    AGE
default    csi-cephfs-pvc   Bound     pvc-878a667c-8e34-11ec-b8d5-fa163e06eeca   2Gi        RWX            csi-cephfs-sc   1h

持久化存储

持久化存储的3中方式:

  • StorageClass
  • PersistentVolume
  • PersistentVolumeClaim

存储资源的访问方式:

  • 直接访问
  • 静态 PV
  • 动态 PV

架构

持久化存储 <---> PV <--1:1--> PVC <--1:n--> Pod(mount Volume)

PV

PV(PersistentVolume,持久化卷) 是 Volume 的一种类型,是对底层的共享存储的一种抽象。PV 由集群管理员进行创建和配置,就像 节点 (Node) 是集群中的资源一样,PV 也是集群资源的一种:

  • PV 包含存储类型、存储大小和访问模式(accessModes,参考)
  • PV 的生命周期独立于 Pod
  • PV 是 集群级别 的资源,并不属于某个 命名空间
  • 帮助命令:kubectl explain pv.spec

下面演示示例:

  • pv-nfs.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pvnfs1
  labels:
    backend: nfs
spec:
  accessModes:
    - ReadWriteOnce
    - ReadWriteMany
  capacity:
    storage: 5Gi
  nfs:
    path: /data/nfs/volume/abc
    server: nfs.kb.cx
  • 查看
root@k8s-master:~/manifests/volume# kubectl apply -f pv-nfs.yaml
persistentvolume/pvnfs1 created
root@k8s-master:~/manifests/volume# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pvnfs1   5Gi        RWO,RWX        Retain           Available                                   3s

PVC

帮助命令:kubectl explain pvc.spec

PVC(PersistentVolumeClaim,持久化卷声明) 是用户对存储资源的一种请求,PVC 和 Pod 比较类似:

  • Pod 消耗的是节点资源,PVC 消耗的是 PV 资源
  • Pod 可以请求 CPU 和内存,PVC 可以请求特定的存储空间和访问模式
  • 对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可
  • PVC 是 命名空间 级别的资源,PV 可以与任何命名空间的 PVC 资源绑定

下面演示示例:

  • pod-pvc-nfs-vol.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvcnfs1
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-pvc-nfs
  namespace: default
spec:
  containers:
  - name: nginx
    image: nginx:latest
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: cache-v1
      mountPath: /cache
  volumes:
  - name: cache-v1
    persistentVolumeClaim:
      claimName: pvcnfs1
  • 查看
$ kubectl apply -f pod-pvc-nfs-vol.yaml
persistentvolumeclaim/pvcnfs1 created
pod/pod-pvc-nfs configured
$ kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
pvnfs1   5Gi        RWO,RWX        Retain           Bound    default/pvcnfs1                           19m
$ kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvcnfs1   Bound    pvnfs1   5Gi        RWO,RWX                       9s

# 对应的 node 节点
root@k8s-node-1:~# cat /proc/mounts |grep nfs.kb.cx
nfs.kb.cx:/data/nfs/volume/abc /var/lib/kubelet/pods/136d3cf5-285c-4b38-8e96-1192878a5f43/volumes/kubernetes.io~nfs/pvnfs1 nfs4 rw,relatime,vers=4.2,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=172.20.0.82,local_lock=none,addr=172.20.0.132 0 0

说明:

  • volume 也是通过先挂载在 node 节点,在映射到容器内部

StorageClass

SC(StorageClass,储存类别) 由于不同的应用程序对于存储性能的要求也不尽相同,比如:读写速度、并发性能、存储大小等。如果只能通过 PVC 对 PV 进行静态申请,显然这并不能满足各种应用对于存储的需求。为了解决这一问题,Kubernetes 引入了一个新的资源对象:StorageClass,通过 StorageClass 的定义,集群管理员可以先将存储资源定义为不同类型的资源,比如快速存储、慢速存储等

当用户通过 PVC 对存储资源进行申请时,StorageClass 会使用 Provisioner(不同 Volume 对应不同的 Provisioner)来自动创建用户所需 PV。这样应用就可以随时申请到合适的存储资源,而不用担心集群管理员没有事先分配好需要的 PV

  • 自动创建的 PV 以 ${namespace}-${pvcName}-${pvName} 这样的命名格式创建在后端存储服务器上的共享数据目录中
  • 自动创建的 PV 被回收后会以 archieved-${namespace}-${pvcName}-${pvName} 这样的命名格式存在后端存储服务器上

其他

  • TopoLVM 是一个用于本地存储的新 CSI 插件,可使用 LVM 动态配置卷

参考

  1. https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数