当前位置:首页 » 服务存储 » k8spod挂载s3对象存储
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

k8spod挂载s3对象存储

发布时间: 2023-08-10 06:38:54

A. 深入剖析k8s中pod的意义和用法

本文是《深入剖析k8s》学习笔记的第二篇,主要解析pod的意义及其使用方法。

pod,是k8s中最小的API对象,是原子调度单位。是超亲密关系容器之间组织和部署的单位。类比地说,pod就是虚拟机,其中的容器就是这个虚拟机里面运行的用户进程。

pod中的所有容器共享network、volume、IP地址,在pod启动的时候,需要先启动一个Infra中间容器,而其它容器都是通过join的方式加入到Infra容器的资源中的。Infra容器是一个用汇编语言编写的,永远处于暂停状态的容器,其唯一的作用就是hold住资源,和pod同生命周期。

initcontainers是一种容器类型,相较于containers类型,前者总是先于后者启动,initcontainers如果有多个,则会按照定义的顺序先后启动,只有当所有的initcontainers都启动成功且退出了,containers用户容器才会启动。

sidecar,是一种容器设计模式,指的是我们可以在一个pod中,启动一个辅助容器来完成一些独立于主容器之外的工作。比如initcontainers容器、Infra容器,都属于sidecar。

在进行上云工作的时候,我们可以把虚拟机类同为一个pod,把里面的进程类同为容器镜像,把有顺序关系的容器,定义为initcontainers。如此才是合理的、松耦合的容器编排诀窍,也是传统应用架构演变到微服务架构最自然的过渡方式。

pod有如下几个重要的属性需要掌握。

pod有如下几个状态需要掌握:

有几种特殊的volume,它们并不是为了存放容器中的数据,也不是为了进行容器之间或者和宿主机之间进行数据共享,而是为了给容器提供预先定义好的数据。这种数据卷被称为”投射数据卷“,projected volume。

pod可以为其中的容器配置探针(probe),用以监控容器的健康检查,而不是以容器镜像是否运行来作为健康检查的依据,因为会存在很多情况,容器是正常运行的,但是无法对外提供服务了,因此探针的健康检查方式更加准确。k8s一旦检测到容器探针发生异常,就会根据设置好的pod恢复机制进行操作,恢复机制restartPolicy有如下几种:

默认情况下pod的恢复机制是always,但并不是所有场景下都是合适的,比如initContainers初始化容器执行任务之后就结束了,就不应该设置为always。

如下文档提供了全量的yaml属性,特别是关于PodSpec的属性可以在3050行看到: api/types.go at master · kubernetes/api · GitHub

B. 云计算时代操作系统Kubernetes之存储(中)

我们在POD中定义数据卷的时候,必须指定数据卷的类型。由于存储技术的发展远远早于Kubernetes平台的诞生,并且随着Kubernetes的日益流行,新的存储技术和方案也在日新月异,因此数据卷可以说理所当然的有很多很多类型,有些是通用的类型,而有些需要底层特定存储技术的支持,下边是Kubernetes支持的数据卷类型不完全清单:

- emptyDir类型,emptyDir类型的数据卷允许POD将数据保存到指定的文件夹中,并且数据在POD的整个生命周期中可见。保存数据的文件夹在POD启动前被创建,并且刚开始文件夹为空,这也是叫empty的缘由。

- hostPath类型,从宿主机的文件系统挂载文件到POD中。

- nfs类型,NFS类型的存储卷挂载到POD中。

- cephfs,cinder,fc等,用来支持不同类型的网络存储。

- configMap,secret,downwardAPI,以及projected类型,四种卷类型,用来将POD和Kubernetes的相关信息通过文件暴露给外部,这些卷类型主要用来配置应用程序。这几种类型笔者会在后续的文章中详细介绍。

- persistentVolumeClaim类型(PVC),一种轻量级的集成外部存储能力的方案。在这种类型的数据卷类型中,PersistentVolumeClaim类型的存储对象指向PersistentVolume类型的存储对象,真实的外部存储系统由PersistentVolume这个对象来引用。由于这是Kuberntes强烈建议大家使用的存储类型,因此笔者会在后续的文章中,单独来详细介绍。

