Kubernetes 是一个“数据库”吗?

Stella981
• 阅读 677

Kubernetes 是一个“数据库”吗?

作者 | 张磊,阿里云高级技术专家、CNCF 官方大使,CNCF 应用交付领域 co-chair,Kubernetes 项目资深维护者

最近,Kubernetes 社区里有一个关于“Kubernetes is the new database”的论述,引起了很多人的关注。当然,这个论述更确切的含义,指的是 Kubernetes 项目本身的工作原理类似于数据库,而不是说你应该把 Kubernetes 当数据库用。

Kubernetes 是一个“数据库”吗?

粗看起来,这个 “Kubernetes 是一个数据库” 的论述还是比较匪夷所思的。毕竟我们平常所说的 Kubernetes 的工作原理,比如控制器模式、声明式 API 等等,好像跟“数据库”这个东西并没有什么直接关系。但实际上,这个论述背后却有着其非常本质的含义。这里的缘由,得从 Kubernetes 项目里一个最基础的理论谈起。

Kubernetes 声明式应用管理理论基础

在我们讨论 Kubernetes 的时候,往往会提到这样一个概念,叫做“声明式应用管理”。实际上,这也是 Kubernetes 项目跟其他所有基础设施项目都不一样的一个设计,是 Kubernetes 所独有的一个能力,那么,你有没有思考过,声明式应用管理在 Kubernetes 中具体的表现到底是什么呢?

1. 声明式应用管理不仅仅是“声明式风格的 API”

如果我们回顾一下 Kubernetes 的核心工作原理,我们其实就不难发现这样一个事实:Kubernetes 里面的绝大多数功能,无论是 kubelet 执行容器、kube-proxy 执行 iptables 规则,还是 kube-scheduler 进行 Pod 调度,以及 Deployment 管理 ReplicaSet 的过程等等,其实从总体设计上都是在遵循着我们经常强调过的“控制器”模式来进行的。即:用户通过 YAML 文件等方式来表达他所想要的期望状态也就是终态(无论是网络、还是存储),然后 Kubernetes 的各种组件就会让整个集群的状态跟用户声明的终态逼近,最终达成两者的完全一致。这个实际状态逐渐向期望状态逼近的过程,就叫做 reconcile(调谐)。而同样的原理,也正是 Operator 和自定义 Controller 的核心工作方式。

这种通过声明式描述文件,以驱动控制器执行 reconcile 逼近两个状态的工作形态,正是声明式应用管理最直观的体现。需要注意的是,这个过程其实包括了两层含义:

  • 声明式描述的期望状态。这个描述必须是严格意义上使用者想要的最终状态,如果你在这个描述里面填写的是某个中间状态,或者你希望动态的调整这个期望状态,都会破坏这个声明式语义的准确执行;
  • 基于 reconcile 的状态逼近过程。Reconcile 过程的存在,确保了系统状态与终态保持一致的理论正确性。 确切地说,Reconcile 过程不停的执行“检查 -> Diff -> 执行”的循环,才使得系统能够始终对系统本身状态与终态直接的差异并能够采取必要的行动。而相比之下,仅仅拥有声明式的描述是不充分的。这个道理很容易理解,你第一次提交这个描述时系统达成了你想要的期望状态,并不能代表、也不能保证一个小时后的情况也是如此。很多人会搞混“声明式应用管理”和“声明式风格的 API” ,其实就是对 Reconcile 必要性没有正确的认识。

你也许会比较好奇,采用这种声明式应用管理体系,对于 Kubernetes 来说有什么好处呢?

2. 声明式应用管理的本质:Infrastructure as Data

实际上,声明式应用管理体系背后的理论基础,是一种叫做 Infrastructure as Data (IaD)的思想。这种思想认为,基础设施的管理不应该耦合于某种编程语言或者配置方式,而应该是纯粹的、格式化的、系统可读的数据,并且这些数据能够完整的表征使用者所期望的系统状态。

注:Infrastructure as Data  有时也被称作 Configuration as Data,背后的意思是一样的。

