|
Kubernetes的存储设计考量
在开始以前,我想先标明一下我对Kubernetes存储才能的态度。Kubernetes在布局耐久化存储才能的时分,仍然遵守着它的一向设计哲学,用户担任以资源和声明式API来形容本人的用意,Kubernetes担任按照用户用意来实现详细的操作。不外我以为,就算只是形容分明用户的存储用意,也不是一件容易的事件,比拟Kubernetes提供的其余才能的资源,它内置的存储资源其实分外地繁杂,乃至能够说是有些繁琐的。
假如你是Kubernetes的拥趸,不克不及认同我对Kubernetes的批判,那无妨来看一看以下环抱着“Volume”所衍生出的概念,它们仅仅是与Kubernetes存储相干概念的一个子集罢了,你在看的时分也能够来思考一下,这些概念是不是全都是必需的、是不是还有整合的空间、是不是有化繁为简的可能性:
概念:Volume、PersistentVolume、PersistentVolumeClaim、Provisioner、StorageClass、Volume Snapshot、Volume Snapshot Class、Ephemeral Volumes、FlexVolume Driver、Container Storage Interface、CSI Volume Cloning、Volume Limits、Volume Mode、Access Modes、Storage Capacity……操作:Mount、Bind、Use、Provision、Claim、Reclaim、Reserve、Expand、Clone、Schedule、Reschedule……其实啊,Kubernetes之所以有如斯多对于存储的术语概念,最首要的缘故是存储技术原本就有得多品种,为了尽量多地兼容各种存储,Kubernetes不能不预置了得多In-Tree(意思是在Kubernetes的代码树里)插件来对接,让用户按照本人的业务按需选择。
同时,为了兼容那些不在预置规模内的需要场景,Kubernetes也反对用户使用FlexVolume或者CSI来定制Out-of-Tree(意思是在Kubernetes的代码树以外)的插件,完成更为丰硕多样的存储才能。下表中列出了Kubernetes目条件供的一部份存储与扩展的插件:
qucilvmffqs.jpg
事实上,迫使Kubernetes存储设计得如斯繁杂的缘故,除了是要扩张兼容范畴以外,还有一个非技术层面的要素,就是Kubernetes是一个工业级的、面向出产运用的容器编排零碎。
而这就象征着,即便Kubernetes发现了某些已存在的功用有更好的完成形式,但直到旧版本被淘汰出世产环境之前,本来已反对的功用都不允许忽然间被移除或者交换掉。不然,当出产零碎更新版本时,已有的功用就会泛起异样,那就会极大要挟到产品的信用。
固然,在一定水平上,咱们能够谅解Kubernetes为了完成兼容而致使的繁琐,但这样的设计的确会让Kubernetes的学习曲线变得更为峻峭。
Kubernetes提供的民间文档的次要作用是为实际开发提供参考,它其实不会告知你Kubernetes中各种概念的演变历程、版本公布新功用的时间线、改变的原由与配景等信息,只会以“平整”的形式来陈说一切目前可用的功用,这可能无利于纯熟的办理员疾速查问到症结信息,却无益于初学者去了解Kubernetes的设计思想。
如斯一来,由于很难了解那些概念和操作的本意,初学者往往就只能融会贯通,很难分辨出它们应该如何被“更正确”地使用。而引见Kubernetes设计理念的职责,只能由Kubernetes民间的Blog 这种信息渠道,或者其余非民间材料去实现。
所以接上去,我会从Volume的概念开始,以操作零碎到Docker,再到Kubernetes的演进历程为主线,带你去梳理后面提到的那些概念与操作,以此帮你更好地舆解Kubernetes的存储设计。
首先,咱们来看看Mount和Volume这两个概念。
Mount和Volume
Mount和Volume都是来源于操作零碎的罕用术语,Mount是动词,表现将某个内部存储挂载到零碎中;Volume是名词,表现物理存储的逻辑笼统,目的是为物理存储提供有弹性的联系形式。
而咱们知道,容器是源于对操作零碎层的虚构化,为了知足容器内生成数据的内部存储需要,咱们也很天然地会把Mount和Volume的概念延至容器中。因此,要想理解容器存储的开展,咱们无妨就以Docker的Mount操作为起始点。
目前,Docker内建反对了三种挂载类型,分别是Bind(--mount type=bind)、Volume(--mount type=volume)和tmpfs(--mount type=tmpfs),如下图所示。其中,tmpfs次要用于在内存中读写暂时数据,跟咱们这个小章节要探讨的对象“耐久化存储”其实不相符,所当前面咱们只侧重关注Bind和Volume两种挂载类型就能了。
vbvlft4a5ol.jpg
(图片来自Docker官网文档)
咱们先来聊聊Bind。
Bind Mount是Docker最先提供的(公布时就反对)挂载类型,作用是把宿主机的某个目录(或文件)挂载到容器的指定目录(或文件)下,好比上面命令中,参数-v表白的意思就是把内部的HTML文档,挂到Nginx容器的默许网站根目录下:
docker run -v /icyfenix/html:/usr/share/nginx/html nginx:latest
请留意,虽然命令中-v参数是--volume的缩写,但-v最后只是用来创立Bind Mount,而不是创立Volume Mount的。
这类蛊惑的行动其实也并非Docker的本意,只是由于Docker刚公布的时分斟酌得不敷周全,马马虎虎就在参数中占用了“Volume”这个词,到起初真的需求扩展Volume的概念来反对Volume Mount的时分,后面的-v曾经被用户普遍使用了,所以也就只能如斯将就着持续用。
从Docker 17.06版本开始,Bind就在Docker Swarm中借用了--mount参数过去,这个参数默许创立的是Volume Mount,用户能够经过明白的type子参数来指定此外两种挂载类型。好比说,后面给到的命令,就能等价于上面所示的--mount版本:
docker run --mount type=bind,source=/icyfenix/html,destination=/usr/share/nginx/html nginx:latest
从Bind Mount到Volume Mount,本质上是容器开展过程当中对存储笼统才能晋升的内在表示。咱们按照“Bind”这个名字,以及Bind Mount的实际功用,其实能够公道地揣测,Docker最后以为“Volume”就只是一种“内部宿主机的磁盘存储到外部容器存储的映照瓜葛”,但起初它眉头紧皱,发现事件并无那末简略:存储的地位其实不局限只在内部宿主机,存储的介质其实不局限只是物理磁盘,存储的办理也其实不局限只要映照瓜葛。
我给你举几个例子。
好比,Bind Mount只能让容器与当地宿主机之间建设某个目录的映照,那末假如想要在不同宿主机上的容器同享同一份存储,就必需先把同享存储挂载到每一个台宿主机操作零碎的某个目录下,而后能力逐一挂载到容器内使用,这类跨宿主机同享存储的场景如下图所示:
lxfr32ujxzw.jpg
(图片来自Docker官网文档)
这类存储规模超出了宿主机的同享存储,配置进程却要波及到少量与宿主机环境相干的操作,只能由办理员人工地去实现,不只繁琐,并且因为每台宿主机环境的差别,还会致使主机很难完成自动化。
再好比,即便只斟酌单台宿主机的状况,基于可办理性的需要,Docker也彻底有反对Volume Mount的须要。为何这么说呢?
实际上,在Bind Mount的设计里,Docker只要容器的管制权,寄放容器出产数据的主机目录是彻底独立的,与Docker没有任何瓜葛,它既不受Docker维护,也不受Docker办理。所以这就使得数据很容易被其余过程拜候到,乃至是被修正和删除。假如用户想对挂载的目录进行备份、迁徙等办理运维操作,也只能在Docker以外靠办理员人工进行,而这些都减少了数据平安与操作不测的危险。
因此,Docker但愿能有一种笼统的资源,来代表在宿主机或网络中存储的区域,以便让Docker能办理这些资源,这样就很天然地联想到了操作零碎里的Volume。
提出Volume最中心的一个目的,是为了晋升Docker对不同存储介质的撑持才能,这同时也是为了加重Docker自身的任务量。
要知道,存储并非只要挂载在宿主机上的物理存储这一种介质。在云计算时期,网络存储逐步成了数据核心的主流选择,不同的网络存储都有各自的协定和交互接口。并且,并非一切的存储零碎都合适先挂载到操作零碎,而后再挂载到容器的,假如Docker想要越过操作零碎去反对挂载某种存储零碎,首先必需要知道该如何拜候它,而后能力把容器中的读写操作自动转移到该地位。
Docker把解决如何拜候存储的功用模块叫做存储驱动(Storage Driver)。经过docker info命令,你能查看到以后Docker所反对的存储驱动。虽然Docker曾经内置了市面上主流的OverlayFS驱动,好比Overlay、Overlay2、AUFS、BTRFS、ZFS等等,但面对云计算的疾速迭代,只靠Docker本人来反对整个云计算厂商的存储零碎是彻底不理想的。
为此,Docker就提出了与Storage Driver相对于应的Volume Driver(卷驱动)的概念。
咱们能够经过docker plugin install命令装置内部的卷驱动,并在创立Volume时,指定一个与其存储零碎相婚配的卷驱动。好比,咱们但愿数据存储在AWS Elastic Block Store上,就找一个AWS EBS的驱动;假如想存储在Azure File Storage上,也是找一个对应的Azure File Storage驱动便可。
而假如在创立Volume时,不指定卷驱动,那默许就是local类型,在Volume中寄放的数据就会存储在宿主机的/var/lib/docker/volumes/目录之中。
Static Provisioning
好了,理解了Mount和Volume的概念含意之后,当初咱们把探讨配角转回容器编排零碎上。
这里,咱们会从存储如何调配、耐久存储与非耐久存储的差别登程,来详细学习下Static Provisioning的设计。
首先咱们能够明白一件事,即Kubernetes一样是把操作零碎和Docker的Volume概念连续了上去,并对其进行了进一步的细化。
Kubernetes把Volume分为了耐久化的PersistentVolume和非耐久化的普通Volume两类,这里为了避免跟我后面定义的Volume这个概念发生混杂,前面课程我提到的Kubernetes中非耐久化的Volume时,都会带着“普通”这个前缀。
普通Volume的设计指标并非为了耐久地保留数据,而是为同一个Pod中多个容器提供可同享的存储资源,所以普通Volume的生命周期十分明白,也就是与挂载它的Pod有着相反的生命周期。
这样,就象征着只管普通Volume不具备耐久化的存储才能,但最少比Pod中运转的任何容器的存活期都更长,Pod中不同的容器能同享相反的普通Volume,当容器从新启动时,普通Volume中的数据也可以失掉保存。
固然,一旦全部Pod被烧毁,普通Volume也就不复存在了,数据在逻辑上也会被烧毁掉。至于实际中是不是会真正删除数据,就取决于存储驱动详细是如何完成Unmount、Detach、Delete接口的(这个小章节的主题是“耐久化存储”,所以对于无耐久化才能的普通Volume,我就再也不展开了)。
如斯一来,从操作零碎里传承上去的Volume概念,就在Docker和Kubernetes中持续根据统一的逻辑延长拓展了,只不外Kubernetes为了把它跟普通Volume区分开来,专门取了PersistentVolume这个名字。你能够从下图中直观地看出普通Volume、PersistentVolume和Pod之间的瓜葛差别:
ebvr5qxwt01.jpg
其实,咱们从Persistent这个单词的意思,就可以大抵理解PersistentVolume的含意,它是指可以将数据进行耐久化存储的一种资源对象。
PersistentVolume能够独立于Pod存在,生命周期与Pod有关,所以也就抉择了PersistentVolume不该该附丽于任何一个宿主机节点,不然必定会对Pod调度发生搅扰限度。咱们在后面“Docker的三种挂载类型”图例中,能够看到“Persistent”一列里都是网络存储,这即是很好的印证。
额定常识:Local PersistentVolume关于部署在云端数据核心的零碎,经过网络拜候同一个可用区中的近程存储,速度是彻底能够承受的。但关于公有部署的零碎来讲,基于机能斟酌,使用当地存储往往会更为常见。因此,斟酌到这样的实际需要,从1.10版起,Kubernetes开始反对Local PersistentVolume,这是一种将一整块当地磁盘作为PersistentVolume供容器使用的公用计划。所谓的“公用计划”就是字面意思,它其实不合用于整个运用,Local PersistentVolume只是针对以磁盘I/O为瓶颈的特定场景的解决计划,于是它的反作用就很显著:因为不克不及包管这类当地磁盘在每个节点中都一定存在,所以Kubernetes在调度时就必需斟酌到PersistentVolume散布状况,只能把使用了Local PersistentVolume的Pod调度到有这类PersistentVolume的节点上。只管调度器中专门有个Volume Binding Mode模式来反对这项处置,然而一旦使用了Local PersistentVolume,仍是会限度Pod的可调度规模。那末,在把PersistentVolume与Pod别离后,就需求专门斟酌PersistentVolume该如何被Pod所援用的问题了。
实际上,本来在Pod中援用其余资源是常有的事,要末是经过资源称号间接援用,要末是经过标签选择器(Selectors)直接援用。然而相似的办法在这里却都不太得当,至于缘故,你能够先思考一下:“Pod该使用何种存储”这件事件,应该是零碎办理员(运维人员)说的算,仍是由用户(开发人员)说的算?
要我看,最公道的谜底是他们一同说的才算,由于只要开发能精确评价Pod运转需求损耗多大的存储空间,只要运维能分明地知道以后零碎能够使用的存储装备情况。
所以,为了让这两者可以各自提供本人长于的信息,Kubernetes又额定设计出了PersistentVolumeClaim资源。
其真实Kubernetes民间给出的概念定义中,也特别强调了PersistentVolume是由办理员(运维人员)担任保护的,用户(开发人员)经过PersistentVolumeClaim,来婚配到符合需要的PersistentVolume。
PersistentVolume & PersistentVolumeClaimA PersistentVolume (PV) is a piece of storage in the cluster that has been provisioned by an administrator.A PersistentVolumeClaim (PVC) is a request for storage by a user.PersistentVolume是由办理员担任提供的集群存储。PersistentVolumeClaim是由用户担任提供的存储申请。—— Kubernetes Reference Documentation,Persistent VolumesPersistentVolume是Volume这个笼统概念的具象化表示,艰深点儿说,即它是曾经被办理员调配好的详细的存储。
这里的“详细”是指有明白的存储零碎地址,有明白的容量、拜候模式、存储地位等信息;而PersistentVolumeClaim是Pod对其所需存储才能的声明,艰深地说就是“假如要知足这个Pod正常运转,需求知足怎么样的前提”,好比要损耗多大的存储空间、要反对怎么样的拜候形式。
所以,实际上办理员和用户并非谁援用谁的固定瓜葛,而是按照实际状况静态婚配的。
上面咱们就来看看这二者配合任务的详细进程:
办理员筹备好要使用的存储零碎,它应该是某种网络文件零碎(NFS)或者云贮存零碎,个别来讲应该具备跨主机同享的才能。办理员会按照存储零碎的实际状况,手工事后调配好若干个PersistentVolume,并定义好每个PersistentVolume能够提供的详细才能。如上面例子所示:apiVersion: v1 kind: PersistentVolume metadata: name: nginx-html spec: capacity: storage: 5Gi # 最大容量为5GB accessModes: - ReadWriteOnce # 拜候模式为RXO persistentVolumeReclaimPolicy: Retain # 回收战略是Retain nfs: # 存储驱动是NFS path: /html server: 172.17.0.2
这里咱们来简略剖析下以上YAML中定义的存储才能:
存储的最大容量是5GB。存储的拜候模式是“只能被一个节点读写挂载”(ReadWriteOnce,RWO),此外两种可选的拜候模式是“能够被多个节点以只读形式挂载”(ReadOnlyMany,ROX)和“能够被多个节点读写挂载”(ReadWriteMany,RWX)。存储的回收战略是Retain,即在Pod被烧毁时其实不会删除数据。此外两种可选的回收战略分别是Recycle ,即在Pod被烧毁时,由Kubernetes自动履行rm -rf /volume/*这样的命令来自动删除材料;以及Delete,它让Kubernetes自动调用AWS EBS、GCE PersistentDisk、OpenStack Cinder这些云存储的删除指令。存储驱动是NFS,其余常见的存储驱动还有AWS EBS、GCE PD、iSCSI、RBD(Ceph Block Device)、GlusterFS、HostPath,等等。用户按照业务零碎的实际状况,创立PersistentVolumeClaim,声明Pod运转所需的存储才能。如上面例子所示:kind: PersistentVolumeClaim apiVersion: v1 metadata: name: nginx-html-claim spec: accessModes: - ReadWriteOnce # 反对RXO拜候模式 resources: requests: storage: 5Gi # 最小容量5GB
能够看到,在以上YAML中,声明了要求容量不得小于5GB,必需反对RWO的拜候模式。
Kubernetes在创立Pod的过程当中,会按照零碎中PersistentVolume与PersistentVolumeClaim的供需瓜葛,对二者进行撮合,假如零碎中存在知足PersistentVolumeClaim声明中要求才能的PersistentVolume,就表现撮分解功,它们将会被绑定。而假如撮合不可功,Pod就不会被持续创立,直到零碎中泛起新的、或让出闲暇的PersistentVolume资源。以上几步都顺利实现的话,象征着Pod的存储需要失掉知足,进而持续Pod的创立进程。以上的全部运作进程如下图所示:
0ftapmdzujk.jpg
(图片来自《Kubernetes in Action》)
Kubernetes对PersistentVolumeClaim与PersistentVolume撮合的后果是发生一对一的绑定瓜葛,“一对一”的意思是PersistentVolume一旦绑定在某个PersistentVolumeClaim上,直到释放之前都会被这个PersistentVolumeClaim所独占,不克不及再与其余PersistentVolumeClaim进行绑定。
这象征着即便PersistentVolumeClaim请求的存储空间比PersistentVolume可以提供的要少,仍然要求全部存储空间都为该PersistentVolumeClaim所用,这有可能会形成资源的挥霍。
好比,某个PersistentVolumeClaim要求3GB的存储容量,以后Kubernetes手上只剩下一个5GB的PersistentVolume了,此时Kubernetes只好将这个PersistentVolume与请求资源的PersistentVolumeClaim进行绑定,平白挥霍了2GB空间。
假定后续有另外一个PersistentVolumeClaim请求2GB的存储空间,那它也只能等候办理员调配新的PersistentVolume,或者有其余PersistentVolume被回收之后,才被能胜利调配。
Dynamic Provisioning
关于中小范围的Kubernetes集群,PersistentVolume曾经可以知足有形态运用的存储需要。PersistentVolume依托人工染指来调配空间的设计虽然简略直观,却算不上是先进,一旦运用范围增大,PersistentVolume很难被自动化的问题就会凸显出来。
这是因为Pod创立过程当中需求去挂载某个Volume时,都要求该Volume必需是实在存在的,不然Pod启动可能依赖的数据(如一些配置、数据、内部资源等)都将无从读取。Kubernetes虽然有才能跟着流量压力和硬件资源情况,自动扩缩Pod的数量,然而当Kubernetes自动扩展出一个新的Pod后,并无方法让Pod去自动挂载一个还未被调配资源的PersistentVolume。
想解决这个问题,要末允许多个不同的Pod都共用相反的PersistentVolumeClaim,这类计划的确只靠PersistentVolume就可以解决,却损失了隔离性,难以通用;要末就要求每个Pod用到的PersistentVolume都是曾经被事后建设并调配好的,这类计划靠办理员提前手工调配好少量的存储也能够完成,却损失了自动化才能。
无论哪一种状况,都难以合乎Kubernetes工业级编排零碎的产品定位,关于大型集群,面对成千盈百,来自不计其数的Pod,靠办理员手工调配存储确定是无奈实现的。在2017年Kubernetes公布1.6版本后,终于提供了明天被称为Dynamic Provisioning的静态存储解决计划,让零碎办理员开脱了人工调配的PersistentVolume的困境,并把此前的调配形式称为Static Provisioning。
那Dynamic Provisioning计划是如何解放零碎办理员的呢?咱们先来看概念,Dynamic Provisioning计划是指在用户声明存储才能的需要时,不是冀望经过Kubernetes撮合来获取一个办理员人工预置的PersistentVolume,而是由特定的资源调配器(Provisioner)自动地在存储资源池或者云存储零碎中调配合乎用户存储需求的PersistentVolume,而后挂载到Pod中使用,实现这项任务的资源被命名为StorageClass,它的详细任务进程如下:
办理员按照储零碎的实际状况,先筹备好对应的Provisioner。Kubernetes民间曾经提供了一系列预置的In-Tree Provisioner,搁置在kubernetes.io的API组之下。其中部份Provisioner曾经有了民间的CSI驱动,如vSphere的Kubernetes自带驱动为kubernetes.io/vsphere-volume,VMware的民间驱动为csi.vsphere.vmware.com。办理员再也不是手工去调配PersistentVolume,而是按照存储去配置StorageClass。Pod是能够静态扩缩的,而存储则是相对于固定的,哪怕使用的是拥有扩展才能的云存储,也会将它们视为存储容量、IOPS等参数可变的固定存储来对待,好比你能够未来自不同云存储提供商、不异性能、反对不同拜候模式的存储配置为各品种型的StorageClass,这也是它名字中“Class”(类型)的由来,如上面这个例子:apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: standard provisioner: kubernetes.io/aws-ebs #AWS EBS的Provisioner parameters: type: gp2 reclaimPolicy: Retain
用户仍然经过PersistentVolumeClaim来声明所需的存储,然而应在声明中明白指出该由哪一个StorageClass来替代Kubernetes处置该PersistentVolumeClaim的申请,如上面这个例子:apiVersion: v1 kind: PersistentVolumeClaim metadata: name: standard-claim spec: accessModes: - ReadWriteOnce storageClassName: standard #明白指出该由哪一个StorageClass来处置该PersistentVolumeClaim的申请 resource: requests: storage: 5Gi
假如PersistentVolumeClaim中要求的StorageClass及它用到的Provisioner均是可用的话,那这个StorageClass就会接管掉本来由Kubernetes撮合的PersistentVolume和PersistentVolumeClaim的操作,根据PersistentVolumeClaim中声明的存储需要,自动发生出知足该需要的PersistentVolume形容信息,并发送给Provisioner处置。Provisioner接纳到StorageClass发来的创立PersistentVolume申请后,会操作其面前存储零碎去调配空间,假如调配胜利,就生成并前往合乎要求的PersistentVolume给Pod使用。后面这几步都顺利实现的话,就象征着Pod的存储需要失掉了知足,会持续Pod的创立进程,全部进程如下图所示。
1szwnr4kw0v.jpg
(图片来自《Kubernetes in Action》)
好了,经过刚刚的讲述,置信你能够看出Dynamic Provisioning与Static Provisioning并非各有用处的互补设计,而是对同一个问题前后泛起的两种解决计划。你彻底能够只用Dynamic Provisioning来完成一切的Static Provisioning可以完成的存储需要,包罗那些不需求静态调配的场景,乃至以前例子里使用HostPath在当地动态调配存储,均可以指定no-provisioner作为Provisioner的StorageClass,以Local Persistent Volume来替代,好比上面这个例子:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer
所以说,相较于Static Provisioning,使用Dynamic Provisioning来调配存储无疑是更公道的设计,不只省去了办理员的人工操作的两头层,也再也不需求将PersistentVolume这样的概念袒露给终究用户,由于Dynamic Provisioning里的PersistentVolume只是处置进程的两头产物,用户再也不需求接触和了解它,只需求知道由PersistentVolumeClaim去形容存储需要,由StorageClass去知足存储需要便可。只形容用意而不关怀两头详细的处置进程是声明式编程的精华,也是流程自动化的须要根底。
除此以外,由Dynamic Provisioning来调配存储还能获取更高的可办理性。如后面提到的回收战略,当但愿PersistentVolume跟随Pod一起被烧毁时,之前常常会配置回收战略为Recycle往返收空间,即让零碎自动履行rm -rf /volume/*命令。
然而这类形式往往过于粗暴,要是遇到更精密的办理需要,如“删除到回收站”或者“敏感信息粉碎式完全删除”这样的功用,完成起来就很费事。而Dynamic Provisioning中因为有Provisioner的存在,如何创立、如何回收都是由Provisioner的代码所办理的,这就带来了更高的灵敏性。所以,当初Kubernetes民间曾经明白倡议废弃掉Recycle战略,假如有这种需要就改由Dynamic Provisioning去完成了。
此外,相较于Dynamic Provisioning,Static Provisioning的次要使用场景就局限于办理员可以手工办理存储的小型集群,它合乎得多小型零碎,尤为是公有化部署零碎的现状,但其实不合乎现今运维自动化所倡导的思绪。Static Provisioning的存在,某种意义上也能够视为是对历史的一种兼容,在可见的未来,Kubernetes确定仍是会把Static Provisioning作为用户调配存储的一种次要计划,来供用户选用。
小结
容器是镜像的运转时实例,为了包管镜像可以反复地发生出具备统一性的运转时实例,必需要求镜像自身是耐久而不乱的,这就抉择了在容器中产生的所有数据变化操作,都不克不及真正写入到镜像傍边,不然必定会破坏镜像不乱不变的性质。
为此,容器中的数据修正操作,大可能是基于写入时复制(Copy-on-Write)战略来完成的,容器会利用叠加式文件零碎(OverlayFS)的特性,在用户用意对镜像进行修正时,自动将变卦的内容写入到独立区域,再与原无数据叠加到一同,使其外观上看起来像是“掩盖”了原有内容。
这类改变通常都是暂时的,一旦容器终止运转,这些存储于独立区域中的变化信息也将被一并移除,不复存在。所以可见,假如不去进行额定的处置,容器默许是不具备耐久化存储才能的。
而另外一方面,容器作为信息零碎的运转载体,必然会发生出有价值的、应该被耐久保留的信息,好比表演数据库角色的容器,大略没有甚么零碎可以承受数据库像缓存办事同样,重启之后会丧失整个数据;多个容器之间也常常需求经过同享存储来完成某些交互操作,好比我在第48讲中已经举过的例子,Nginx容器发生日志、Filebeat容器采集日志,二者就需求同享同一块日志存储区域能力协同任务。
而正由于镜像的不乱性与出产数据耐久性存在矛盾,所以咱们才需求去重点理解这个问题:如何完成容器的耐久化存储。
一篇一思
不知你是不是察觉,这一篇埋藏了一条暗线的逻辑,以Kubernetes的存储为样例,探讨当新的更好的解决计划出来之后,零碎对既有旧计划和旧功用的兼容。这是得多场景中都会遇到的问题,零碎设计必需斟酌理想状况,必需有所让步,很难单纯去寻求实践上的最优解。越大范围的运用,通常都带着更大的理想牵绊。假如你也有这样的阅历,无妨留言与我分享一下。 |
|