- csi类型,一种通过CSI来扩展存储的方式。这种方式允许所有实现了CSI(Container Storage Interface)接口的存储实现能够被POD引用,在POD初始化的过程中,CSI驱动会将存储卷attach到POD上。

上边罗列的只是数量巨大存储卷类型中很小一部分,每种类型都有对应的使用场景。笔者在本篇以及后续的文章中,着重介绍最具代表性的几个类型,来帮助大家理解Kubernetes存储体系。首先我们从最简单的emptyDir类型开始,这种类型的数据卷用来在容器重启场景中保持状态。

还记得我们在前边文章中介绍如何在同一个POD中部署两个容器实例的例子吗?当时的做法是通过post-start hook来执行fortune命令产生一个名言警句写入文件中,运行在另外一个容器中的Nginx服务器由于挂载了相同的volume,因此会直接将这个信息返回给客户端请求。这个保存fortune产生的名言警句的文件在容器的文件系统中,这就意味着当容器由于liveness probe三次失败重启后,你会看到不同的名言警句,虽然说看起来问题不大,但是从原理上讲,数据由于容器重启丢失。

我们来验证一下上边的推理是否符合事实,请在自己的本地环境中部署yunpan-fs.yaml,然后执行kubectl port-forward yunpan-fs 1080:80来创建客户端代理,访问服务返回名言警句。然后通过命令让Nginx重新启动,重新访问服务,你可以看到两次返回的数据不一致,这就证明了保存在容器文件系统的数据,在容器重启的场景下,不会保持。在笔者的本地环境输出如下图:

如上图所示,重启容器后会产生新的名言警句,这就意味着容器重启后保存在文件系统中的数据丢失了。如果我们要在这种重启的场景中保持数据状态,那么就必须确保数据被保存在数据卷中,而emptyDir是解决这个问题的完美方案。当emptyDir类型的数据卷被挂载到容器中,应用写到挂载目录的数据文件,在容器重启后,能够继续保持。

emptyDir类型的数据卷可以让容器即便是重启后,可以让写到文件中的数据状态保持;或者容器的文件系统为只读,但是应用在运行的过程中,需要写状态到文件中等场景,我们也可以使用emptyDir类型的数据卷来在同一个POD的多个容器之前,进行数据共享。

废话不多说了,咱直接修改fortune pod来把post-start hook执行fortune命令返回的名言警句写到emptyDir类型的数据卷中,这样当容器重启后,就不会出现数据丢失了。我们其实要修改的地方不多,主要包括:1,给POD增加emptyDir类型的数据卷定义;2,在容器中将这个数据卷挂载到指定的目录。

另外我们对命令的执行进行了一点点优化,post-start hook会在每次容器启动后都会执行,因此我们需要防止重启后对fortune命令输出对已经存在文件的覆盖,因此我们对post-start命令脚本也做了优化,如下图所示:

注:post-start hook脚本被更新成"ls /usr/share/nginx/html/quote || (apk add fortune && fortune > /usr/share/nginx/html/quote)",如果读者对Linux shell脚本不是很熟悉,这句肯定看的云里雾里,我们来稍微解释一下。首先ls命令先执行,我们这里用ls来检查quote文件是否存在,你有所不值得是,当ls后边给的文件存在的时候,命令返回0,而如果不存在,就返回非0。由于我们使用||将两个表达式进行了组合,因此当左边的ls quote执行成功,那么右边的语句就压根不会执行。通过这种方式,如果quote文件存在,那么咱就直接跳过了。而当文件不存在,才需要执行右边的一串命令,安装fortune和执行fortune来产生名言警句。这句脚本确保名言警句只被生成并写入一次,也就是只在容器第一次启动的时候。

如上图所示,我们定义了emptyDir类型的数据卷content,并挂载到nginx容器指定目录/usr/share/nginx/html(这个是Nginx服务器默认用来扫描静态资源的目录)。在POD中配置volume需要提供配置参数,接下来我们详细聊聊如何配置emptyDir类型的数据卷。