而这样做的好处就在于,任何时候我想对基础设施做操作,最终都等价于对这些数据的“增、删、改、查”。而更重要的是,我对这些数据进行“增、删、改、查”的方式,与这个基础设施本身是没有任何关系的。所以说,我跟一个基础设施交互的过程,不会被绑定在某种编程语言、某种远程调用协议、或者某种 SDK 上。只要我能够生成对应格式的“数据”,我就能够“天马行空”地使用任何我喜欢的方式来完成对基础设施的操作。

这种好处具体体现在 Kubernetes 上,就是如果我想在 Kubernetes 上做任何操作,我只需要提交一个 YAML 文件,然后对这个 YAML 文件进行增删改查即可。而不是必须使用 Kubernetes 项目的 Restful API 或者 SDK 。这个 YAML 文件里的内容,其实就是 Kubernetes 这个 IaD 系统对应的 Data(数据)。

所以说,Kubernetes 从诞生起就把它的所有功能都定义成了所谓的“API 对象”,其实就是定义成了一份一份的 Data。这样,Kubernetes 使用者就可以通过对这些 Data 进行增删改查来达成自己想要的目标,而不是被绑定在某种具体的语言或者 SDK 上。更重要的是,相比于专有的、命令式的 API 或者 SDK,以 YAML 为载体的声明式数据能够更简单的完成对底层实现的屏蔽,从而更容易对接和集成现有的基础设施能力,这其实也是 Kubernetes 生态能够以惊人的速度蓬勃发展到今天的一个秘密武器:IaD 思想带来的声明式 API 与控制器模式,让整个社区更愿意为 Kubernetes 编写插件和对接各种能力,并且这些插件和能力的通用性和可移植性也非常高,这是其它项目比如 Mesos 和 OpenStack 所望尘莫及的。可以说,IaD 正是 Kubernetes 能够达成 “The Platform for Platform” 这个目标的核心战斗力所在。

说到这里,大家估计也就明白了:这种 IaD 设计中的 Data 具体表现出来,其实就是声明式的 Kubernetes API 对象;而 Kubernetes 中的控制循环,则是确保系统本身能够始终跟这些 Data 所描述的状态永远保持一致。从这一点上来说,Kubernetes 本质上其实是一个以数据(Data)来表达系统的设定值、通过控制器(Controller)的动作来让系统维持在设定值的调谐系统。

等一下,这个“让系统维持在设定值”的理论,听起来好像有点耳熟?

实际上,Kubernetes 背后的这门基础课,可能绝大多数工科背景的读者都是学过的,它叫做《控制理论》。

Kubernetes 是一个“数据库”吗?

是不是感觉豁然开朗了呢?

在明白了 Kubernetes 的这个本质之后,我们回过头来再看原本一些比较难以理解的设定,可能会更容易体会到一些本质的东西。

比如,今天我们在使用 Kubernetes 的时候之所以要写那么多 YAML 文件,其实是因为我们需要通过一种方式把 Data 提交给 Kubernetes 这个控制系统。而在这个过程中,YAML 只是一种为了让人类能够格式化的编写 Data 的一个载体。如果做一个类比,那么 YAML 就像我们小时候作业本里的“田字格”,而“田字格”里写的那些文字,才是 Kubernetes 真正关心的 Data 和整个系统运转的核心。

细心的读者此时应该已经想到了,既然 Kubernetes 需要处理这些 Data,那么 Data 本身不是也应该有一个固定的“格式”这样 Kubernetes 才能解析它们呢?没错,这里的格式在 Kubernetes 中就叫做 API 对象的 Schema。如果你经常编写自定义 Controller 的话,可能就会对这个 Schema 的体感比较深刻:CRD 就是一个专门用来定义 Schema 的一个特殊的 API 对象。

YAML 工程师?不,你是数据库工程师!

上述 Kubernetes 的 IaD 的本质,决定了它的工作原理其实更类似一个“数据库”,而不像传统意义上的分布式系统。这个差异,也是导致 Kubernetes 学习成本比较陡峭的一个根本性原因。

