谢于宁
Coding 基础架构工程师
多年互联网摸爬滚打经验,早年从事信息安全,后转为全栈开发,关注系统运维技术领域,热衷于容器化技术。在 Coding 参与了 Coding-Job 平台研发,推动从研发到生产的流程自动化。
Coding 的架构演进
罗马不是一天建成的,Coding 复杂的网站系统也是如此。
结构复杂的单体系统 > 微服务 > Docker 化 > 自动化如上是 Coding 的架构演进流程。Coding 起初也是一个结构复杂的单体系统,后来才采用了各种策略去改进它。那么我们该如何去评判一个系统的复杂程度呢?在 Coding 内部主要有两个指标。
一个是运维人员需要花多长时间才能把新的代码部署上线。例如在上线一个新服务时,运维人员可能原本说是半个小时就可以更新上线了,我们最后却会发现,四五个小时过去了还没有上线,而出现这种情况的原因很多时候是因为我们线上和线下状态的不统一。
还有一个指标是,一个新同事来到公司以后,要多长时间可以把整个系统的开发环境部署起来。以一个后端程序员为例,他需要装虚拟机、Nginx 服务器、数据库、具体语言的编译环境以及运行 npm install 来安装一些前端的代码库。这些操作,加上国内有奇葩的网络问题,可能通常会耗费半个到一个工作日之久。
而用了 Coding-Job 来部署本地开发环境,这个时间可以降低到半个小时。一个复杂的单体系统会拉长启动时间,增加代码理解难度,测试也会变得更加困难。
虚拟机与 Docker
Coding 网站一开始是一个简单的 Java War 包,编译、打包、上传,再到上线,还算是一个比较简单的操作。但是随着业务的快速发展,比如说有邮件、短信推送,如何把这些东西融合在一起,是一件比较棘手的事情。前两年微服务比较火的时候, Coding 也采用了微服务的架构,允许开发者用他们最拿手的框架和语言,选一个微服务来做,比如说短信,短信模块、接口文档写好之后,发给 Coding 写后台的同事,然后一会儿功夫就完成了。
这种方式使得 Coding 的代码能够跟得上 Coding 迅猛的业务发展,但是我们突然发现,全公司几乎已经没有人记得每个微服务是如何编译、配置和启动的了。于是我们希望有一种跟黑盒子一样的东西,可以让我们把一堆代码放到里面去,而不用管黑盒子是怎么配置运行的,把它放到线上去就能跑起来。代码在里面怎么配置是盒子的事情,外部环境无论如何脱胎换骨,都不影响盒子里面的正常运行。而这个黑盒子,其实就是虚拟化技术。在 2015 年初 Docker 刚火起来的时候,Coding 研究了当时的传统方案——虚拟机和 Docker 技术,最终采用了 Docker 。
查看图片▲ 图 1
图 1 是传统方案——虚拟机的架构图,在买了主机(Infrastructure)、装了宿主机操作系统(Host Operating System)以后,想要实现虚拟化技术,就要安装一套虚拟机管理软件(Hypervisor),比如 VMware vSphere 。它可以允许跑三个黑盒子,即虚拟机,在三个虚拟机里面分别跑三个操作系统(GuestOS),而在这三个操作系统之上,才运行我们真正想要运行的东西,即 App 1 、App 2 、App 3 这三个微服务。可是为什么我们要启动三个虚拟机?为什么要将大量的物理资源耗费在可有可无的上层操作系统上面呢?
于是,我们开始着手研究更加轻量级的虚拟化技术。与此同时,Linux 内核的命名空间(Name Space)和 控制组 Cgroups (Control Groups) 等技术应运而生,它实现了进程间命名空间的隔离、网络环境的隔离和进程资源控制。Docker 则正是依靠这些技术突然火热了起来。
大家都知道, Linux 只会有一个 PID 为 1 的进程 init 。有了命名空间以后,在每个进程命名空间里面,PID 列表是相互隔离的。在容器里面,也可以有一个 PID 为 1 的进程,这就实现了进程间命名空间的隔离。而控制组,它是可以做到对每个容器所占用的物理资源的控制,比如指定 CPU 的使用,块设备的读写速度。结合这两种技术,我们可以做到的是让 Docker 容器在保持一定性能的同时,尽可能地在隔离性上面接近虚拟机。
当我们在用 Docker 跑微服务的时候,图 1 中的虚拟机管理软件被替换成了一个 Docker Engine ,每个 App 跑在 Docker 容器中,容器与宿主机共享一个操作系统,如图 2 所示。这样能节省较多的物理资源,启动速度也由虚拟机的分钟级达到秒级,I/O 性能也接近直接运行与宿主机上。
▲ 图 2
于是 Coding 开始将微服务一个一个地迁移到 Docker 内,以容器的方式部署运行。然后你以为是这样一幅场景,如图 3 所示 。可事实却是这样的,如图 4 所示。
查看图片▲ 图 3
查看图片▲ 图 4
Apache Mesos 与 Kubernetes
Coding 大大小小的微服务有五十余个,就像鸡蛋不能放在一个篮子里一样,容器也不能被放在同一台云主机上面,而是整整齐齐地分开来放,不然怎么能叫分布式呢? Coding 的微服务,对于文件系统,对于彼此的网络还存在一些依赖性,像一个蜘蛛网一样串在一起,对于微服务所允许的主机位置和相应的主机配置也都是有要求的。
所以是需要一个中心化的东西去存放每个服务的配置以及它们运行的代码甚至 Docker 镜像。而这个中心化的东西所做的事情就是编排,就好像音乐会上的指挥家一样,它告诉这台云主机做什么任务,以什么配置运行这个任务,用什么代码来执行它,然后再告诉另外一台机器,又做什么任务等等。
为此 Coding 研究了两款业界比较火的两款开源容器管理框架,其中一款是 Apache Mesos 。它是一个用于集群的操作系统,会把一个集群所具有的所有物理资源抽象成一台计算机供用户使用,比如你的集群里有一百台服务器,每台服务器一个 CPU,那么 Apache Mesos 能给你一台具有一百个 CPU 的电脑。
查看图片▲ 图 5
Apache Mesos 做的比较好的一点是物理资源的分配。从图 5 中,我们可以看到 Apache Mesos 具有 Framework 的概念,它等同于我们通常所说的应用程序,每个 Framework 由调度器(Scheduler)和执行器(Executor)两部分组成。
调度器负责调度任务,执行器负责执行任务。图 5 的中间部分是 Mesos Master ,下方是几个 Mesos Slave 。 Master 是管事的,相当于包工头,而 Slave 是奴隶,负责干活儿的。这些 Slave 其实就是我们的云主机,每一个 Slave 就是一台主机。
从图 5 中我们还可以看到一个物理资源分配的流程,首先 Slave 1 发现它有 4GB 内存和 4CPU 的空闲物理资源,于是向 Mesos Master 汇报,询问它有没有任务可以做,然后 Mesos Master 会询问当前可用的 Framework 1 的调度器有没有可以分配给 Slave 1 的活儿,调度器按照空闲物理资源取出了两个任务回应给 Mesos Master,然后 Mesos Master 又转发给 Slave1,Slave1 又开始干活了。此时大家会发现 Slave 1 上面还有 1GB 内存和一个 CPU 是空闲的,那么它可以通过 Mesos Master 请求 Framework2 去请求任务来做。
所以 Apache Mesos 能带给我们的好处,一是高效,我们通过对主机的物理资源量化以及对任务的资源需求量化,使得多个任务能在同一台主机上运行,并充分利用其物理资源;二是可扩展性,Mesos 提供五十多种 Framework 帮助我们处理多种多样的任务。
另外一款则是一个叫做 Kubernetes 的 Docker 容器集群管理框架,它借鉴了谷歌的 Borg ,为容器化系统提供了资源调度、部署运行、服务发现等各种功能。它更加倾向于容器的编排,具有系统自愈功能。
查看图片▲ 图 6
图 6 是 Kubernetes 的架构图,左边是一个控制的节点,右边是一台台的 Slave。我们可以在左上角用 kuberctl 提交一个作业,让 Kubernetes 帮你把作业分配到一个 Slave 上。在 Kubernetes 里面,调度任务的单位是 Pod ,中文是豆荚的意思。就像豆荚一样,里面是有很多豆子的,那这些豆子是什么呢?这些豆子其实是我们的 Docker 容器,这些容器共享一个豆荚,在 Kubernetes 里面就是一个共享容器组的概念。所有在一个 Pod 里面的 Docker 容器都是共享命名空间的,这解决了一些特殊场景的需求。因为使用 Docker 的最佳实践是在每一个容器里面只做一件事,不把 Docker 容器当做虚拟机来用。而这意味着有些时候,比如 B 进程需要监测(watch) A 进程的进程号(PID)或者和 A 进程进行 IPC 通信,如果是一个容器一个命名空间,这显然是不能直接实现的,而这就是 Pod 的应用场景。
查看图片▲ 图 7
那么 Pod 该如何定义呢?图 7 所示的 Pod Definition 是通过 kubectl 向 Kubernetes 提交作业的配置文件。在 Pod 中会有多个 Container , 这里它定义了一个 Container 是 Nginx 以及 Nginx 的一些配置,例如镜像名和容器端口。
查看图片▲ 图 8
Kubernetes 是通过副本控制器(Replication Controller)来实现一个或者多个 Pod 的运行控制的。图 8 是我们向 Replication Controller 提交的配置文件,Template 字段代表了这个 Controller 使用的 Pod 的模板,而 Replicas 字段代表了我们希望 Kubernetes 用这个 Pod 模板产生多少个 Pod 同时运行,这涉及到 Kubernetes 里面一个叫理想状态(desired state)的概念。提交了这个配置文件以后,如果有任何一个 Pod 因为某种原因 Down 掉了,那么原先应该运行三个的副本只剩下两个,而 Kubernetes 会想办法达到理想状态,因此它会启动一个新的副本,最终变成三个副本,这个就是 Kubernetes 的自愈系统。
Coding-Job 容器化编排平台虽然 Apache Mesos 的资源管理和 Kubernetes 的自愈管理已经做得相当成熟了,但是想要把它们投入到生产环境当中,可能还是会遇到很多问题。例如当我们想用 Apache Mesos 时,首先会考虑到 Coding 通常所运行的服务是一些常驻服务,不是批处理任务,所以需要额外安装 Marathon 这样的长期运行任务管理框架(Framework)来做到这件事情。
若是在生产环境中遇到性能问题,调优也是一个棘手的事。而在 Kubernetes 中,我们并不想让自愈系统替我们把服务恢复在任何一台机器上,因为目前 Coding 还是有着一些对机器和运行位置有着苛刻要求的微服务。除此之外,这两款框架也在迅速的开发迭代中,文档也仍需补充,投入到生产中我们认为还为时过早。考虑到使用原生的 Docker API 就可以做到大部分我们想要用到的功能,于是我们开始开发自己的容器编排平台——Coding-Job 。
查看图片▲ 图 9
Coding-Job 的任务配置分成三层,Service、Job 和 Task,如图 9 所示,其中的 Service 是核心(core)服务,说明它是被众多服务所依赖的。每个 Job 定义了一件要做的事情,而每个 Job 要具体被分配去做的时候,会细分为 Task,每个 Task 可以使用不同的配置,运行在不同的机器上。
Coding-Job 是 C/S 架构的,在客户端,有命令行版的操作。例如,Push 是推送配置文件操作, UP / DOWN / UPDATE 分别是启动、停止、按照配置更新 Job , List 则是列出所有任务的现在运行状况。
此外 Coding-Job 的服务器端会展现一个 WebUI 界面,我们可以通过 WebUI 来获知每个容器的运行状态,通过 INSPECT 操作来提供容器的具体信息(与 Docker Inspect 一致),LOG 功能供查看容器 LOG ,History 是显示每个 JOB 的历史容器的配置。此外,Coding-Job 服务端会定时请求各 Slave 系统资源使用及 Docker 运行数据,这些数据也会在 WebUI 上显示出来。
查看图片▲ 图 10
图 10 是 Coding-Job 的使用架构图,Host-1、Host-2 是 Slave 机器。开发者在拉取最新的代码以后,用预先提供的打包命令生成一个 docker image 文件,通过 docker push 把镜像上传到私有 Docker Registry 中。同时开发者会根据最新的代码标签更新任务配置文件,通过 Coding-Job 客户端 PUSH 到 Coding-Job 服务端所使用的 etcd 中。
这个 etcd 起到了存储任务配置信息的作用,由于它是可监测变化的存储(watchable storage),在收到新的任务配置信息后,Coding-Job 服务端就可以各种方式通知到运维人员(Ops)。运维人员如果确认要更新线上代码,调用 Coding-Job 客户端的 UP 或者 UPDATE 命令,就可以让 Slave 机器开始下载新的代码镜像来运行,于是更新就完成了。
这样有什么好处呢?首先是一分钟发布新组件(服务)不再是梦,在此基础上,历史容器的功能加上每次更新后任务配置提交到 Git 仓库中,允许我们追溯每个组件的历史线上版本。其次,我们可以利用它在公司内网环境内五分钟启动一个跟线上几乎一致的 Staging 环境,这个 Staging 可被用于新功能的内测。
最后一个优点,是我们在使用 Coding-Job 的过程中,开发者不再对线上环境一头雾水,而是全透明的,可以知道生产环境是怎么组建的。在运维检查整站状态的时候,可以通过 WebUI 获得一些编排意见,甚至这个只读的 WebUI 可以开放到公网上,让所有人都可以看到 Coding 的服务提供状态。
「七牛架构师实践日」——这里只谈架构
七牛架构师实践日是由七牛云发起的线下技术沙龙活动,联合业内资深技术大牛以及各大巨头公司和创业品牌的优秀架构师,致力于为业内开发者、架构师和决策者提供最前沿、最有深度的技术交流平台,帮助大家知悉技术动态,学习经验成果。
回复关键字:0618 获取 「七牛架构师实践日」PPT和视频
查看图片扫码或者戳阅读原文,查看七牛直播云发布会详情