K8S 快速入门(十三)实战篇:存储 卷(Volume)

Volume

官网文档 卷

1. 为什么要用Volume?

k8s中Container 中的文件在磁盘上是临时存放的, 这就带来了一些列的问题

  1. 当一个容器损坏之后, kubelet会重启这个容器, 但是容器中的文件将丢失----容器以干净的状态重新启动
  2. 当很多容器运行在同一个pod中时, 很多时候需要数据文件的共享
  3. 在k8s中,由于pod分布在各个不同的节点之上,并不能实现不同节点之间持久性数据的共享,并且在节点故障时,可能会导致数据的永久性丢失。

Kubernetes 卷(Volume) 这一抽象概念能够解决以上问题。

Volume 的生命周期独立于容器,Pod 中的容器可能被销毁和重建,但 Volume 会被保留。

2. 什么是Volume?

Docker 也有 卷(Volume) 的概念,但对它只有少量且松散的管理。 Docker 卷是磁盘上或者另外一个容器内的一个目录。 Docker 提供卷驱动程序,但是其功能非常有限。

Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型。临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长。 因此,卷的存在时间会超出 Pod 中运行的所有容器,并且在容器重新启动时数据也会得到保留。 当 Pod 不再存在时,卷也将不再存在。(根据卷的类型,有些类型虽然卷不再存在,但是数据依然会被保留)

注意:docker磁盘映射的数据将会被保留,和kubernetes有一些不一样

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

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

在这里插入图片描述

3. 卷的类型

kubenetes卷的类型:
在这里插入图片描述

不只上图中列的,还支持很多文件系统

卷的类型大致分为四类:

第一种就是本地卷

  • 像hostPath类型与docker里面的bind mount类型,就是直接挂载到宿主机文件的类型
  • 像emptyDir类型,数据的存储取决于宿主机所使用的介质,比如磁盘或 SSD 或网络存储

这两种类型的存储都是绑定宿主机节点的

第二种就是网络数据卷

  • 比如Nfs、ClusterFs、Ceph,这些都是外部的存储都可以挂载到k8s上

第三种就是云盘

  • 比如AWS、微软(azuredisk)

第四种就是k8s自身的资源

  • 比如secret、configmap、downwardAPI

数据卷挂载有很多种方式:
在这里插入图片描述
同一个pod可以挂载多个多种不同类型的卷。

4. emptyDir

4.1 介绍

当 Pod 分派到某个 Node 上时,emptyDir 卷会被创建,并且在 Pod 在该节点上运行期间,卷一直存在。 就像其名称表示的那样,卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,这些容器都可以读写 emptyDir 卷中相同的文件。当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。

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

emptyDir 的一些用途:

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

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

4.2 案例演示

清除上一章的测试数据:
在这里插入图片描述

在这里插入图片描述

apiVersion: v1
kind: Pod
metadata:
  name: test-pod1
spec:
  containers:
  - image: hub.kaikeba.com/java12/myapp:v1
    name: test-container
    volumeMounts:
    - mountPath: /cache # 挂载到容器的/cache目录下
      name: cache-volume
  volumes: # 申明数据卷
  - name: cache-volume
    emptyDir: {
    
    } #空卷

创建一个新目录volumes:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

容器中有这个目录说明已经挂载成功了

清除环境
在这里插入图片描述

4.3 案例演示2

接下来演示同个pod中多个容器共享这个数据卷:

apiVersion: v1
kind: Pod
metadata:
  name: test-pod2
spec:
  containers:
  - image: hub.kaikeba.com/java12/myapp:v1 #容器1
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  - name: test-1
    image: hub.kaikeba.com/java12/busybox:v1 #容器2
    command: ["/bin/sh","-c","sleep 3600s"]
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - mountPath: /cache # 这个挂载到容器的目录是可以不一样的
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {
    
    }

在这里插入图片描述

同一个卷挂载到容器的目录是可以不一样的
在这里插入图片描述

在这里插入图片描述

依次登录到两个容器上:
test-1容器挂载的目录是 /em
在这里插入图片描述

test-container容器挂载的目录是/cache
在这里插入图片描述

在test-container容器 /cache 中创建一个文件:
在这里插入图片描述

发现 test-1容器 /em 目录下也有该文件:
在这里插入图片描述

5. HostPath

5.1 介绍

hostPath 卷能将主机节点文件系统上的文件或目录挂载到你的 Pod 中。 虽然这不是大多数 Pod 需要的,但是它为一些应用程序提供了强大的逃生舱。

例如,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 卷。

总结:简单来说就是把宿主机上的文件或目录挂载到容器中

