Volume
我們知道默認情況下容器的數據都是非持久化的,在容器消亡以後數據也跟着丟失,所以 Docker 提供了 Volume 機制以便將數據持久化存儲。類似的,Kubernetes 提供了更強大的 Volume 機制和豐富的插件,解決了容器數據持久化和容器間共享數據的問題。
與 Docker 不同,Kubernetes Volume 的生命週期與 Pod 綁定
- 容器掛掉後 Kubelet 再次重啓容器時,Volume 的數據依然還在 
- 而 Pod 刪除時,Volume 纔會清理。數據是否丟失取決於具體的 Volume 類型,比如 emptyDir 的數據會丟失,而 PV 的數據則不會丟 
Volume 類型
目前,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 的消亡而消失。
API 版本對照表
v1.5+
core/v1
emptyDir
如果 Pod 設置了 emptyDir 類型 Volume, Pod 被分配到 Node 上時候,會創建 emptyDir,只要 Pod 運行在 Node 上,emptyDir 都會存在(容器掛掉不會導致 emptyDir 丟失數據),但是如果 Pod 從 Node 上被刪除(Pod 被刪除,或者 Pod 發生遷移),emptyDir 也會被刪除,並且永久丟失。
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}hostPath
hostPath 允許掛載 Node 上的文件系統到 Pod 裏面去。如果 Pod 需要使用 Node 上的文件,可以使用 hostPath。
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: gcr.io/google_containers/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      path: /dataNFS
NFS 是 Network File System 的縮寫,即網絡文件系統。Kubernetes 中通過簡單地配置就可以掛載 NFS 到 Pod 中,而 NFS 中的數據是可以永久保存的,同時 NFS 支持同時寫操作。
volumes:
- name: nfs
  nfs:
    # FIXME: use the right hostname
    server: 10.254.234.223
    path: "/"gcePersistentDisk
gcePersistentDisk 可以掛載 GCE 上的永久磁盤到容器,需要 Kubernetes 運行在 GCE 的 VM 中。
volumes:
  - name: test-volume
    # This GCE PD must already exist.
    gcePersistentDisk:
      pdName: my-data-disk
      fsType: ext4awsElasticBlockStore
awsElasticBlockStore 可以掛載 AWS 上的 EBS 盤到容器,需要 Kubernetes 運行在 AWS 的 EC2 上。
volumes:
  - name: test-volume
    # This AWS EBS volume must already exist.
    awsElasticBlockStore:
      volumeID: <volume-id>
      fsType: ext4gitRepo
gitRepo volume 將 git 代碼下拉到指定的容器路徑中
  volumes:
  - name: git-volume
    gitRepo:
      repository: "git@somewhere:me/my-git-repository.git"
      revision: "22f1d8406d464b0c0874075539c1f2e96c253775"使用 subPath
Pod 的多個容器使用同一個 Volume 時,subPath 非常有用
apiVersion: v1
kind: Pod
metadata:
  name: my-lamp-site
spec:
    containers:
    - name: mysql
      image: mysql
      volumeMounts:
      - mountPath: /var/lib/mysql
        name: site-data
        subPath: mysql
    - name: php
      image: php
      volumeMounts:
      - mountPath: /var/www/html
        name: site-data
        subPath: html
    volumes:
    - name: site-data
      persistentVolumeClaim:
        claimName: my-lamp-site-dataFlexVolume
如果內置的這些 Volume 不滿足要求,則可以使用 FlexVolume 實現自己的 Volume 插件。注意要把 volume plugin 放到 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/<vendor~driver>/<driver>,plugin 要實現 init/attach/detach/mount/umount 等命令(可參考 lvm 的 示例)。
  - name: test
    flexVolume:
      driver: "kubernetes.io/lvm"
      fsType: "ext4"
      options:
        volumeID: "vol1"
        size: "1000m"
        volumegroup: "kube_vg"Projected Volume