对于emptyDir类型的存储卷,Kubernetes要求配置如下两个属性:

- medium,文件夹的存储介质,如果留空不配置,那么默认就是宿主机的(工作节点)磁盘。除了磁盘之外,我们还可以配置Memory,这会导致数据卷使用tmpfs文件系统,这是一个在内存文件系统。

- sizeLimit,文件夹需要的磁盘空间大小,比如我们如果需要限制这个文件夹中文件的大小为10M,那么就可以设置为10Mi。

注:我们上边的例子中,emptyDir类型的数据卷content未显示的定义任何字段,取默认值,大括号非常明确的表达了这一点,但是并不是必须的。

在POD中定义完数据卷只完成了工作的一半,工作的另一半就是将数据卷挂载到容器实例中,这通过在容器spec.containers域通过volumeMounts来引用。volumeMounts除了要制定name之外,还需要包含mountPath字段,来指定数据卷被具体挂载到容器文件系统的文件目录树的那个路径。笔者上边提供的例子中,emptyDir类型的数据卷被挂载到了/usr/share/ngxin/html目录,因为这也是post-start hook将名言警句写到文件的路径。

由于使用了emptyDir类型的数据卷之后,名言警句被写入到了宿主机的文件系统,因此数据在POD的整个生命周期都会保持,因此我们无论重启nginx容器多少次,返回的数据(名言警句)都不应该有任何变化。

接下来,我们将这个新版本基于fortune命令的名言警句网站部署到Kubernetes集群,并人为的让nginx容器重启,你会发现无论我们重启多少次,quote接口返回的内容都一样。背后的原理是,因为我们只在容器第一次启动的时候,才创建quote文件,并且当容器重启重新挂载数据卷后,这个quote文件仍然存在。你可能会问,这个文件到底在宿主机的啥地方啊,可以运行kubectl exec yunpan-emptydir -- mount --list | grep nginx/html来发现,如下图所示:

如上图所示,通过使用emptyDir类型的数据局content,我们成功让容器重启之后,保持数据状态。接下来,我们继续看另外一个例子,如何通过数据卷在两个容器时间共享数据。

如笔者前边多次提到,我们也可以使用emptyDir类型的数据卷来在同一个POD中的两个容器之间共享数据,这里需要注意的是,我们无法通过emptyDir类型的数据卷在不同PDO中不同的容器间共享数据,请继续阅读。

我们基于fortune的名言警句网站目前略显无趣,因为每次都返回相同的谚语,我们希望这个行为能够增强,比如每30分钟更换一次。为了实现这个功能,我们需要将post-start hook替换成容器,并且在容器中,fortune命令每30秒运行一次。为了使大家学习更加容易,笔者已经构建好了需要的容器,并上传到Docker Hub,大家可以自行通过命令 docker pull qigaopan/yunpan-fortune:v1.0拉取。

好了,我们已经把需要的容器镜像都准备好了,接下来我们来编写POD的YAML文件,如下图所示:

如上图所示,emptyDir类型的数据卷被两个容器共享(共同挂载),容器fortune将数据写到content数据卷,在nginx容器中,相同的数据卷被以read-only的模式被挂载到nginx的默认目录。

注:我们在前边文章中反复强调过一个事实,同一个POD中的多个容器几乎是同时启动的,因此可能存在微小的一段时间,ngxin服务器已经成功运行起来,但是quote文件尚未生成。聪明的你可能想到了,要避免这种场景,我们可以使用初始化容器。

接着,我们将fortune POD部署到Kubernetes集群中,两个容器几乎同时开始运行。fortune容器每30秒更新一次谚语(名言警句),nginx容器基于相同的数据文件服务客户端请求,当POD中的两个容器都Ready后,可以验证一下输出,是否每30秒后,quote请求对应的谚语的返回会更新。

由于在fortune例子中emptyDir类型的数据卷会在宿主机的磁盘上创建共享目录,因此数据读写的性能,完全取决于工作节点上硬件的类型。如果我们的应用需要高性能的IO操作,那么磁盘可能不是最合适的存储介质。

