专栏首页菲宇Kubernetes-存储卷Volume

Kubernetes-存储卷Volume

1、存储卷概述

由于容器本身是非持久化的,因此需要解决在容器中运行应用程序遇到的一些问题。首先,当容器崩溃时,kubelet将重新启动容器,但是写入容器的文件将会丢失,容器将会以镜像的初始状态重新开始;第二,在通过一个Pod中一起运行的容器,通常需要共享容器之间一些文件。Kubernetes通过存储卷解决上述的两个问题。

在Docker有存储卷的概念卷,但Docker中存储卷只是磁盘的或另一个容器中的目录,并没有对其生命周期进行管理。Kubernetes的存储卷有自己的生命周期,它的生命周期与使用的它Pod生命周期一致。因此,相比于在Pod中运行的容器来说,存储卷的存在时间会比的其中的任何容器都长,并且在容器重新启动时会保留数据。当然,当Pod停止存在时,存储卷也将不再存在。在Kubernetes支持多种类型的卷,而Pod可以同时使用各种类型和任意数量的存储卷。在Pod中通过指定下面的字段来使用存储卷:

  • spec.volumes:通过此字段提供指定的存储卷
  • spec.containers.volumeMounts:通过此字段将存储卷挂接到容器中

2、存储卷类型和示例

当前Kubernetes支持如下所列这些存储卷类型,并以hostPath、nfs和persistentVolumeClaim类型的存储卷为例,介绍如何定义存储卷,以及如何在Pod中被使用。

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

2.1 hostPath

hostPath类型的存储卷用于将宿主机的文件系统的文件或目录挂接到Pod中,除了需要指定path字段之外,在使用hostPath类型的存储卷时,也可以设置type,type支持的枚举值由下表。另外在使用hostPath时,需要注意下面的事项:

  • 具有相同配置的Pod(例如:从同一个podTemplate创建的),可能会由于Node的文件不同,而行为不同。
  • 在宿主机上创建的文件或目录,只有root用户具写入的权限。您要么在容器中以root身份运行进程,要么在主机上修改的文件或目录的权限,以便具备写入内容到hostPath的存储卷中。

行为

空字符串(默认)是用于向后兼容,这意味着在挂接主机路径存储卷之前不执行任何检查。

DirectoryOrCreate

如果path指定目录不存在,则会在宿主机上创建一个新的目录,并设置目录权限为0755,此目录与kubelet拥有一样的组和拥有者。

Directory

path指定的目标必需存在

FileOrCreate

如果path指定的文件不存在,则会在宿主机上创建一个空的文件,设置权限为0644,此文件与kubelet拥有一样的组和拥有者。

File

path指定的文件必需存在

Socket

path指定的UNIX socket必需存在

CharDevice

path指定的字符设备必需存在

BlockDevice

在path给定路径上必须存在块设备。

下面是使用hostPath作为存储卷的YAML文件,此YAML文件定义了一个名称为test-pd的Pod资源。它通过hostPath类型的存储卷,将Pod宿主机上的/data挂接到容器中的/teset-pd目录。

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:
      # 宿主机上的目录
      path: /data
      # this field is optional
      type: Directory

2.2 NFS

在Kubernetes中,可以通过nfs类型的存储卷将现有的NFS(网络文件系统)到的挂接到Pod中。在移除Pod时,NFS存储卷中的内容被不会被删除,只是将存储卷卸载而已。这意味着在NFS存储卷总可以预先填充数据,并且可以在Pod之间共享数据。NFS可以被同时挂接到多个Pod中,并能同时进行写入。需要注意的是:在使用nfs存储卷之前,必须已正确部署和运行NFS服务器,并已经设置了共享目录。

下面是一个redis部署的YAML配置文件,redis在容器中的持久化数据保存在/data目录下;存储卷使用nfs,nfs的服务地址为:192.168.8.150,存储路径为:/k8s-nfs/redis/data。容器通过volumeMounts.name的值确定所使用的存储卷。

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: redis
  revisionHistoryLimit: 2
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      # 应用的镜像
      - image: redis
        name: redis
        imagePullPolicy: IfNotPresent
        # 应用的内部端口
        ports:
        - containerPort: 6379
          name: redis6379
        env:
        - name: ALLOW_EMPTY_PASSWORD
          value: "yes"
        - name: REDIS_PASSWORD
          value: "redis"   
        # 持久化挂接位置,在docker中 
        volumeMounts:
        - name: redis-persistent-storage
          mountPath: /data
      volumes:
      # 宿主机上的目录
      - name: redis-persistent-storage
        nfs:
          path: /k8s-nfs/redis/data
          server: 192.168.8.150

