编者按:《微博混合云架构》专栏是 InfoQ 向新浪微博技术团队的系列约稿,本专栏包含 8 篇内容,详细阐述以 DCP 设计理念为指导思想的混合云架构实践。本文是该系列的第二篇,主要讲解了在新浪微博业务背景下 DCP 的不可变基础设施服务。
《微博混合云架构》专栏主要包括以下 8 篇内容:
- 混合云架构挑战与概述
- DCP 的不可变基础设施
- DCP 的弹性调度揭秘
- DCP 的镜像分发实战
- DCP 的容器编排设计与实践
- DCP 的服务发现
- DCP 的容量决策评估
- DCP 的监控体系
概述
不可变,顾名思义就是一旦创建,便不再修改。这听起来和我们常见的诉求——灵活的部署环境,似乎背道而驰。对于 DCP 中的基础设施而言,这并不矛盾,因为创建后就没有必要去修改了。整个基础环境作为一种版本化管理的资源,和代码类似。运行时如果有一定要变更的部分,那么直接更新源码,重新创建资源即可。老版的环境依然存在,可以在需要时用于回滚。
为了做到“不可变”,有两个必要条件:
- 能够快速获取所需的资源;
- 业务应用和基础资源之间相互独立。
第一点很容易理解,如果重建创建的过程太慢,比如几个小时甚至数天,那将无法满足线上业务的需求,反而极大提高了运维成本;第二点在容器化技术出现之前,是相当难做到的。业务应用大量依赖本地环境的配置、文件以及缓存等,耦合过于严重导致不同的上层业务需要不同的运行环境,迫使我们对基础设施进行复杂的异构。利用 Docker 技术,可以将业务应用运行时的绝大部分依赖都打包到容器中。这样一来,需要维护的基础环境数量大大减少,便于统一管理,也能够支持更多的业务方来接入。
本文将主要介绍新浪微博混合云架构上的不可变基础设施服务。
微博私有云的传统基础设施
正如概述中所说,私有云的设备申请和环境部署流程过于繁杂,如下图所示:
整个周期可能需要几周到数月之久,一旦有设备损坏,又需要进入另一个同样冗长的报修流程中。而短时间补充计算资源的方式只有从非核心业务中下线服务器挪过来顶上,费时也费力。但是私有云的一些优势是毋庸置疑的:安全性高、可控度高,相比以虚拟机为基础的公有云性能和稳定性更好。
基础设施方面,传统私有云面临这样几个困难:
- 不同业务部门的环境需求差异非常大,甚至操作系统版本都不同,难以统一管理;
- 随着运行时间增加,即使最初两台主机环境相同,到后来也无法保证一致性,最坏的情况可能造成业务应用部署失败;
- 环境的回滚几乎不可能,只有重装操作系统。
在向混合云架构转变的过程中,我们主要处理的也就是这些问题。
混合云上的基础设施服务
微博混合云的资源分为两个部分:内网主机和阿里云 ECS,我们的目标是对上层业务提供统一、不可变的基础环境。但是如果彻底不可变,反而带来了不小的麻烦。还有人提出拒绝 SSH,目的也是如此。试想仅仅需要临时改变一个系统参数,就必须完整构建一次环境,并且重新部署,这是令人难以接受的。
因此我们决定将不可变的范围缩小,那些耗时相对较长,修改频率又很低的模块纳入不可变范围,这些模块的变更需要重新制作整个环境;而另一些模块放到实时的配置管理系统中,以便在需要的时候进行更新。这样既能保证构建速度,又不带来过高的变更成本的方案,同时解决上面的问题。
正视差异化
不同业务对环境的不同需求是客观存在的,理论上也不可能完全抹平差异,因此我们的服务必须支持各类用户定制自己的环境,自下而上包括三部分:主机环境、配置管理脚本和基础容器。
最下层是我们认为不可变的部分,而中间的配置是可能变更的模块,最上面是一些标准的容器,包括面向业务的 JAVA 和 PHP,也包括面向运维的 OPS。这样明确各层的职责,便于分别进行管理。
环境一致性
一致性包括两个方面:
- 资源在使用过程中,环境保持不变:内网主机随着时间推移,会不可避免地被修改,因此我们制作了一个运维使用的基础 Docker 镜像,即上面的 OPS 镜像,包括一些工具软件和业务脚本,并将
docker.sock
挂载进去。这样就可以在容器内部操作 Docker Daemon,而其他修改也仅仅只在容器内部,不会污染主机环境。公有云的使用场景原则上不会发生环境漂移的现象,毕竟每次新建的资源使用时间不会超过 12 小时,同时使用上述运维镜像,更加没有必要操作宿主机。 - 重新创建的和已经在运行的资源环境一致:即使配置未变更,也可能出现不一致的问题,尤其在使用外部软件仓库的情况下,比如脚本中
yum update
或者yum install docker
类似的命令。因此我们使用了内部搭建的软件仓库,可自己对软件的更新频率和范围进行控制,同时也要求脚本中所有安装软件的命令带上版本号,如yum install docker-1.6.2
。
基础资源版本化
基础设施即服务,服务即代码,自然可以进行版本化管理。
可以看到图中以 CentOS 7 发行版加基础配置为起点,类似 Git 中分支的概念,衍生出两个不同的基础环境 A 和 B,而从 A 又产生了新的分支 C。每种环境都有自己的版本,在必要的时候可以回滚。需要注意的一点是,各环境的第一个版本在制作时我们需要进行更全面的测试,因为它是后面环境变更的基础,万一出问题,并没有更老的版本可供回滚。
架构演进
初试:Docker Machine
去年微博刚启动混合云项目时,我们首先尝试的是 Docker Machine——一个官方出品的 Docker 环境构建工具。当时这个工具才刚推出不久,还不能直接创建阿里云 ECS,也无法对 CentOS 进行构建,于是我们自行开发了对这两者的支持。它是一个命令行工具,原生支持创建 Swarm 集群,使用起来构建环境只需要简单几步:
docker-machine create
- 配置自定义的系统环境
- 部署服务
对于个人使用者而言,Docker Machine 非常方便,但是对于混合云项目的需求,有几点它都难以满足:
- Docker 启动参数无法完全自定义,当时只能配置少数几个参数,如
--insecure-registry
。 - 命令行对应的几个函数都是不可导出的,因此无法通过 API 调用,只能进行二进制依赖。
- 官方宣布不支持 CentOS 6.x 及之前的版本,而微博内部还有一小部分 CentOS 6.5 的服务器。
- Docker 的安装使用的官方脚本,超时问题比较严重。
- 不够稳定,当时还处于开发阶段,版本迭代过于频繁。
其实在初步尝试过程中,前 4 点都通过修改源码解决了,但那就没办法再合入官方的代码,不是长久之计。因此放弃了 Docker Machine,使用了自己设计的另一套方案。
改进:VM Image & Ansible
前面提到,我们将所有的模块分为不可变和可变两个部分,其实就分别对应了这个方案中的虚拟机镜像和配置管理。利用阿里云 ECS 提供的功能,把耗时长、变更很少的模块直接打到虚机镜像中,而可能变化的模块使用 Ansible 进行管理,能够随时执行。两部分共同构成了一套版本化的环境。如果变更的部分需要被长期使用,通过 Ansible 即时下发后也能够同步到镜像,保证下次构建环境时直接生效。整体设计如下图所示:
我们在阿里云 API 的基础上,提供了一个快捷制作镜像的服务,它使用了 Ansible,用户只需要编写 yml 描述文件,即可生成相应的 ECS 镜像。类似于 Dockerfile,环境描述文件也支持FROM
语法,对应的值就是上层镜像的名字和版本号,再加上INCLUDE
和ROLE
,分别定义需要执行的 playbook 和 role,例如:
<ol><li><code>FROM weibo_plat_init:1.0</code></li><li><code></code></li><li><code>INCLUDE user.yml</code></li><li><code>INCLUDE config.yml</code></li><li><code>ROLE hongbao</code></li></ol>
在使用 ECS 镜像的过程中,有两点也是需要注意的:
- 使用镜像创建 ECS 后,ntpd 的配置会恢复为阿里云默认值,如果使用自定义的需要再次修改。
- 如果在构建镜像时挂载了数据盘,生成镜像前需要删除
/etc/fstab
中自动挂载的配置,否则该镜像将由于找不到第二块硬盘的分区而无法启动。
另外我们选用 Ansible 作为配置管理工具,主要因为它架构简单、依赖少,只要有 SSH 便可以工作;学习曲线平滑,上手比较容易;模块也足够丰富,能够满足需求。它被广泛诟病的是性能问题,我们对此进行了一些优化:
- 开启 SSH 参数,pipelining 和 ControlPersist;
- 优化 playbook,除去非必要模块,减少远程依赖;
- callback 模块异步化,Ansible 自身会等 callback 结束才执行后续命令,这点可以大大降低高并发时的耗时;
- 将需要网络传输的操作,如安装软件包、拉取 Docker 镜像等,内置到 ECS 镜像中。
最后,从阿里云 ECS 启动完成到初始化结束的用时被缩短到 1 分钟之内。
基础设施发布
准备工作完成之后,就是环境发布了。我们对于公有云的使用是用于弹性扩容,所以发布也主要是针对阿里云 ECS。每次发布可以选择一个 VM 镜像和一套 Ansible 脚本进行构建。整体流程为:
- 在 DCP 申请阿里云资源;
- 根据选择的 VM 镜像创建 ECS;
- 待 ECS 启动完成后下发 Ansible 命令进行初始化;
- 交付上层业务使用。
Ansible Scheduler
上述第三步的命令的批量发布使用了 Ansible Scheduler 来调度。但由于 Ansible 本身不提供 HTTP 接口,因此我们基于它的 Python API 进行了开发。
Scheduler 本身是无状态的,可任意水平扩容,主要负责分发初始化命令,可控制并发度、步长等参数。每个 ECS 镜像都对应 Ansible 的一个 role,在一台主机上执行的 role 我们称为 Task,其中又包含很多 Action。在每个 Action 开始和结束时,都会触发我们自定义的回调模块,异步将消息写入队列,最后存储到数据库中。DCP 的界面上即可显示所有主机环境初始化的情况,包括执行了哪些模块、耗时和成功与否。
部署公共组建
除了线上应用,DCP 中这整套基础设施构建的系统,也在为其他公共组件提供服务:
FROM weibo_plat_init:1.0 INCLUDE user.yml INCLUDE config.yml ROLE hongbao
在大规模扩容中,这些组件也是需要支持弹性伸缩的。以 DNS 为例,为避免解析请求跨机房,我们在阿里云上常规部署了两台 DNS 服务。同时由于所有扩容的 ECS 都是新建的,不存在 DNS 缓存,业务首次启动会有大量域名解析的请求,也需要保证 DNS 服务的高可用。这里我们使用了阿里云的内网 SLB 服务,作为 VIP 对 DNS 做负载均衡。两个 SLB 分别指向所有的 DNS 服务器,设置 UDP 转发,并且增加健康检查,便于摘除不可用节点。
基础监控
由于构建了统一的环境,整套基础监控也是标准化的,包括 CPU、内存、硬盘、网络、Docker 进程等等。其中对于专线带宽的监控是相当重要的一个部分,跨云的专线没法和自有机房的线路相比,不论是稳定性和带宽使用,都需要实时监控。
首先我们根据网络资源的分配在阿里云建立 VPC 时选择一个独立的网段,如 10.85.0.0/16,然后每台 ECS 创建后都会安装专线带宽监控的软件,只要过滤掉所有在上述网段内部传输的流量,就是穿越专线的流量,同时也定时监测自有机房到阿里云的网络延迟。最后将监控数据推送到中心存储节点,通过 grafana 进行展示:
专线监控精确到单机,因此也可以自行设置聚合逻辑,从而统计各业务使用的总体带宽。
总结
基础设施的快速构建为新浪微博混合云的弹性扩容提供了强有力的支持,不可变在很多时候是简单而高效的,但不是绝对的。实际应用中,我们也需要将基础环境中长期稳定和可能变更的模块分别处理,从而在构建速度和变更成本之间取得平衡。
感谢魏星对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论