Kubernetes允许我们使用tmpfs文件系统来创建数据卷,而tmpfs将数据保存在内存中,我们只需要在POD的YAML文件中,把emptyDir的字段meim设置为Memory。

其实Memory类型的数据卷除了提供较高的IO之外,数据安全性也比磁盘高。由于数据并没有落盘,因此数据不容易被恶意攻击者窃取,因此建议大家可以在自己的项目上考虑这种数据卷类型。另外我们也可以通过参数sizeLimit来约束数据卷的size,特别对于Memory类型的数据卷来说,请务必设置sizeLimit,以防内存被耗尽。

在前边的内容中,我们将目光主要集中在如何在POD中定义数据卷,而没有详细介绍volume是如何挂载到容器中的,接下来我们来看看在容器中挂载数据卷具体需要设置哪些参数。如下图所示,是我们在新版本的fortune POD定义中关于content数据卷挂载的配置:

从上图可以看出,挂载数据卷到容器中,我们需要至少配置两个字段:name和mountPath,其中name字段是我们在POD定义的数据卷的名字,而mountPath字段指定了数据卷应该挂载到容器文件系统的文件数的那个目录。

除了这两个必须提供的参数之外,我们还有一些可选的参数可以配置,详细的可配置参数清单如下:

- name字段,如笔者上边的介绍,name字段就是我们在POD中挂载的数据卷的name

- mountPath字段,前文应介绍,不累述

- readOnly字段,是否以只读的模式挂载数据卷,默认是false,也就是以读写的方式挂载数据卷。

- mountPropagation字段,设置如果在数据卷内部挂载额外的文件系统会发生什么。有几个选项,默认是none,指如果宿主机在数据卷中挂在了额外的文件系统,容器不会收到任何通知,反之亦然;还有两个选项HostToContainer和Bidirectional,具体含义如命名,如果要了解详情,可以参考官方文档。

- subPath字段,默认为“”,意味着整个数据卷都被挂载到mountPath指定的目录,当设置为非空的字符串后,只有subPath指定的文件路径被挂载到容器中

- subPathExpr字段,使用类似于shell提供的$(ENV_VAR_NAME)语句,只能使用环境变量。

在大部分场景下,我们只需要设置name和mountPath就可以了,顶多额外多配置参数readOnly。mountPropagation参数只有在一些复杂配置的场景下才会用到,当我们用一个数据卷来提供不同的文件夹给不同的容器的时候,subPath和subPathExpr非常有用。另外这两个参数也可以用作多个PDO共享一个数据卷的场景。

好了,这篇文章的内容就这么多了,下篇文章我们继续介绍存储,看看如何访问宿主机文件系统中的数据文件,敬请期待!

C. kubernetes(十一) 数据存储(挂载卷管理)

在前面已经提到,容器的生命周期可能很短,会被频繁地创建和销毁。那么容器在销毁时,保存在容器中的数据也会被清除。这种结果对用户来说,在某些情况下是不乐意看到的。为了持久化保存容器的数据,kubernetes引入了Volume的概念。

Volume是Pod中能够被多个容器访问的共享目录,它被定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下,kubernetes通过Volume实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储。Volume的生命容器不与Pod中单个容器的生命周期相关,当容器终止或者重启时,Volume中的数据也不会丢失。销帆宴

kubernetes的Volume支持多种类型,比较常见的有下面几个:

EmptyDir是最基础的Volume类型,一个EmptyDir就是Host上的一个空目录。

EmptyDir是在Pod被分配到Node时创建的,它的初始内容为空,并且无须指定宿主机上对应的目录文件,因为kubernetes会自动分配一个目录,当Pod销毁时, EmptyDir中的数据也会被永久删除。 EmptyDir用途如下:

接下来,通过一个容器之间文件共享的案例来使用一下EmptyDir。

在一个Pod中准备两个容器nginx和busybox,然后声明一个Volume分别挂在到两个容器的亏银目录中,然后nginx容器负责向Volume中写日志,busybox中通过命令将日志内容读到控制台。

