共计 3929 个字符,预计需要花费 10 分钟才能阅读完成。
去年换工作后,开始真正在生产环境中接触容器与 Kubernetes。边恶补相关知识的同时,也想把学到的内容和自己的理解整理出来。学习的途径包括 k8s 官方文档、书籍、极客时间专栏及网上各种博文。所涉及一些摘抄或描述,大多用自己的理解来组织语言,也就不一一注明出处了。
Kubernetes(简称 K8S) 与容器技术,可以说是近几年最火热的技术之一。提起 K8S,大家都知道是 google 开源的容器编排工具。今天想先谈谈,我理解的容器、K8S 是什么,以及为什么它们能火起来。
Why Docker
既然说 K8S 是一个容器编排的工具,那么要搞清楚 K8S 是什么,首先得搞清楚,容器是什么,以及为什么要用容器技术。
形象的来说,一个 linux 容器,实际就是一个进程,还是个被系统欺骗的进程。为什么这么说呢?一个运行在容器里的进程,主要有以下特点:
它被宿主机操作系统隔离了,它看不到宿主机上的其他进程,以为自己就是 pid 为 1 的进程
它被宿主机操作系统限制了硬件资源,它能使用的 cpu、内存等硬件资源只是宿主机的一部分
在被宿主机操作系统限制了存储空间,让这个进程认为宿主机的某个目录就是系统根目录
这几个欺骗进程的技术,就是是容器技术的三板斧,用于资源隔离的 namespace,用于资源限制的 cgroup, 以及用于伪装进程根目录的 rootfs。这三种技术,都是是早已存在于 linux 中的,只是 docker 公司比较创新的把这三种技术整合在一起,并且,提出了容器镜像及镜像仓库等概念,把这个进程及相关的依赖环境都一起打包成可分发及重复使用的镜像文件,方便容器能在不同机器之间移植。这样,在任何地方,只要能运行 docker,就能把容器镜像跑成一个包含这应用进程及相关依赖环境的容器实例。
这里用利用 K8S 官方文档的图,简单说下生产中的场景,看看容器技术能解决什么问题。
左图是传统的物理机部署应用方式的方式,可以看到除了一个应用的运行,除了程序本身,离不开应用配置、库、等等依赖环境。通常情况下,一个应用的上线,要经历开发环境、pre 环境、beta 环境、灰度测试、生产环境等等不同的基础环境。开发的同学在开发环境跑通了代码,到其他环境运行时,由于各环境依赖、配置、安全需求不同,可能会出现各种问题。运维的同学忙着在不同的环境中统一依赖。不同应用各种语言,各种应用的特殊依赖需求,也造成了 CI/CD 逻辑复杂,难以统一。
右图是用了容器技术之后的场景。一个容器镜像的实质就是程序进程加所有运行时环境及配置、依赖的集合。只要各个环境的底层能兼容 docker,就能实现所有环境部署的一致性。开发同学不用关心生产环境和开发环境的差异可能会导致应用运行问题,运维同学部署一个应用,只要确保容器镜像能正常运行就好。CI/CD 的自动化也相对容易实现很多。从而极大增加开发效率、应用迭代效率及节省了运维工作量。
说到这里,不得不说下容器与传统意义的虚拟机间的对比。其实二者都可以理解为虚拟化,它们最本质的区别是,容器是操作系统层级的虚拟化,而虚拟机是硬件层级的虚拟化。参看下图。由于虚拟机多了一层 Guest OS,需要宿主机额外的性能开销进行硬件虚拟化,同时因为是完整的操作系统,虚拟机镜像一般动辄大几 G,很难在各环境间快速传播,hypervisor 层相对 Docker Engine 也比较重。再看 docker 容器,实质就是宿主机上跑的一个进程,只不过通过 docker 与其他进程隔离开来。简单的说,敏捷和高效,是容器相比虚拟机最大的优势,当然也有劣势,由于容器只是操作系统级别的隔离,不同容器间隔离的不够彻底。
Why Kubernetes
简单说完了 docker 的理解,那么 Kubernetes 又是什么,它解决了哪些问题呢,为啥现在提容器技术必提 k8s 呢。这里再谈谈我理解的 Why K8S。
回到实际的场景来,假如你已经开始用 docker 镜像来打包应用,可以方便的进行分发和部署,不用去考虑不同环境的差异。但是不是还感觉还少了点什么?
因为正常的实际业务系统,不是应用能部署,能运行起来就完事了,还要考虑应用容器的访问、水平伸缩、监控、安全、备份、容灾等等因素。而对于一个完整的业务系统来说,也不是单个应用就能搞定的,还要考虑的是各应用间的关系,及应用运行的形态。比如一个 web 业务,可能需要 web 服务器、缓存系统、数据库等多个应用。容器化部署后,它们可能部署在不同宿主机的不同容器中,相互间的访问要怎么实现,这就涉及到容器间访问关系的处理。再比如,有个优化缓存的应用也跑在容器里,只需要定期运行容器实例执行优化任务,执行完毕就终止容器,这就需要处理不同容器应用的运行形态问题。类似上述这些对容器应用及容器间关系进行管理,就是所谓的容器编排及调度。而 Kubernetes,就是目前的容器编排的平台的事实标准了。
那么,具体来说,K8S 到底能做哪些事呢。
在官方文档中,对 K8S 功能的描述如下
Kubernetes 满足了生产中运行应用程序的许多常见的需求,例如:Pod 提供了一种复合的应用容器模型, 挂载外部存储,Secret 管理, 应用健康检查, 副本应用实例, 横向自动扩缩容, 服务发现, 负载均衡, 滚动更新, 资源监测, 日志采集和存储, 支持自检和调试, 认证和鉴权.
从这些功能介绍可以看出,K8S 已很类似一个云平台了,可以完全能满足生产级别的容器应用管理需求。下面是一张最简单的 K8S 系统示意图:K8S 集群由一个主节点(master 节点)及多个工作节点(node 节点)构成,开发者提交应用容器镜像,并将镜像运行的数量、方法等通过描述文件提交给 K8S master 节点,K8S master 节点或根据集群整体情况,将应用按照需求部署在工作节点中。对于开发者来说,利用 K8S 可以方便的部署程序,不用关心基础设施,而对于运维人员来说,工作重心从维护具体应用,转变为维护 K8S 集群。而且,不管是开发者还是运维人员,都不用关心应用具体部署在哪个节点,K8S 会自动判断搞定一切。相比于传统的应用部署方式,有没有觉得 K8S 很棒棒?
在容器编排这个概念出现的时候,Kubernetes 并不是唯一的一个容器编排工具,主流的工具还有 Docker 公司原生的 swarm 和 Apache 基金会的 mesos,为什么 K8S 能笑到最后,成为容器编排的事实标准呢?我理解 K8S 对比它们有两个最大不同点:(这里不对 swarm 和 mesos 做详细介绍了,实际也确实没怎么玩过)
K8S 对容器又做了一层抽象,也就是 POD。不同于与其他两个工具,K8S 管理的原子对象,其实并不是容器,而是 POD。按照官方文档的定义,一个 POD,是由一个或多个共享存储及网络的容器,以及描述怎么运行这些容器的集合,所以,POD 实际是一个抽象的概念。k8s 对容器的所有操作,比如动态伸缩、监控等,实际上都是对 pod 的管理。那这层抽象的好处是什么呢?上面有提到过,容器实质就是被特殊处理的进程。想像一个 web 业务,web 应用进程输出的日志需要被大数据 agent 进程处理。这个业务如果想容器化,通常有两个做法。一是分别起来两个容器,挂载宿主机同一个目录来存放日志。另一种是起一个操作系统级别的容器或 supervisord 容器作为 enterpoint,来管理 web 服务和 agent 进程。前一种方式,这个两个容器就被框在这台宿主机上了,要实现业务实例横向扩缩容,要考虑两个容器的运行情况和存储挂载,逻辑比较复杂。后一种方式,你要为每个容器再额外开一个 supervisord 进程,更重要的是,由于 entrypoint 是 supervisord 进程,web 应用和大数据 agent 对 docker 来说,都是不可见的。即使 nginx 出错频繁重启,只要 supervisord 还活着,Docker 就认为这个容器是正常的。我们再来看看,使用了 pod 这个概念以后,有什么变化。一个 pod 里面同时起了 web 服务进程和大数据 agent 两个容器实例,首先,pod 里的容器实例是共享存储和网络 namespace 的,也就是说,这两进程的存储数据是直接共享的,不需要额外的挂载动作。其次,这个 pod 是作为一个整体被 k8s 管理着的,k8s 会监控 pod 里每个容器的状态,并根据策略在有问题时进行自动干预。从这个意义上说,pod 才更类似传统的虚拟机。
声明式 API 第二点也是比较重要的方面,是 K8S 的声明式 api(貌似 swarm 的新版也支持了,同样没玩过就不细说了)。什么是声明式 API 呢,可以参考上面系统图中的描述文件。比如要我需要集群中跑 10 个 web 服务容器,传统的命令式 API 是一步步调用命令构建出容器。而使用声明式 api,只要告诉 K8S 我要 10 个 web 容器,K8S 就会自动将 web 集群实例数维持在 10 个,并且,在某个 pod 出问题退出时,K8S 会自动重新拉起新 pod,使集群始终保持 10 个 pod 实例在跑。这就使得管理集群变得很简单,只要通过配置文件描述出希望的集群状态,而不用去关注中间的实现过程。
最后,总结一下:Why Dokcer:用容器技术跑应用,相比原来的物理机及虚拟机更高效、轻量、省资源,同时大大方便了不同环境下的应用部署及分发。Why Kubernetes:生产集群光跑容器还不够,还要对容器应用作为一个业务系统集群进行编排及管理,而 K8S 的一些优势使得它成为目前容器集群编排管理工具的事实标准。
最后的最后再多提一点,实际上,容器技术不止 Docker 公司一家在做,Kubernetes 也不是只能管理 Docker 容器。只是,无论从市场份额、应用性还是开发社区的热度来说,它们都是目前容器技术最主流的解决方案,就生产环境来说,目前基本没有必要去考虑其他的容器技术了。