🏆 volume

Container 中的文件在磁盘上是临时存放的,这给 Container 中运行的较重要的应用 程序带来一些问题。问题之一是当容器崩溃时文件丢失。kubelet 会重新启动容器, 但容器会以干净的状态重启。 会在同一 Pod 中运行多个容器并需要共享文件时, Kubernetes 卷(Volume) 这一抽象概念能够解决这两个问题。

Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型。 临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长。 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;不过 Kubernetes 不会销毁 持久卷。对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。

卷的核心是一个目录,其中可能存有数据,Pod 中的容器可以访问该目录中的数据。 所采用的特定的卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放 的内容。

使用卷时, 在 .spec.volumes 字段中设置为 Pod 提供的卷,并在 .spec.containers[\*].volumeMounts 字段中声明卷在容器中的挂载位置。 容器中的进程看到的是由它们的 Docker 镜像和卷组成的文件系统视图。 Docker 镜像 位于文件系统层次结构的根部。各个卷则挂载在镜像内的指定路径上。 卷不能挂载到其他卷之上,也不能与其他卷有硬链接。 Pod 配置中的每个容器必须独立指定各个卷的挂载位置。

🌟 卷的类型

Kubernetes支持以下类型的卷:

#awsElasticBlockStore azureDisk azureFile cephfs csi downwardAPI emptyDir fc flocker 
#gcePersistentDisk gitRepo glusterfs hostPath iscsi local nfs persistentVolumeClaim 
#projected portworxvolume quobyte rbdl scaleI0 secret
#storageos vsphereVolume

🌟 emptyDir

Pod被分配给节点时,首先创建 emptyDir 卷,并且只要该 Pod在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入 emptyDir 卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod时,emptyDir 中的数据将被永久删除

容器崩溃并不会导致 Pod 被从节点上移除,因此容器崩溃期间 emptyDir 卷中的数据是安全的。

emptyDir 的一些用途:

  • 缓存空间,例如基于磁盘的归并排序。
  • 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
  • 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。

取决于你的环境,emptyDir 卷存储在该节点所使用的介质上;这里的介质可以是磁盘或 SSD 或网络存储。但是,你可以将 emptyDir.medium 字段设置为 "Memory",以告诉 Kubernetes 为你挂载 tmpfs(基于 RAM 的文件系统)。 虽然 tmpfs 速度非常快,但是要注意它与磁盘不同。 tmpfs 在节点重启时会被清除,并且你所写入的所有文件都会计入容器的内存消耗,受容器内存限制约束。

1️⃣ 配置emptyDir

apiVersion: v1
kind: Pod
metadata:
  name: volume-pod-test1
spec:
  volumes:
  - name: empty-test
    emptyDir: {}
  containers:
  - name: test
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: empty-test
      mountPath: /test

2️⃣ 进入pod

[root@master volume]# kubectl exec -it volume-pod-test1 bash
root@volume-pod-test1:/# ls
bin   docker-entrypoint.d   home   media  proc  sbin  test  var
boot  docker-entrypoint.sh  lib    mnt    root  srv   tmp
dev   etc                   lib64  opt    run   sys   usr
root@volume-pod-test1:/# cd test/
root@volume-pod-test1:/test# ls

3️⃣ 使用emptyDir创建容器共享目录

apiVersion: v1
kind: Pod
metadata:
  name: volume-pod-test1
spec:
  volumes:
  - name: empty-test
    emptyDir: {}
  containers:
  - name: test1
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: empty-test
      mountPath: /test1
  - name: test2
    image: busybox
    imagePullPolicy: IfNotPresent
    command: ["sh","-c","sleep 600s;"]
    volumeMounts:
    - name: empty-test
      mountPath: /test2

🌟 HostPath

也很好理解就是将主机节点的文件系统中你的文件或者目录挂载到集群中

hostPath 的一些用法有:

  • 运行一个需要访问 Docker 内部机制的容器;可使用 hostPath 挂载 /var/lib/docker 路径。
  • 在容器中运行 cAdvisor 时,以 hostPath 方式挂载 /sys
  • 允许 Pod 指定给定的 hostPath 在运行 Pod 之前是否应该存在,是否应该创建以及应该以什么方式存在。

除了必需的 path 属性之外,用户可以选择性地为 hostPath 卷指定 type。支持的 type 值如下:

取值 行为
空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。
DirectoryOrCreate 如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。
Directory 在给定路径上必须存在的目录。
FileOrCreate 如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。
File 在给定路径上必须存在的文件。
Socket 在给定路径上必须存在的 UNIX 套接字。
CharDevice 在给定路径上必须存在的字符设备。
BlockDevice 在给定路径上必须存在的块设备。