创建一个volume-emptydir.yaml

EmptyDir中数据不会被持久化,它会随着Pod的结束而销毁,如果想简单的将数据持久化到主机中,可以选择HostPath。

HostPath就是将Node主机中一个实际目录挂在到Pod中,以供容器使用,这样的设计就可以保证Pod销毁了,但是数据依据可以存在于Node主机上。

创建一个volume-hostpath.yaml:

HostPath可以解决数据持久化的问题,但是一旦Node节点故障了,Pod如果转移到了别的节点,又会出现问题了,此时需要准备单独的网络存储系统,比较常用的用NFS、CIFS。

NFS是一个网络文件存储系统,可以搭建一台NFS服务器,然后将Pod中的存储直接连接到NFS系统上,这样的话,无论Pod在节点上怎么转移,只要Node跟NFS的对接没问题,数据就可以成功访问。

1)首先要准备nfs的服务器,这里为了简单,直接是master节点做nfs服务器

2)接下来,要在的每个node节点上都安装下nfs,这样的目的是为了node节点可以驱动nfs设备

3)接下来,就可以编写pod的配置文件了,创建volume-nfs.yaml

4)最后,运行下pod,观察结果

前面已经学习了使用NFS提供存储,此时就要求用户会搭建NFS系统,并且会在yaml配置nfs。由于kubernetes支持的存储系统有很多,要求客户全都掌握,显然不现实。为了能够屏蔽底层存储实现的细节,方便用户使用, kubernetes引入PV和PVC两种资源对象。

PV(Persistent Volume)是持轿培久化卷的意思,是对底层的共享存储的一种抽象。一般情况下PV由kubernetes管理员进行创建和配置,它与底层具体的共享存储技术有关,并通过插件完成与共享存储的对接。

PVC(Persistent Volume Claim)是持久卷声明的意思,是用户对于存储需求的一种声明。换句话说,PVC其实就是用户向kubernetes系统发出的一种资源需求申请。

使用了PV和PVC之后,工作可以得到进一步的细分:

PV是存储资源的抽象,下面是资源清单文件:

PV 的关键配置参数说明:

实验
使用NFS作为存储,来演示PV的使用,创建3个PV,对应NFS中的3个暴露的路径。
1.准备NFS环境

2.创建pv.yaml

PVC是资源的申请,用来声明对存储空间、访问模式、存储类别需求信息。下面是资源清单文件:

PVC 的关键配置参数说明:

实验
1.创建pvc.yaml,申请pv

2.创建pods.yaml, 使用pv

PVC和PV是一一对应的,PV和PVC之间的相互作用遵循以下生命周期:

ConfigMap是一种比较特殊的存储卷,它的主要作用是用来存储配置信息的。

创建configmap.yaml,内容如下:

接下来,使用此配置文件创建configmap

接下来创建一个pod-configmap.yaml,将上面创建的configmap挂载进去

在kubernetes中,还存在一种和ConfigMap非常类似的对象,称为Secret对象。它主要用于存储敏感信息,例如密码、秘钥、证书等等。

1.首先使用base64对数据进行编码

2.接下来编写secret.yaml,并创建Secret

3.创建pod-secret.yaml,将上面创建的secret挂载进去:

至此,已经实现了利用secret实现了信息的编码。

D. K8s怎么对象分布式存储

K8s对象分布式存储的方式很多,我们用的元核云分布式块存储,用的就是ceph-csi对接的他们的rbd块存储。

E. microk8s上给Pod挂载NFS

团队新开发的区域医疗平台包含一个课件上传与播放模块,其实际的业务包含如下的步骤:

1.  县级和乡镇卫生院的医生们通过在线视频参加培训、并录制视频。

2. 医生上传视频,并共享课件。

3.  平台上的其他医生可以在课件学习栏目学习录制的培训会议。

