Kubernetes 存储卷

    与 Docker 不同,Kubernetes Volume 的生命周期与 Pod 绑定

    • 容器挂掉后 Kubelet 再次重启容器时,Volume 的数据依然还在
    • 而 Pod 删除时,Volume 才会清理。数据是否丢失取决于具体的 Volume 类型,比如 emptyDir 的数据会丢失,而 PV 的数据则不会丢

    目前,Kubernetes 支持以下 Volume 类型:

    • emptyDir
    • hostPath
    • gcePersistentDisk
    • awsElasticBlockStore
    • nfs
    • iscsi
    • flocker
    • glusterfs
    • rbd
    • cephfs
    • gitRepo
    • secret
    • persistentVolumeClaim
    • downwardAPI
    • azureFileVolume
    • azureDisk
    • vsphereVolume
    • Quobyte
    • PortworxVolume
    • ScaleIO
    • FlexVolume
    • StorageOS
    • local

    注意,这些 volume 并非全部都是持久化的,比如 emptyDir、secret、gitRepo 等,这些 volume 会随着 Pod 的消亡而消失。

    emptyDir

    如果 Pod 设置了 emptyDir 类型 Volume, Pod 被分配到 Node 上时候,会创建 emptyDir,只要 Pod 运行在 Node 上,emptyDir 都会存在(容器挂掉不会导致 emptyDir 丢失数据),但是如果 Pod 从 Node 上被删除(Pod 被删除,或者 Pod 发生迁移),emptyDir 也会被删除,并且永久丢失。

    hostPath

    hostPath 允许挂载 Node 上的文件系统到 Pod 里面去。如果 Pod 需要使用 Node 上的文件,可以使用 hostPath。

    1. kind: Pod
    2. metadata:
    3. name: test-pd
    4. spec:
    5. containers:
    6. - image: gcr.io/google_containers/test-webserver
    7. name: test-container
    8. volumeMounts:
    9. - mountPath: /test-pd
    10. name: test-volume
    11. volumes:
    12. - name: test-volume
    13. hostPath:
    14. path: /data

    NFS

    NFS 是 Network File System 的缩写,即网络文件系统。Kubernetes 中通过简单地配置就可以挂载 NFS 到 Pod 中,而 NFS 中的数据是可以永久保存的,同时 NFS 支持同时写操作。

    1. - name: nfs
    2. nfs:
    3. # FIXME: use the right hostname
    4. server: 10.254.234.223
    5. path: "/"

    gcePersistentDisk

    1. volumes:
    2. - name: test-volume
    3. # This GCE PD must already exist.
    4. gcePersistentDisk:
    5. pdName: my-data-disk
    6. fsType: ext4

    awsElasticBlockStore 可以挂载 AWS 上的 EBS 盘到容器,需要 Kubernetes 运行在 AWS 的 EC2 上。

    gitRepo

    gitRepo volume 将 git 代码下拉到指定的容器路径中

    1. volumes:
    2. - name: git-volume
    3. gitRepo:
    4. repository: "git@somewhere:me/my-git-repository.git"
    5. revision: "22f1d8406d464b0c0874075539c1f2e96c253775"

    使用 subPath

    Pod 的多个容器使用同一个 Volume 时,subPath 非常有用

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: my-lamp-site
    5. spec:
    6. containers:
    7. - name: mysql
    8. image: mysql
    9. volumeMounts:
    10. - mountPath: /var/lib/mysql
    11. name: site-data
    12. - name: php
    13. image: php
    14. volumeMounts:
    15. - mountPath: /var/www/html
    16. name: site-data
    17. subPath: html
    18. volumes:
    19. - name: site-data
    20. persistentVolumeClaim:
    21. claimName: my-lamp-site-data

    FlexVolume

    如果内置的这些 Volume 不满足要求,则可以使用 FlexVolume 实现自己的 Volume 插件。注意要把 volume plugin 放到 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/<vendor~driver>/<driver>,plugin 要实现 init/attach/detach/mount/umount 等命令(可参考 lvm 的 )。

    1. - name: test
    2. flexVolume:
    3. driver: "kubernetes.io/lvm"
    4. fsType: "ext4"
    5. options:
    6. volumeID: "vol1"
    7. size: "1000m"
    8. volumegroup: "kube_vg"

    Projected Volume

    Projected volume 将多个 Volume 源映射到同一个目录中,支持 secret、downwardAPI 和 configMap。

    v1.7 + 支持对基于本地存储(如 hostPath, emptyDir, gitRepo 等)的容量进行调度限额,可以通过 --feature-gates=LocalStorageCapacityIsolation=true 来开启这个特性。

    • storage.kubernetes.io/overlay,即 /var/lib/docker 的大小
    • storage.kubernetes.io/scratch,即 /var/lib/kubelet 的大小

    Kubernetes 根据 storage.kubernetes.io/scratch 的大小来调度本地存储空间,而根据 storage.kubernetes.io/overlay 来调度容器的存储。比如

    为容器请求 64MB 的可写层存储空间

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: ls1
    5. spec:
    6. restartPolicy: Never
    7. containers:
    8. - name: hello
    9. command: ["df"]
    10. resources:
    11. requests:
    12. storage.kubernetes.io/overlay: 64Mi

    为 empty 请求 64MB 的存储空间

    1. apiVersion: v1
    2. kind: Pod
    3. name: ls1
    4. spec:
    5. restartPolicy: Never
    6. containers:
    7. - name: hello
    8. image: busybox
    9. command: ["df"]
    10. volumeMounts:
    11. - name: data
    12. mountPath: /data
    13. volumes:
    14. - name: data
    15. emptyDir:
    16. sizeLimit: 64Mi

    Mount 传递

    在 Kubernetes 中,Volume Mount 默认是 私有的,但从 v1.8 开始,Kubernetes 支持配置 Mount 传递(mountPropagation)。它支持两种选项

    • HostToContainer:这是开启 MountPropagation=true 时的默认模式,等效于 rslave 模式,即容器可以看到 Host 上面在该 volume 内的任何新 Mount 操作
    • Bidirectional:等效于 rshared 模式,即 Host 和容器都可以看到对方在该 Volume 内的任何新 Mount 操作。该模式要求容器必须运行在特权模式(即 securityContext.privileged=true

    注意:

    • 使用 Mount 传递需要开启 --feature-gates=MountPropagation=true
    • rslavershared 的说明可以参考

    Volume 快照

    v1.8 新增了 pre-alpha 版本的 Volume 快照,但还只是一个雏形,并且其实现不在 Kubernetes 核心代码中,而是存放在 中。

    Windows Volume

    Windows 容器暂时只支持 local、emptyDir、hostPath、AzureDisk、AzureFile 以及 flexvolume。注意 Volume 的路径格式需要为 mountPath: "C:\\etc\\foo" 或者 mountPath: "C:/etc/foo"

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: hostpath-pod
    5. spec:
    6. containers:
    7. - name: hostpath-nano
    8. image: microsoft/nanoserver:1709
    9. stdin: true
    10. tty: true
    11. volumeMounts:
    12. - name: blah
    13. mountPath: "C:\\etc\\foo"
    14. readOnly: true
    15. nodeSelector:
    16. beta.kubernetes.io/os: windows
    17. volumes:
    18. - name: blah
    19. hostPath:

    API 版本对照表