Projected volume 將多個 Volume 源映射到同一個目錄中,支持 secret、downwardAPI 和 configMap。
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本地存儲限額
v1.7 + 支持對基於本地存儲(如 hostPath, emptyDir, gitRepo 等)的容量進行調度限額,可以通過 --feature-gates=LocalStorageCapacityIsolation=true 來開啓這個特性。
爲了支持這個特性,Kubernetes 將本地存儲分爲兩類
- storage.kubernetes.io/overlay,即- /var/lib/docker的大小
- storage.kubernetes.io/scratch,即- /var/lib/kubelet的大小
Kubernetes 根據 storage.kubernetes.io/scratch 的大小來調度本地存儲空間,而根據 storage.kubernetes.io/overlay 來調度容器的存儲。比如
爲容器請求 64MB 的可寫層存儲空間
apiVersion: v1
kind: Pod
metadata:
  name: ls1
spec:
  restartPolicy: Never
  containers:
  - name: hello
    image: busybox
    command: ["df"]
    resources:
      requests:
        storage.kubernetes.io/overlay: 64Mi爲 empty 請求 64MB 的存儲空間
apiVersion: v1
kind: Pod
metadata:
  name: ls1
spec:
  restartPolicy: Never
  containers:
  - name: hello
    image: busybox
    command: ["df"]
    volumeMounts:
    - name: data
      mountPath: /data
  volumes:
  - name: data
    emptyDir:
      sizeLimit: 64MiMount 傳遞
在 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
- rslave和- rshared的說明可以參考 內核文檔
Volume 快照
v1.8 新增了 pre-alpha 版本的 Volume 快照,但還只是一個雛形,並且其實現不在 Kubernetes 核心代碼中,而是存放在 kubernetes-incubator/external-storage 中。
TODO: 補充 Volume 快照的設計原理和示例。
Windows Volume
Windows 容器暫時只支持 local、emptyDir、hostPath、AzureDisk、AzureFile 以及 flexvolume。注意 Volume 的路徑格式需要爲 mountPath: "C:\\etc\\foo" 或者 mountPath: "C:/etc/foo"。
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-pod
spec:
  containers:
  - name: hostpath-nano
    image: microsoft/nanoserver:1709
    stdin: true
    tty: true
    volumeMounts:
    - name: blah
      mountPath: "C:\\etc\\foo"
      readOnly: true
  nodeSelector:
    beta.kubernetes.io/os: windows
  volumes:
  - name: blah
    hostPath:
      path: "C:\\AzureData"apiVersion: v1
kind: Pod
metadata:
  name: empty-dir-pod
spec:
  containers:
  - image: microsoft/nanoserver:1709
    name: empty-dir-nano
    stdin: true
    tty: true
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
    - mountPath: C:/scratch
      name: scratch-volume
  volumes:
  - name: cache-volume
    emptyDir: {}
  - name: scratch-volume
    emptyDir: {}
  nodeSelector:
    beta.kubernetes.io/os: windows掛載傳播
掛載傳播(MountPropagation)是 v1.9 引入的新功能,並在 v1.10 中升級爲 Beta 版本。掛載傳播用來解決同一個 Volume 在不同的容器甚至是 Pod 之間掛載的問題。通過設置 `Container.volumeMounts.mountPropagation),可以爲該存儲卷設置不同的傳播類型。
支持三種選項:
- None:即私有掛載(private) 
- HostToContainer:即 Host 內在該目錄中的新掛載都可以在容器中看到,等價於 Linux 內核的 rslave。 
- Bidirectional:即 Host 內在該目錄中的新掛載都可以在容器中看到,同樣容器內在該目錄中的任何新掛載也都可以在 Host 中看到,等價於 Linux 內核的 rshared。僅特權容器(privileged)可以使用 Bidirectional 類型。 
注意:
- 使用前需要開啓 MountPropagation 特性 
- 如未設置,則 v1.9 和 v1.10 中默認爲私有掛載( - None),而 v1.11 中默認爲- HostToContainer
- Docker 服務的 systemd 配置文件中需要設置 - MountFlags=shared
其他的 Volume 參考示例
https://github.com/kubernetes/examples/tree/master/staging/volumes/iscsi
Last updated