通常,课件的上传和保存我们都是通过对象存储做的,对象存储的好处显而易见:不担心文件丢失(三份备份), 不担心容量(云服务商集群),https/http访问, 数据安全(对象访问签名);  但是这个平台需要部署到区域医疗机构的机房里,多数情况下是没有对象存储的,外购对象存储也成本过高, 所以我们采用了折中的方案,存储系统换为NFS, 只需要一个大存储量的机器就可以了,大概服务如下:

我们开发了一个uploader服务,用于上传文件,同时使用Nginx提供http/https服务,两个服务之间共享存储,使用NFS存储挂载给他们。

这里我们来看看怎么给microk8s上的pod挂载NFS存储。

首先,我们需要安装NFS server 用于测试

我们使用ubuntu来进行测试,先执行命令:sudo apt install nfs-kernel-server

这个命令将安装服务器端,以及所有相关的包:

在home目录下创建一个nfsshare的文件夹用作共享目录。然后我们来编辑nfs配置文件,配置该共享目录,默认允许所有IP段挂在:

启动nfs: sudo /etc/init.d/nfs-kernel-server start

可以使用服务命令查看服务状态: service nfs-kernel-server   status

使用ip addr命令查看以下当前主机的IP:

现在我们来使用nfsclient端测试一下:

sudo mount 10.0.2.15:/home/nfsshare   /mnt

查询 /mnt 目录,可以看到在 /home/nsshare下面创建的文件和子目录

测试完后umount 挂载点:  sudo umount -v /mnt

1. 先写一个PV, 用来表示可以挂载的NFS存储:

2. 接着写一个PVC,用于绑定PV:

3. 然后写包装了nginx的存储服务的deployment文件:

4. 最后写存储服务对应的service文件:

完成了所有配置文件,使用microk8s kubectl apply -f 命令,依次创建资源对象。

查询创建的pod:

使用exec 登陆docker,

查询/usr/share/storage目录,如下图,nfs已经挂载好了,可以看见我们在test目录下创建了几个文件:

最后,我们来验证一下http方式访问文件

现在storage的nfs目录下创建两个子目录,attachement、video , 对应docker的挂在路径为: /usr/share/storage/atttachment、/usr/share/storage/video。 

在两个文件夹下面,分别创建两个文件 helloA.txt  helloB.txt, 并随意写写内容。

完成后我们通过30080端口,从microk8s节点的浏览器访问两个文件:

至此,在k8s下,给pod挂在nfs的工作,并通过http访问的任务就完了。另外:

1.   后续需要考虑,通过Lua写一个脚本和nginx集成,实现访问资源签名验证,这个机制可以很容易的参考对象存储的验证。

2. 这里没有讨论,如何写upload和制作storage服务的镜像,upload服务也需要挂载nfs,原理是一样的,所以就不再讨论。 storage服务是基于Nginx镜像实现,下面的附录了带上了可参考的配置文件。

==============================================================

附录A: storageservice服务中,nginx的配置文件storage.conf

附录B:  storageservice服务中dockerfile文件

附录C: Storageservice的build.gradle文件

参考 一个Springboot项目的build.gradle和Dockerfile ,  这里的buiild.gradle文件不需要java build, 仅需要用来生成新docker镜像。

F. 什么是K8S

k8s全称kubernetes,这个名字大家应该都不陌生,k8s是为容器服务而生的一个可移植容器的编排管理工具,越来越多的公司正在拥抱k8s,并且当前k8s已经主导了云业务流程,推动了微服务架构等热门技术的普及和落地,正在如火如荼的发展。想要了解更多,我推荐你去看看时速云,他们是一家全栈云原生技术服务提供商,提供云原生应用及数据平台产品,其中涵盖容器云PaaS、DevOps、微服务治理、服务网格、API网关等。大家可以去体验一下。
希望能给您提供帮助,可以给个大大的赞不。

G. 如何进行K8S存储系统

在K8S运行的服务,从简单到复杂可以分成三类:无状态服务、普通有状态服务和有状态集群服务。下面分别来看K8S是如何运行这三类服务的。

