首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kubernetes-存储卷Volume

Kubernetes-存储卷Volume

作者头像
菲宇
发布2019-06-12 15:25:55
4.8K1
发布2019-06-12 15:25:55
举报
文章被收录于专栏:菲宇菲宇菲宇

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年08月17日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、存储卷概述
  • 2、存储卷类型和示例
    • 2.1 hostPath
      • 2.2 NFS
        • 2.3 persistentVolumeClaim
        • emptyDir
        • 参考资料
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档