那么为什么 Kubernetes 不直接使用已经非常成熟稳定的容器?
为什么要再单独抽象出一个 Pod 对象?
为什么几乎所有人都说 Pod 是 Kubernetes 里最核心最基本的概念呢?
为什么要有 Pod?
Pod 这个词原意是“豌豆荚”,后来又延伸出“舱室”“太空舱”等含义,你可以看一下这张图片,形象地来说 Pod 就是包含了很多组件、成员的一种结构。
image.png容器技术我想你现在已经比较熟悉了,它让进程在一个“沙盒”环境里运行,具有良好的隔离性,对应用是一个非常好的封装。
不过,当容器技术进入到现实的生产环境中时,这种隔离性就带来了一些麻烦。因为很少有应用是完全独立运行的,经常需要几个进程互相协作才能完成任务,比如我们搭建 WordPress 网站的时候,就需要 Nginx、WordPress、MariaDB 三个容器一起工作。
WordPress 例子里的这三个应用之间的关系还是比较松散的,它们可以分别调度,运行在不同的机器上也能够以 IP 地址通信。
但还有一些特殊情况,多个应用结合得非常紧密以至于无法把它们拆开。比如,有的应用运行前需要其他应用帮它初始化一些配置,还有就是日志代理,它必须读取另一个应用存储在本地磁盘的文件再转发出去。这些应用如果被强制分离成两个容器,切断联系,就无法正常工作了。
那么把这些应用都放在一个容器里运行可不可以呢?
当然可以,但这并不是一种好的做法。因为容器的理念是对应用的独立封装,它里面就应该是一个进程、一个应用,如果里面有多个应用,不仅违背了容器的初衷,也会让容器更难以管理。
为了解决这样多应用联合运行的问题,同时还要不破坏容器的隔离,就需要在容器外面再建立一个“收纳舱”,让多个容器既保持相对独立,又能够小范围共享网络、存储等资源,而且永远是“绑在一起”的状态。
所以,Pod 的概念也就呼之欲出了,容器正是“豆荚”里那些小小的“豌豆”,你可以在 Pod 的 YAML 里看到,“spec.containers”字段其实是一个数组,里面允许定义多个容器。
如果再拿之前讲过的“小板房”来比喻的话,Pod 就是由客厅、卧室、厨房等预制房间拼装成的一个齐全的生活环境,不仅同样具备易于拆装易于搬迁的优点,而且要比单独的“一居室”功能强大得多,能够让进程“住”得更舒服。
为什么 Pod 是 Kubernetes 的核心对象?
因为 Pod 是对容器的“打包”,里面的容器是一个整体,总是能够一起调度、一起运行,绝不会出现分离的情况,而且 Pod 属于 Kubernetes,可以在不触碰下层容器的情况下任意定制修改。所以有了 Pod 这个抽象概念,Kubernetes 在集群级别上管理应用就会“得心应手”了。
Kubernetes 让 Pod 去编排处理容器,然后把 Pod 作为应用调度部署的最小单位,Pod 也因此成为了 Kubernetes 世界里的“原子”(当然这个“原子”内部是有结构的,不是铁板一块),基于 Pod 就可以构建出更多更复杂的业务形态了。
下面的这张图你也许在其他资料里见过,它从 Pod 开始,扩展出了 Kubernetes 里的一些重要 API 对象,比如配置信息 ConfigMap、离线作业 Job、多实例部署 Deployment 等等,它们都分别对应到现实中的各种实际运维需求。
image.png不过这张图虽然很经典,参考价值很高,但毕竟有些年头了,随着 Kubernetes 的发展,它已经不能够全面地描述 Kubernetes 的资源对象了。
受这张图的启发,我自己重新画了一份以 Pod 为中心的 Kubernetes 资源对象关系图,添加了一些新增的 Kubernetes 概念,今后我们就依据这张图来探索 Kubernetes 的各项功能。
从这两张图中你也应该能够看出来,所有的 Kubernetes 资源都直接或者间接地依附在 Pod 之上,所有的 Kubernetes 功能都必须通过 Pod 来实现,所以 Pod 理所当然地成为了 Kubernetes 的核心对象。
Pod 屏蔽了容器的一些底层细节,同时又具有足够的控制管理能力,比起容器的“细粒度”、虚拟机的“粗粒度”,Pod 可以说是“中粒度”,灵活又轻便,非常适合在云计算领域作为应用调度的基本单元,因而成为了 Kubernetes 世界里构建一切业务的“原子”。
虽然 Pod 是 Kubernetes 的核心概念,非常重要,但事实上在 Kubernetes 里通常并不会直接创建 Pod,因为它只是对容器做了简单的包装,比较脆弱,离复杂的业务需求还有些距离,需要 Job、CronJob、Deployment 等其他对象增添更多的功能才能投入生产使用。
image.pngKubernetes 的核心对象 Pod,用来编排一个或多个容器,让这些容器共享网络、存储等资源,总是共同调度,从而紧密协同工作。
因为 Pod 比容器更能够表示实际的应用,所以 Kubernetes 不会在容器层面来编排业务,而是把 Pod 作为在集群里调度运维的最小单位。
前面我们也看到了一张 Kubernetes 的资源对象关系图,以 Pod 为中心,延伸出了很多表示各种业务的其他资源对象。
那么你会不会有这样的疑问:Pod 的功能已经足够完善了,为什么还要定义这些额外的对象呢?为什么不直接在 Pod 里添加功能,来处理业务需求呢?
为什么不直接使用 Pod?
我们学习了 Kubernetes 的核心对象 Pod,用来编排一个或多个容器,让这些容器共享网络、存储等资源,总是共同调度,从而紧密协同工作。
因为 Pod 比容器更能够表示实际的应用,所以 Kubernetes 不会在容器层面来编排业务,而是把 Pod 作为在集群里调度运维的最小单位。
前面我们也看到了一张 Kubernetes 的资源对象关系图,以 Pod 为中心,延伸出了很多表示各种业务的其他资源对象。
那么你会不会有这样的疑问:Pod 的功能已经足够完善了,为什么还要定义这些额外的对象呢?为什么不直接在 Pod 里添加功能,来处理业务需求呢?
这个问题体现了 Google 对大规模计算集群管理的深度思考。
现在你应该知道,Kubernetes 使用的是 RESTful API,把集群中的各种业务都抽象为 HTTP 资源对象,那么在这个层次之上,我们就可以使用面向对象的方式来考虑问题。
如果你有一些编程方面的经验,就会知道面向对象编程(OOP),它把一切都视为高内聚的对象,强调对象之间互相通信来完成任务。
虽然面向对象的设计思想多用于软件开发,但它放到 Kubernetes 里却意外地合适。因为 Kubernetes 使用 YAML 来描述资源,把业务简化成了一个个的对象,内部有属性,外部有联系,也需要互相协作,只不过我们不需要编程,完全由 Kubernetes 自动处理(其实 Kubernetes 的 Go 语言内部实现就大量应用了面向对象)。
面向对象的设计有许多基本原则,其中有两条我认为比较恰当地描述了 Kubernetes 对象设计思路,一个是“单一职责”,另一个是“组合优于继承”。
“单一职责”的意思是对象应该只专注于做好一件事情,不要贪大求全,保持足够小的粒度才更方便复用和管理。
“组合优于继承”的意思是应该尽量让对象在运行时产生联系,保持松耦合,而不要用硬编码的方式固定对象的关系。
应用这两条原则,我们再来看 Kubernetes 的资源对象就会很清晰了。
因为 Pod 已经是一个相对完善的对象,专门负责管理容器,那么我们就不应该再“画蛇添足”地盲目为它扩充功能,而是要保持它的独立性,容器之外的功能就需要定义其他的对象,把 Pod 作为它的一个成员“组合”进去。
这样每种 Kubernetes 对象就可以只关注自己的业务领域,只做自己最擅长的事情,其他的工作交给其他对象来处理,既不“缺位”也不“越位”,既有分工又有协作,从而以最小成本实现最大收益。
网友评论