无状态服务,K8S使用RC(或更新的Replica Set)来保证一个服务的实例数量,如果说某个Pod实例由于某种原因Crash了,RC会立刻用这个Pod的模版新启一个Pod来替代它,由于是无状态的服务,新启的Pod与原来健康状态下的Pod一模一样。在Pod被重建后它的IP地址可能发生变化,为了对外提供一个稳定的访问接口,K8S引入了Service的概念。一个Service后面可以挂多个Pod,实现服务的高可用。

普通有状态服务,和无状态服务相比,它多了状态保存的需求。Kubernetes提供了以Volume和Persistent Volume为基础的存储系统,可以实现服务的状态保存。

有状态集群服务,与普通有状态服务相比,它多了集群管理的需求。K8S为此开发了一套以Pet Set为核心的全新特性,方便了有状态集群服务在K8S上的部署和管理。具体来说是通过Init Container来做集群的初始化工作,用Headless Service来维持集群成员的稳定关系,用动态存储供给来方便集群扩容,最后用Pet Set来综合管理整个集群。

要运行有状态集群服务要解决的问题有两个,一个是状态保存,另一个是集群管理。我们先来看如何解决第一个问题:状态保存。Kubernetes有一套以Volume插件为基础的存储系统,通过这套存储系统可以实现应用和服务的状态保存。

K8S的存储系统从基础到高级又大致分为三个层次:普通Volume,Persistent Volume和动态存储供应。

1.普通Volume

最简单的普通Volume是单节点Volume。它和Docker的存储卷类似,使用的是Pod所在K8S节点的本地目录。

第二种类型是跨节点存储卷,这种存储卷不和某个具体的K8S节点绑定,而是独立于K8S节点存在的,整个存储集群和K8S集群是两个集群,相互独立。

跨节点的存储卷在Kubernetes上用的比较多,如果已有的存储不能满足要求,还可以开发自己的Volume插件,只需要实现Volume.go里定义的接口。如果你是一个存储厂商,想要自己的存储支持Kubernetes上运行的容器,就可以去开发一个自己的Volume插件。

2.persistent volume

它和普通Volume的区别是什么呢?

普通Volume和使用它的Pod之间是一种静态绑定关系,在定义Pod的文件里,同时定义了它使用的Volume。Volume是Pod的附属品,我们无法单独创建一个Volume,因为它不是一个独立的K8S资源对象。

而Persistent Volume简称PV是一个K8S资源对象,所以我们可以单独创建一个PV。它不和Pod直接发生关系,而是通过Persistent Volume Claim,简称PVC来实现动态绑定。Pod定义里指定的是PVC,然后PVC会根据Pod的要求去自动绑定合适的PV给Pod使用。

H. k8s之存储

k8s的存储常用的就是上面几种模式,分为临时存储,半持久化存储,与持久化存储这三类,本章我们着重讲解emptydir与hostpath与pvc跟pv等

当pod的存储方案设定为emptydir的时候,pod启动时,就会在pod所在节点的磁盘空间开辟出一块空卷,最开始里面是什么都没有的,pod启动后容器产生的数据会存放到那个空卷中。空卷变成了一个临时卷

供pod内的容器读取和写入数据,一旦pod容器消失,节点上开辟出的这个临时卷就会随着pod的销毁而销毁

一般来说emptydir的用途都是用来充当临时存储空间,例如一些不需要数据持久化的微服务,我们都可以用emptydir来当做微服务pod的存储方案

k8s存储emptdir实战例子:以之前的myapp应用为例

创建应用

观察是否生产data目录,并在/data目录创建文件test.txt

手动删除容器模拟容器销毁,用于是pod是被控制器管理的,删除后会被重建新的pod

这时候在看我们之前创建的data.txt已经不见了

hostPath类型则是映射node文件系统中的文件或者目录到pod里。在使用hostPath类型的存储卷时,也可以设置type字段,支持的类型有文件、目录、File、Socket、CharDevice和BlockDevice(我只映射过文件与目录)。

其实这个功能就相当于docker中的-v 目录映射,只不过在k8s中的时候,pod会漂移,当pod漂移到其他node节点的时候,pod不会跨节点的去读取目录。所以说hostpath只能算一种半持久化的存储方式

实战例子

创建应用