而从这个角度来讲,Kubernetes 为你暴露出来的各种 API 对象,实际上就是一张张预先定义好 Schema 的表(Table)。而我们绞尽脑汁编写出的那些 YAML 文件,其实就是对这些表中的数据(Data)进行的增删改查(CURD)。而 YAML 这个工具本身,则好比 SQL 一样是一个帮助你对数据库中的数据进行操作的工具和载体。而唯一跟传统数据库不太一样的是,Kubernetes 在拿到这些数据之后,并不以把这些数据持久化起来为目的,而是希望通过这些数据来驱动 Controller 执行某些操作,从而将整个系统的状态逐步调整为跟数据中声明的终态一致,这就回到我们前面所说的“控制理论”部分了。

也正是由于  Kubernetes 这样整套体系都围绕着“数据”这个一等公民运转的设定,才使得“编写和操作 YAML文件”成为了 Kubernetes 工程师的几乎唯一的日常工作。不过,在理解了本文今天介绍的 IaD 的思想之后,你其实大可以把自己比作一个“数据库工程师”了,而且这个 TItle 确实要比“YAML 工程师”更加贴切一些。

Kubernetes 项目的“视图层”

正如前文所述,如果你从一个“数据库”的角度重新审视 Kubernetes 设计的话,就不难发现 Kubernetes 的很多设计背后其实有着非常精妙的思想。比如:

  • 数据模型 -  Kubernetes 的各种 API 对象与 CRD 机制
  • 数据拦截校验和修改机制 - Kubernetes Admission Hook
  • 数据驱动机制 - Kubernetes Controller/Operator
  • 数据监听变更与索引机制 - Kubernetes 的 Informer 机制
  • ……

另外一方面,随着 Kubernetes 基础设施越来越复杂,第三方插件与能力越来越多,社区的维护者们也发现 Kubernetes 这个“数据库”内置的“数据表”无论从规模还是复杂度上,都正在迎来爆炸式的增长。所以  Kubernetes 社区很早就在讨论如何给 Kubernetes  设计出一个“数据视图(View)”出来,即:

Kubernetes 是一个“数据库”吗?

而这样一个构建在 Kubernetes 内置 API 资源之上的“视图层”给 Kubernetes 使用者带来的好处,跟数据库中的“视图”是非常类似的,比如:

  1. 简化和更改数据格式和表示

Kubernetes 的视图层,需要能够给研发和运维暴露更简洁的、经过抽象后的应用层 API 对象,而不是原始的基础设施层 API 对象。而一个视图层对象具体如何定义,自由度应该完全在用户手中,不需要拘束在底层 Kubernetes 内置对象的 Schema 上。

  1. 简化复杂的数据操作(简化 SQL )

经过抽象后产生的视图层对象,不仅在 UI 上需要更加简单,还需要可以定义和管理非常复杂的底层 Kubernetes 资源拓扑,从而降低用户管理 Kubernetes 应用的复杂度和心智负担。

  1. 保护底层数据表

研发和运维直接操作的是视图层对象,所以底层的 Kubernetes 原始对象是被保护起来的。这使得这些 Kubernetes 的原始对象可以在用户无感的情况下进行任意变更和升级。

  1. 复用数据操作(复用 SQL)

由于视图层对象与底层基础设施是完全解耦的,所以一个通过视图层声明的应用或者运维能力可以在任意 Kubernetes 集群漂移,而不必担心这些集群支持的能力是不是有差异。

  1. 视图依然是表,支持标准的表操作

Kubernetes 的视图层对象必须依然是标准的 Kubernetes 对象,这样 Kubernetes 对 API 对象的所有操作和原语对,才会对视图层对象适用。我们不能在 Kubernetes API 模型上引入额外的心智负担。