2.3 persistentVolumeClaim

persistentVolumeClaim类型存储卷将PersistentVolume挂接到Pod中作为存储卷。使用此类型的存储卷,用户并不知道存储卷的详细信息。

此处定义名为busybox-deployment的部署YAML配置文件,使用的镜像为busybox。基于busybox镜像的容器需要对/mnt目录下的数据进行持久化,在YAML文件指定使用名称为nfs的PersistenVolumeClaim对容器的数据进行持久化。

# This mounts the nfs volume claim into /mnt and continuously
# overwrites /mnt/index.html with the time and hostname of the pod. 
apiVersion: v1
kind: Deployment
metadata:  
  name: busybox-deployment
spec:  
  replicas: 2  
  selector:    
    name: busybox-deployment
  template:    
    metadata:      
      labels:        
        name: busybox-deployment    
    spec:      
      containers:      
      - image: busybox        
        command:          
        - sh          
        - -c          
        - 'while true; do date > /mnt/index.html; hostname >> /mnt/index.html; sleep $(($RANDOM % 5 + 5)); done'        
        imagePullPolicy: IfNotPresent        
        name: busybox        
        volumeMounts:          
        # name must match the volume name below          
        - name: nfs            
          mountPath: "/mnt"     
     volumes:      
     - name: nfs        
       persistentVolumeClaim:          
         claimName: nfs-pvc

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: /data

NFS

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: ext4

awsElasticBlockStore

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

volumes:

- name: test-volume

# This AWS EBS volume must already exist.

awsElasticBlockStore:

volumeID: <volume-id>

fsType: ext4

gitRepo

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-data

FlexVolume

如果内置的这些 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: 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 核心代码中,而是存放在 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

参考资料

1.《Volumes》地址:https://kubernetes.io/docs/concepts/storage/volumes/

2.《nfs》地址:https://github.com/kubernetes-incubator/external-storage/tree/master/nfs

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • kubernetes 功能介绍

    每个Node 节点上都运行着以下一组关键进程 - 1. kubelet:负责pod对应的容器创建、启停等任务,同时与master 节点密切协作,实现集群管理的...

    菲宇
  • kubernetes控制器之DaemonSet

    DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod 。当有 Node 从集群移...

    菲宇
  • redis缓存数据库

    NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库,随着互联网web2.0网站的兴起,传统的关系数据库在应...

    菲宇
  • Kubernetes 最佳安全实践指南

    对于大部分 Kubernetes 用户来说,安全是无关紧要的,或者说没那么紧要,就算考虑到了,也只是敷衍一下,草草了事。实际上 Kubernetes 提供了非常...

    米开朗基杨
  • 深入理解Pod(二)

    将应用所需的配置信息与程序进行分离,可以使应用程序更好的被复用,通过不同的配置实现更灵活的功能。如果将应用打包成镜像,再用环境变量或者外挂文件的方式挂载配置,在...

    Liusy
  • Django中FilePathField字段的用法

    class FilePathField(path=None[, match=None, recursive=False, max_length=100, **o...

    砸漏
  • python 字典

      字典是一种可变容器模型,且可存储任意类型对象。字典的每个键值对(key->value)用冒号“:”分割,每个键值对之间用逗号“,”分割,整个字典包括在花括号...

    py3study
  • 基于OpenCV 的美颜相机推送直播流

    先从opencv(2.4.10版本)采集回来摄像头的图像,是一帧一帧的 每一帧图像是一个矩阵,opencv中的mat 数据结构。

    流川疯
  • Struts2笔记(一)

    1.创建Action 创建action需要继承ActionSupport类,然后就会有一些常量以及一些方法。 struts2的action默认执行的方法就是ex...

    lwen
  • 学习python的第十天(内置算法:列表数据类型,元祖数据类型,字典数据类型)

    (与列表相似,区别是可以读取不可存储改变,列表中关于存储或者改名元素的内容内置函数元祖不行)

    小小咸鱼YwY

扫码关注云+社区

领取腾讯云代金券