在node节点可以看到生成了/data/volume目录,在里面创建测试文件

检验pod里面的/data是否存在这个映射目录的文件

可以看到刚才创建的文件已经映射到我们的目录里边了

为了验证是否映射到容器里面的目录也会随着pod生命周期的消失而消失,我们手动删除pod模拟容器终止

可以看到容器被删除后,新建的pod也可以看到我们映射的目录,而且里面数据test.txt还在。

这有个缺点就是不能够跨容器去读取数据,如果删除后的pod被调度到其他节点的话,原来的数据也就没有了,如果能不受节点的影响,并且挂载的数据不会随生命周期的结束而结束,我们应该怎么解决呢?就是我们后面讲到的持久化存储了

上面介绍了俩种临时存储于半持久化存储的方案。在k8s实际生产环境中,一般会选用私有云持久化存储方案还有公有云持久化存储方案,私有云存储方案包括nfs,ceph,glusterfs等方案。公有云存储会用到AWS等方案

存储方案各有各的优缺点,可参考 https://www.cnblogs.com/yswenli/p/7234579.html 这篇文章。今天我们主要讲解pvc,pv,nfs之间的关系。

简单来说,要使用持久化存储,就需要使用pvc去跟pv去申请,然后pv查看自己有没有合适的存储空间卷,有合适的就与pvc进行绑定。pv与pvc是一一对应绑定的。现在我们用一幅图来说明pvc,pv,nfs的关系

实战例子

准备存储服务安装nfs

接下来创建pv与nfs绑定

创建pvc与pv关联

创建并查看结果

注意:STATUS为Bound说明该pvc已经与pv绑定了

接下来创建pod来引用pvc

创建pod

接下来验证一下在nfs创建一个测试文件,看是否被映射到容器中

可以看到容器里面也可以看到创建的文件

手动删除容器,或者调度到其他节点原来的文件还是不会被删除的,这里就省略验证了,这就是nfs的好处,不过企业一般不会选用nfs,磁盘IO,性能读取方面不太理想,毕竟是本地存储,还是有一定的风险。推荐用用云存储。

文件存储提供无限扩展的文件系统来给云服务器存取数据实际上相当于nfs

1、已注册阿里云账号,并完成实名认证。

如果没有,请先注册阿里云账号,详情请参见阿里云账号注册流程。

2、已开通NAS服务。

首次登录NAS控制台时,根据页面提示开通NAS服务。

3、在需要创建文件系统的地域,已有可用的云服务器ECS。

k8s应用NAS实战例子

1、打开阿里云NAS控制台确认已创建好文件系统

2、把复制挂载参数把它挂载到服务器中创建测试目录,前提是服务器需要安装nfs客户端。

安装完成挂载到本地目录并创建test目录作为测试目录

并在里面创建一个测试文件1.txt

接下来可以创建pvc和pv了

创建并查看

接下来创建pod去引用pvc

创建pod

检验刚才的1.txt是否挂到容器的/data/nas下

云存储适合于生产环境k8s的存储解决方案

I. 通过K8S部署对象存储MinIO

MinIO 是全球领先的对象存储先锋,以 Apache License v2.0 发布的对象存储服务器,是为云应用和虚拟机而设计的分布式对象存储服务器。在标准硬件上,读/写速度上高达183GB/s和171GB/s。它与 Amazon S3 云存储服务兼容。 它最适用于存储非结构化数据,如照片、视频、日志文件、备份和容器/虚拟机映像。 对象的大小可以从几KB 到最大5TB。

MinIO是一个非常轻量的服务,可以很简单的和其他应用的结合,类似 NodeJS, Redis 或者 MySQL。

MinIO支持多种灵活的部署方式,支持Docker Compose、Docker Swam、Kubernetes等,详见官网: https://docs.min.io/docs/minio-deployment-quickstart-guide.html 或者 https://min.io/download#/linux

这里着重介绍K8S下部署

1、standalone模式

由于service采用NodePort类型,通过主机IP:32593访问web

2、distributed模式

分布式部署,实例数至少4个,所以需要另外创建4个pv