给 Kubernetes 设置视图层的想法虽然最终没有在 Kubernetes 上游落地,但是却成为了社区中大多数大规模玩家的主流做法。比如 Pinterest 就在 Kubernetes 之上设计了一个 PInterestService 的 CRD 来描述和定义 Pinterest 的应用,这个 CRD 其实就是一个视图层对象。但这个做法对于绝大多数企业来说,还是太过简陋了。要知道,数据的“视图”并不只是数据的简单抽象和翻译,在真正的生产环境中要大规模使用视图层,至少需要解决几个关键问题:

  • 如何定义和管理视图层对象与底层 K8s 对象之间的映射关系?注意这里绝不是简单的一对一映射,一个视图层对象可能会对应多个 K8s 对象。
  • 如何对“运维能力”进行建模和抽象?一个真正的应用,绝不只是简单的 Deployment 或者 Operator,它一定是待运行程序与相应的运维能力的有机组合(比如一个容器化应用和它的水平扩展策略)。这些运维能力如何通过在应用定义里体现出来?全定义成 annotation 可行吗?
  • 如何管理运维能力同待运行程序之间的绑定关系?如何将这个绑定关系映射成底层 K8s 当中真正的执行关系?
  • 如何通过视图层对象标准化的定义云资源,比如一个阿里云的 RDS 实例?
  • ……

上述这些问题,正是 Kubernetes 上游最终没能将“视图层”落地的重要原因之一,同时也是诸如  Open Application Model (OAM)这样的 Kubernetes 应用层开源项目主要的关注点。需要指出的是,仅靠一个 OAM 这样一个“规范”是依然不足以解决上述所有问题的,Kubernetes 视图层的建立,必须借助标准的视图层依赖库在实现层予以保证,才能真正在 Kubernetes 中享受到“数据视图”带来的优势和便捷。目前社区中比较强大的 Kubernetes 视图层依赖库,是来自 Crossplane 团队的 oam-kubernetes-runtimehttps://github.com/crossplane/oam-kubernetes-runtime

总结

Kubernetes 这个以 IaD 为核心的、类似“数据库”设计,正是这个社区繁荣发展背后的重要理论基础。然而,IaD 的思想本身也是一把双刃剑,它催生出来的蓬勃发展的社区的另一面,是无数个“各自为政”的 Controller/Operator,以及一个通过这些 Controller 拼装出来的、复杂度极高的 Kubernetes 集群。这样的一个生产级别复杂度的 Kubernetes 集群,距离一个真正受研发和运维喜爱的云原生应用管理平台,差距可谓十万八千里。

在过去的 5 年里,Kubernetes 项目的巨大成功,实际上是基础设施能力(比如网络、存储、容器)在声明式 API 下逐步标准化和统一化的一个过程,而随着 OAM 等 Kubernetes 应用层技术的逐步普及,我们已经看见一个标准化应用层生态正在付出水面。越来越多的团队正在尝试通过更加用户友好的数据视图层,对最终用户暴露出喜闻乐见的 API,同时对基础设施工程师提供出更加强大的横向连通与模块化的平台能力。

与此同时,Kubernetes 这个“数据库”其他欠缺的部分,也一定会越来越多的在社区涌现出来。比如今天正在迅速成熟的 Open Policy Agent(OPA)项目,可以认为是“数据拦截校验和修改机制”这一层的不断进化结果。再比如阿里巴巴内部在“万节点”集群中推进的管控链路性能调优工作,其理论基础和实践,跟今天的数据库性能优化,更是有异曲同工之妙的。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
2019 年 CNCF 中国云原生调查报告
!头图.jpg(https://ucc.alicdn.com/pic/developerecology/6db0c465111b4d9a96eb1ffe85c00e7a.jpg)中国72%的受访者生产中使用Kubernetes在CNCF,为更好地了解开源和云原生技术的使用,我们定期调查社区。这是第三次中国云原生调查,以中文进行
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
CNCF 官方大使张磊:Kubernetes 是一个“数据库”吗?
!头图.png(https://ucc.alicdn.com/pic/developerecology/3724056b4e44447d99b124508091487a.png)作者| 张磊,阿里云高级技术专家、CNCF官方大使,CNCF应用交付领域cochair,Kubernetes项目资深维护者最近,Kubernetes社区里
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这