亚马逊AWS官方博客
FreeWheel 云环境治理实践之运维体系设计
前言
随着各大云厂商竞争愈发激烈,云计算产业正在快速崛起。云计算正在影响整个信息产业,其可靠性、灵活性、按需计费的高性价比等优势已经让很多厂商把“上云”列入到了战略计划中。
相对传统运维,云计算为我们节省了很多硬件、网络、甚至一些基础服务的维护成本。与此同时也把运维模式从传统的静态化变成了动态化,如何管理多样化的动态资源、构建弹性化服务、实现异地切换与备份、管控内外部安全、优化成本等等挑战应运而生。
本文将分享 FreeWheel 基于亚马逊云科技云服务的运维生态体系设计思路:面对内部众多团队,如何在保持“底线”的同时,给用户提供灵活的可变空间、实现裸资源交付与管理。
不以规矩 不能成方圆
古人云,工欲善其事必先利其器。让我们先来定定规矩,制定内部标准“白皮书”。
命名标准与组织关系定义
传统运维中的 CMDB 是一个绕不开的话题。不过亚马逊云科技丰富的 API 已经帮我们封装好了各种接口,这些基础信息都可以通过 API 实时查询。我们要做的是把各个服务模块通过多种维度描述出来。
我们将服务树服务作为公司内部统一入口,用来描述和维护所有资源的组织关系,虽然服务本身很轻量化,但却是整个运维生态系统的基石。
服务树需要怎么设计?这个并没有标准答案,需要综合公司实际情况反复地推敲与验证才能定制出合理的方案。
虽然是开放性设计,但还是需要满足一些基本要求:
- 最小服务单元唯一性
注册在服务树里面的节点必须是唯一的,这个就像传统的硬件资源管理,大到一个机柜,小到一根内存,每个硬件都是唯一并且真实存在的。
- 灵活并尽可能小巧
这里需要考虑维度问题,服务树既是给自动化代码读的,也是给人看的。不同角色需要不同的维度,所以这里一定要按需制定好标准规范,以后公司内部的沟通与开发、部署、维护等都会围绕这个体系运转。
- 与业务关联
先顺应公司当前的产品线思路去设计。梳理清楚当前的业务结构,了解未来的发展计划和趋势,需要考虑的因素包括产品线定位、人员安排等等。
然后要考虑当前底层基础服务情况。比如我们的大部分业务都运行在亚马逊云科技上,需要利用云原生服务的特性来支撑设计需求。
最后要兼顾底层载体的基本特性,其初期交付、中后期的部署与配置管理,以及后期的下线等都需要通过服务树来管理。
在此抛砖引玉一下,我们的设计是以 Project(项目) 、 Application(应用) 、Service(服务,即最小服务单元)为主的三层结构(以下简称 P-A-S 模型),小巧且可以灵活覆盖业务。
根据这三层结构,我们定义出了不同的维度便于生态管理,即:
- P 节点:项目层,包括下面所有 P-A 及 P-A-S 资源
- P-A 节点:应用层,包括 P-A 下面的所有资源
- P-A-S 节点:单服务层,仅仅包括对应的单一服务单元
- P-*-S 节点:通配服务层,该项目下所有应用的特定服务单元,适用于内部多租户的越界管理
下图简单介绍了服务树的层级与云资源的对应关系:
同时面对多租户及中台性质的这些服务,我们的服务树也会基于应用层来显性地指明对应关系,如下图所示:
- 中台性质的服务,S 层所属统一项目,并跨 P 或 A 层节点提供业务支持。
- 多租户性质的服务,A 层可根据需求,映射到不同的 P 或者 A 节点,这可以灵活地实现费用分析以及人员的管理等。
基于服务树,我们把 亚马逊云科技 的资源均对号入座打上 P-A-S 的 TAG,看下服务树帮我们解决了哪些问题:
- 命名标准:
- 通过命名的标准化,很好地统一了内部沟通语言,包括工作和机器语言。
- P 和 A 层资源信息(命名、节点位置、人员信息等)固化在服务树里,剩下的 S 层相对灵活,通过流程确保服务树“源”的权威性。
- 对于云上的资源,把服务树节点信息与 TAG 绑定,对支持自定义化的 ARN 资源,也会基于服务树节点固化 ARN。
- 组织关系:
- 资源相关的信息,都可以通过不同节点位置或者用定义好的不同维度来查询。
- 费用分析:
- 将 P-A-S 设定为 Billing TAG,这样我们可以从 cost explorer 或者 billing raw data 里方便地统计出各个维度的费用明细。
- 针对中台或者多租户平台的费用追踪,我们提出了一个 budget entity 的概念,即通过 P-A-S 不同维度的组合,可以预定义出不同范畴的“预算组合集”。
- 通过费用明细和监控数据的关联分析,可以给容量评估和优化提供很好的参考数据。
- 访问控制:
- 针对于业务层面,基础的 IAM 和 Security Group 均基于服务树节点进行通配或精准授权。
- 针对于人员和工具层面,比如报警组、权限申请、pipeline 等都可基于服务树进行授权和隔离。
- 自动化运维:
- 服务树的设计理念为实现统一的、标准的自动化运维平台打下了坚实的基础, 例如上述的命名标准,访问控制都是自动化运维平台里不可或缺的部分。
云原生服务的标准定义
完成了组织结构的规范和标准,接下来就要标准化原生服务的使用与管理方案。
为什么要规范云原生服务的使用呢?
公有云服务往往需要兼顾多样化的用户场景,所以服务设计得非常灵活,内部多租户模式给管理带来了很多痛点:
- 不同团队使用相同服务、解决不同问题,或使用不同服务、解决相同问题,过多的差异化难以维护。
- 往往一个参数的差异,就会导致误把资源发布到公网或者内部权限越界,存在很多安全隐患。
- 公有服务迭代快,学习成本高。
我们本着“在同构中求异构,不在异构中求同构”的原则,尽可能最大化复用资源。像部署发布这种琐碎重复的事情交给底层基础服务去完成就好了,所以我们在支撑众多业务团队时候需要尽可能做到:
事做一遍、坑踩一次、快速迭代。
在云上,对于最底层裸资源我们大概划分成这几类:
除亚马逊云科技开箱即用的原生服务,其他服务均需要额外的工具来构建其生态,因篇幅有限,今天我们先不做深入讨论。
在亚马逊云科技各种白皮书和最佳实践文档的基础上,我们根据公司实际情况,针对大部分常用服务制定了公司内部的“最佳实践”,主要包括:
- 原生服务的应用场景的制定,固定需求的统一解决方案,原生服务选型等标准;
- 扩展性、安全性、可管理性、费用成本评估等标准;
- 权限、属性等配置约束;
- Tag、ARN 等命名约束;
当然,标准不意味着技术锁定,对于“老”技术需要不断更新迭代,对于“新”技术,在积极拥抱的同时更需要理智地评估,而不是一味赶“时髦”。
基础设施的标准定义
无标准不成自动化,到此,我们有了足够详细的标准化参考,接下来我们就要思考如何确保各种标准可以准确地应用到生产之中。
在底层基础实施技术栈的选型上,我们主要考量以下几个方面:
- 可管理云上资源
- 可支持多用户或团队协同工作
- 可扩展
- 可维护
亚马逊云科技作为一个很成熟的公有云,很多商业化或开源的厂商都在其之上提供了完整解决方案,相关的技术选型是个仁者见仁智者见智的问题,找到适合的就可以。
我们最终选择了 Terraform 的开源方案,在此简单介绍下 Terraform(以下简称 TF)的优势:
- Infrastructure as Code 模式;
- 执行计划提示,即应用新代码前可显示“dry run”结果,对幂等性管理比较友好;
- 一键执行,TF 会根据代码的修改自动编排对云服务 API 的调用;
- 较丰富的组件支持,除亚马逊云科技外还支持很多流行工具,同时产品迭代也跟的上亚马逊云科技的进度(亚马逊云科技的更新速度真的很快)。
TF 作为一个 Infrastructure as Code 的框架,虽然有诸多优势,但是如何将它用好仍然是我们需要去解决的问题,尤其是在多团队合作参与云环境治理的的情况下, 如何保证整套治理体系的可维护性、安全性、幂等性、唯一性等等。
鉴于此,我们打造了一个支持 TF 的自动化运维平台作为云环境治理的统一入口,通过平台介入来实现下图中左侧往右侧的转变, 并解决上述几个问题:
可维护性:保障代码风格和结构一致性,保证代码库始终处于可维护的健康状态
- 针对亚马逊云科技的各项原生服务,基于上文确定的“内部最佳实践”,我们将对应的实践固化成 TF 模块,并加入显性的版本控制,便于灵活管理模块,使其与应用代码解耦,实现私有化模块注册功能。
- 私有化模块库在公司内部以开源项目的模式管理,集大家的力量和经验来扩大和提升“最佳实践”的范围。
- 降低用户对 TF 的学习成本,通过可视化前端来生成和维护代码,用户只需在界面选择自己需要的私有化模块版本,根据引导输入简单的变量,运维平台会负责自动生成 TF 代码,并进入 pull request(以下简称 PR)阶段,从而保证代码风格和结构的一致性。
安全性:保障修改后的代码平稳应用到线上
- 准确性,利用自动化运维平台结合 TF 的 Dry run 功能保证用户提交代码的准确性,包括语法和预定义的语义检查,以及提交资源修改前的二次确认。
- 运维平台支持暂存当前工作目录状态,便于执行 TF dry run 和不合法修改再编辑等功能。
- 运维平台根据我们的最佳实践定义了一些语义检查规则,补足了 TF dry run 无法实现的一些检查点。比如,IAM policy 的内容会结合预定的黑名单,初筛一些权限越界的修改。
- TF dry run 结果会提示用户此次资源变更的具体信息和细节, 用户确认此次提交的影响是否符合预期后,变更才会正式进入 PR 阶段。
- 合法性,用户提交的任何关于资源变更的修改,上线之前都会经过审核人员(SRE 团队)的评估。
- 可审计性,任何关于云资源的变更都会被详细记录下来,便于变更追溯和第三方审计。
- 隔离性,基于服务树的设计,可以灵活地把任意节点和下面的子节点定义为一个租户,每个租户都为其创建单独的 pipeline 进行权限和网络的隔离。通过权限边界的隔离,一是便于组织租户内的资源,二是可以止损一些泛事件的影响,比如极端 bug、恶性行为等。
幂等性:保障代码可一次或多次按需应用变更
- 维护好 TF 的状态信息,即 TF 的 state 信息。TF 每次运行都会用对比云资源实际状态和 state 里记录的状态,若发现不一致的情况,TF 会以自己的 state 信息为基准去纠正实际状态。所以 state 信息需要独立维护,并且做好备份。目前我们采取的方案是 state 信息独立存储在Amazon S3 里,并且开启 object version 来备份每次更新,同时在异地备份,避免一些灾难性的不可逆事故。
- 处理好资源依赖。服务的部署通常比较复杂,有先后顺序、输入输出等等依赖关系,所以小到模块内部,大到整套 TF 代码,都需要确保这些关系是正确的,这样代码就可以到处部署了。
- 通过 TF 模块化的结构来限制一些变更。先解释下哪些属于重要参数,因为一些 云原生设计的特性,一些服务一旦创建出来,有些参数就无法修改了,或者修改后不会影响现有资源,只有下次创建新资源才会生效。TF 不但会继承这些特性,在有些场景还会强制植入些新的逻辑。因为云的特性,这种案例有很多,但是在大部分场景下我们可能不需要这样的“硬操作”,所以之前提到的“内部最佳实践”都会对参数和使用场景等等进行评估和设计。
唯一性:保障代码做为“源”,而不是环境影响代码
- 最小化授权,无论人员还是服务,只授权需要的的权限。原理很简单,但是实现起来还是有些难度,需要沉淀出各种场景的权限模板供大家参考与使用,主要原因如下:
- IAM policy 的学习成本高,涉及服务种类多,每个服务下面又有很多 action,还需要配置很多条件才可实现最小化授权,最终的结果是一个较复杂的组合。
- 用户往往可以描述出清晰的使用场景,但是不清楚所依赖的云服务和具体 action。
- 若资源被 TF 维护,那修改的途径也要通过 TF,否则就会产生歧义,到底该以环境状态还是代码状态为准。
- 尽量使用云原生服务来管理动态资源,支持动态扩展的原生服务已经为我们造好轮子了,除非功能不能满足我们需求。另外 TF 管理资源其实是非动态的,它需要记录在管的每个资源的生命周期状态,并且基于这些对应的状态才能做出决策。举个简单的例子,我们需要根据业务不同的时间段,来扩展集群里 Amazon EC2 的数量,如果直接使用 TF 管理每一个Amazon EC2,那我们就只能频繁地调整代码了。换个角度,如果利用 TF 直接管理 Auto Scaling group(以下简称 ASG),所有 Amazon EC2 托管于 ASG,非 TF 直接管理,这样的话我们只需要维护 ASG 的 schedule policy 和 Amazon EC2 的 launch template 即可优雅地固化 TF 代码。
- 监控方面,通过 TF 的 plan 功能进行异步检查,判断当前 TF 代码是否与线上环境一致。一旦检查到非一致的资源,主动发送报告给对应的负责人,由负责人修复。
结语
标准定义是一个团队持续思考与沉淀的过程,也是不断迭代与试错的过程,更是获得宝贵经验财富的过程。但是有了标准,如果没有强有力的执行,那么标准就失去了应有的意义。在之后的文章中,我们将重点介绍 FreeWheel 在标准化过程中的实践,以及运维平台如何发挥它的作用。