5.2 案例演示

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - image: hub.kaikeba.com/java12/myapp:v1
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    hostPath: # 唯一变化在这,之前空目录是emptyDir
      path: /data # 宿主机的挂载路径
      type: Directory # 挂载的一些校验行为,可以不填

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

会发现容器一直在创建中,查看一下pod
在这里插入图片描述

在这里插入图片描述

因为type设置为Directory,所以会检查宿主机上的目录是否存在
我们master节点上是有该目录的,但是pod是不可能部署在master节点的
根本原因就是该pod所部署的node节点上没有该目录

在这里插入图片描述

在这里插入图片描述

删除重新创建,比较快
在这里插入图片描述

在这里插入图片描述

看到该pod部署在node1节点上的,现在我们在node1节点上创建文件
在这里插入图片描述

在这里插入图片描述

总结:HostPath可以把宿主机的文件挂载到容器内部

6. NFS网络存储

这里我们演示数据卷挂载网络存储,nfs服务器搭建比较容易,就用nfs演示。

6.1 搭建nfs服务器

NFS服务器搭建与配置

nfs就是一个网络文件存储服务器,装完nfs之后,共享一个目录,其他的服务器就可以通过这个目录挂载到本地了,在本地写到这个目录的文件,就会同步到远程服务器上,实现一个共享存储的功能,一般都是做数据的共享存储,比如多台web服务器,肯定需要保证这些web服务器的数据一致性,那就会用到这个共享存储了,要是将nfs挂载到多台web服务器上,网站根目录下,网站程序就放在nfs服务器上,这样的话,每个网站,每个web程序都能读取到这个目录,一致性的数据,这样的话就能保证多个节点,提供一致性的程序了。

1) 单独拿一台服务器做nfs服务器,我们这里先搭建一台NFS服务器用来存储我们的网页根目录

yum install nfs-utils -y
systemctl start nfs-server

已经安装好并启动了
在这里插入图片描述

2)配置共享文件目录,让其他服务器能挂载这个目录,编辑配置文件:

mkdir /opt/k8s # 创建共享目录
vim /etc/exports # 编辑配置文件

配置文件格式:共享目录的路径 允许访问的NFS客户端(共享权限参数)

/opt/k8s 192.168.66.0/24(rw,no_root_squash)

在这里插入图片描述

在这里插入图片描述

  • rw:可读写的权限
  • ro:只读的权限
  • no_root_squash:登入NFS主机,使用该共享目录时相当于该目录的拥有者,如果是root的话,那么对于这个共享的目录来说,他就具有root的权限,这个参数『极不安全』,不建议使用
systemctl reload nfs  #重新加载NFS服务,使配置文件生效

3)客户端节点挂载测试
找个节点去挂载测试一下,客户端也需要安装nfs

#其他节点也需要安装nfs
yum install nfs-utils -y
mount -t nfs 192.168.66.13:/opt/k8s /mnt # 挂载远程nfs目录
cd /mnt
df -h #检查
touch a.txt

其他两个node节点也都安装了nfs:
在这里插入图片描述

测试挂载
在这里插入图片描述

在nfs服务器上创建一个文件,然后在node1节点上查看
在这里插入图片描述

在这里插入图片描述

6.2 pod挂载nfs案例演示

nfs 卷能将 NFS (网络文件系统) 挂载到你的 Pod 中。 不像 emptyDir 那样会在删除 Pod 的同时也会被删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。

注意: 在使用 NFS 卷之前,你必须运行自己的 NFS 服务器并将目标 share 导出备用。

# mkdir wwwroot
# vim nfs.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nfs
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: hub.kaikeba.com/java12/myapp:v1
        volumeMounts: # 容器挂载数据卷
        - name: wwwroot
          mountPath: /usr/share/nginx/html # 挂载到容器指定目录
        ports:
        - containerPort: 80
      volumes: # 申明数据卷
      - name: wwwroot
        nfs: #注意这里使用nfs进行挂载
          server: 192.168.66.13 #nfs服务器地址
          path: /opt/k8s/wwwroot #挂载nfs服务器上哪个地址
---
apiVersion: v1
kind: Service # 创建service
metadata:
  name: nginx-service
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginx
  type: NodePort # 直接开启物理机端口,对外提供服务

我们在源pod的网页目录下写入数据,并查看我们的nfs服务器目录下是否也会共享

先在nfs服务器上创建wwwroot目录
在这里插入图片描述

删除之前的测试环境
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

现在访问是403
在这里插入图片描述

登录任意一个pod中的容器,看到对应目录什么都没有
在这里插入图片描述

通过nfs服务器在对应目录创建html
在这里插入图片描述

回到之前容器查看
在这里插入图片描述

外网访问也是可以的
在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_41947378/article/details/111387243