当使用这种类型的卷时要小心,因为:

  • 具有相同配置(例如基于同一 PodTemplate 创建)的多个 Pod 会由于节点上文件的不同 而在不同节点上有不同的行为。
  • 下层主机上创建的文件或目录只能由 root 用户写入。你需要在 特权容器 中以 root 身份运行进程,或者修改主机上的文件权限以便容器能够写入 hostPath 卷。
apiVersion: v1
kind: Pod
metadata:
  name: volume-test2-pod
spec:
  volumes:
  - name: hostpath-test
    hostPath:
      path: /data
      type: Directory
  - name: hostpath-test2
    hostPath:
      path: /data/date
      type: FileOrCreate
  containers:
  - name: test1
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: hostpath-test
      mountPath: /data
    - name: hostpath-test2
      mountPath: /data/date

因为是 Directory,所以要在 node节点都创建 /data目录,在去创建 hostpath

mkdir /data
kubectl create -f volume.hostpath.yaml

进入容器查看

[root@master volume]# kubectl exec -it volume-test2-pod /bin/bash
root@volume-test2-pod:/# cd /data/
root@volume-test2-pod:/data# ls
date 

在查看节点

[root@node2 ~]# cd /data/
[root@node2 data]# ls
date

🌟 NFS

NFS客户端将NFS服务端设置好的共享目录挂载到本地某个挂载点,对于客户端来说,共享的资源就相当于在本地的目录下

  • 安装nfs工具
	[root@master ~]# yum install -y nfs-utils  
  • 配置挂载规则
[root@master ~]# cat /etc/exports
/nfs   *(rw,no_root_squash)
  • 创建nfs挂在目录并设置nfs开机自启
[root@master ~]# mkdir /nfs
[root@master ~]# systemctl enable --now nfs
Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.
[root@master ~]# showmount -e
Export list for master:
/nfs *
  • 创建nfs.yaml
[root@master volume]# cat volume-nfs.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nfs-pod
spec:
  containers:
  - image: ubuntu:18.04
    name: ubuntu-nfs-pod
    imagePullPolicy: IfNotPresent
    volumeMounts:
      - mountPath: /usr/local/nfs
        name: nfs
  volumes:
  - name: nfs
    nfs:
      path: /nfs
      server: 192.168.200.10
  • 创建后查看
[root@master volume]# kubectl get pod 
NAME      READY   STATUS              RESTARTS   AGE
nfs-pod   0/1     ContainerCreating   0          10m
##发现一直没有起来
  • 查看为什么起不了
Mounting command: systemd-run
Mounting arguments: --description=Kubernetes transient mount for /var/lib/kubelet/pods/2f110856-54c4-42e4-b852-abae3abcc327/volumes/kubernetes.io~nfs/nfs --scope -- mount -t nfs 192.168.200.10:/nfs /var/lib/kubelet/pods/2f110856-54c4-42e4-b852-abae3abcc327/volumes/kubernetes.io~nfs/nfs
Output: Running scope as unit run-60150.scope.
mount: wrong fs type, bad option, bad superblock on 192.168.200.10:/nfs,
       missing codepage or helper program, or other error
       (for several filesystems (e.g. nfs, cifs) you might
       need a /sbin/mount.<type> helper program)

       In some cases useful info is found in syslog - try
       dmesg | tail or so.
  Warning  FailedMount  11m  kubelet, slave  MountVolume.SetUp failed for volume "nfs" : mount failed: exit status 32
  • 在查看一下在哪个节点
[root@master volume]# kubectl get pod -o wide
NAME      READY   STATUS              RESTARTS   AGE   IP       NODE    NOMINATED NODE   READINESS GATES
nfs-pod   0/1     ContainerCreating   0          24m   <none>   slave   <none>           <none>
##可以看见是在slave节点slave节点没有配置nfs
  • 在slave节点下载nfs
[root@master volume]# kubectl apply -f volume-nfs.yaml 
pod/nfs-pod created
[root@master volume]# kubectl get pod
NAME      READY   STATUS    RESTARTS   AGE
nfs-pod   1/1     Running   0          22s
[root@master volume]# kubectl exec -it nfs-pod bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
root@nfs-pod:/# cd /usr/local/nfs/
root@nfs-pod:/usr/local/nfs# ls
root@nfs-pod:/usr/local/nfs# mkdir 1
  • 在进入本机的nfs目录查看
[root@master nfs]# ls
1