概述

Volume是对各种存储资源的抽象、虚拟化。为管理、控制、使用存储资源提供统一接口。Openstack中的volume为虚拟机提供存储,Docker中的volume为容器提供存储。因为在kubernetes中可部署运行最小单位是pod ,所以kubernetes的volume为pod提供存储。当然在部署pod时可以不为其提供volume,pod中的容器使用所在节点的硬盘,能同时读写数据的地方称为可读写层。这种存储是容器级的临时存储,不是pod级。其生命周期与容器相同,如果容器crash后被重启,也就是旧容器被删除而新容器启动,则旧容器的可读写层与容器一起被删除,其上数据丢失。同理如果pod在节点之间迁移调度,容器的可读写层并不会迁移调度。因此,kubernetes需要提供pod级volume,本文中的volume特指kubernetes。

Volume类型

Volume是抽象概念,有很多种具体实现,每种实现各具目的、特点、特性。差不多什么东西都可以当成volume,类型如下:

• awsElasticBlockStore
• azureDisk
• azureFile
• cephfs
• configMap
• csi
• downwardAPI
• emptyDir
• fc (fibre channel)
• flocker
• gcePersistentDisk
• gitRepo (deprecated)
• glusterfs
• hostPath
• iscsi
• local
• nfs
• persistentVolumeClaim
• projected
• portworxVolume
• quobyte
• rbd
• scaleIO
• secret
• storageos
• vsphereVolume

awsElasticBlockStore

亚马逊公司提供,实现将亚马逊云平台提供的EBS volume挂接到pod上。emptyDir类型的volume在pod被删除时其上数据会被清空,与此不同,EBS volume只是解除mount,数据仍然被保持,这意味着可以提前为EBS volume注入数据供pod使用,或者将EBS volume在不同pod之间换手,传递数据。在使用EBS volume前必需调用aws ec2 create-volume命令行创建。

有如下限制:

  • 运行pod的节点必需是AWS EC2实例。
  • AWS EC2实例必需与EBS volume实现们于同一地址或者可用区之内。意思就是中国的AWS EC2实例无法使用北美的EBS volume实例。
  • 单个EBS volume实例只能被一个AWS EC2实例使用,不能跨节点。

创建 EBS volume

aws ec2 create-volume --availability-zone=eu-west-1a --size=10 --volume-type=gp2

使用EBS volume 

apiVersion: v1
kind: Pod
metadata:
  name: test-ebs
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-ebs
      name: test-volume
  volumes:
  - name: test-volume
    # This AWS EBS volume must already exist.
    awsElasticBlockStore:
      volumeID: <volume-id>
      fsType: ext4

azureDisk

azureDisk is used to mount a Microsoft Azure Data Disk into a Pod.

More details can be found here.

azureFile

azureFile is used to mount a Microsoft Azure File Volume (SMB 2.1 and 3.0) into a Pod.

More details can be found here.

cephfs

cephfs是一款优秀、流行的云环境存储解决方案,原因是它开源、高可用、弹性伸缩,对操作系统、硬件无特殊要求,用户很容易搭建,使用它的节点也无特别要求。它具备awsElasticBlockStore陈述之所有特点,并且单个voluem可以被多个节点同时使用。用户首先搭建自己的cephfs环境,然后配置kubernetes集群与其对接,最后在pod中使用其提供的volume

configMap

用户首先创建configMap并创建数据保存其中,此时数据保存在kubernetes的etcd数据库中,volume还不存在。当用户在pod中引用创建的configMap时,系统首先在节点上创建volume并将数据保存其中,这个volume占用的是节占的存储空间。此后就可以像使用普通volume一样使用它。

configMap是kubernetes中的一种对象类型,核心本质是以volume的方式将单独管理的配置信息传递给pod中的容器,并非用来存储持久化数据。细参考这里。

downwardAPI

与configMap类似,以volume的方式向pod中的容器传递信息。configMap中的信息由用户在创建对象时传递,而downwardAPI的信息就来自pod对象本身,downwardAPI不需要创建,它是pod Spec中的一个字段,内容指向pod对象本身的其它字段,如pod的metadata、image等信息。在创建pod时系统首先将指向的字段提取出来,然后创建volume并保存提取出来的字段并挂载,容器就可以读取这些字段了。

downwardAPI的目的是为将pod本身的字段信息如label、annotation等传递给容器的一种手段。

emptyDir

在节点上运行pod实例时才会创建emptyDir volume。它首先是节点上的一个空目录,pod中的任何容器都可以用volume的形式挂载使用它。如果容器因为某种原因被删除并重新启动,创建的emptyDir不会删除也不会被清空。当pod实例离开节点调度到其它节点或因为缩容被删除时,emptyDir被删除,相当于pod还在但数据丢了。示例:

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

fc (fibre channel)

光纤通道区域存储网络,需要购买支持FC的磁盘阵列设备、控制器、光纤、光接口以及与设置相匹配的软件。

flocker

是一种开源的存储管理技术。它的后端可以是各种存储技术,为用户屏蔽低层存储技术不同的现实,并提供一定的自动化能力。

gcePersistentDisk

由谷歌GCE提供,与awsElasticBlockStore相似,不能自由使用,不细描。

gitRepo (deprecated)

将git仓库中的项目以volume的形式直接指定给pod,此特性已经被放弃。很容易用替代方案实现。首先为pod的初始化容器指定emptyDir,将git创建中的内容clone到这个emptyDir,初始化容器退出,但emptyDir被保留,然后再将emptyDir挂载到普通容器。

glusterfs

与cephfs一样,流行的云环境下的存储解决方案

hostPath

pod实例中的容器通过hostPath直接访问节点的文件系统,比如某个容器负责收集节点上某个目录下的日志,就可以通过hostPath实现,示例如下:

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # directory location on host
      path: /data
      # this field is optional
      type: Directory

iscsi

互联网小型计算机系统接口,其特点是便宜。

local

与emptyDir相似,它也占用节点的存储空间。不同点是它是kubernetes中的一种对象类型,用户可以像管理普通对象一样管理它。emptyDir在pod实例开时运行时分配,当pod离节点时删除。local类型的volume则由用户创建,系统在合适的节点上为其分配资源,调度到这个节点上的pod可以挂载它,pod离开时它也不会消失,除非用户删除。示例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 100Gi
  # volumeMode field requires BlockVolume Alpha feature gate to be enabled.
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /mnt/disks/ssd1
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - example-node

nfs

网络文件系统

persistentVolumeClaim

与flocker相似,用来屏蔽不同云环境

projected

如果一个容器需要挂开多个已经存在的volume比如Secret、ConfigMap、DownwardAPI等,原本每个这种类型的volume需要各自占用一个挂载目录,而projected能将它们整合在一起,并只挂开到一个目录下,示例:

apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  containers:
  - name: container-test
    image: busybox
    volumeMounts:
    - name: all-in-one
      mountPath: "/projected-volume"
      readOnly: true
  volumes:
  - name: all-in-one
    projected:
      sources:
      - secret:
          name: mysecret
          items:
            - key: username
              path: my-group/my-username
      - downwardAPI:
          items:
            - path: "labels"
              fieldRef:
                fieldPath: metadata.labels
            - path: "cpu_limit"
              resourceFieldRef:
                containerName: container-test
                resource: limits.cpu
      - configMap:
          name: myconfigmap
          items:
            - key: config
              path: my-group/my-config

其它

参考:https://kubernetes.io/docs/concepts/storage/volumes/#projected