亚马逊AWS官方博客
FreeWheel 云环境治理实践:基础资源交付
前言
和很多团队一样,FreeWheel 也是从简单的脚本调用云原生 API 接口开始管理云上资源的。随着业务的不断发展,内部产品线拆分与重组、多账号和多区域的扩张,这种零散的维护模式已经难以应对日益复杂多变的云环境。
为了解决这个痛点,FreeWheel 决定构建一套服务平台,高效地为众多团队交付安全一致的基础资源,并在其生命周期内提供良好的可维护性。
本文将介绍 FreeWheel 如何在亚马逊云科技上实现规模化的持续交付和基础资源维护。
背景
资源维护平台构建的核心思路是践行 Infrastructure as Code 模式,基于 Terraform 实现亚马逊云科技上基础资源的维护。整体方案根据 FreeWheel 自身业务需求,通过自研与开源服务相结合的方式,完成平台生态化构建。平台建设的目标是面向内部团队,提供规基础资源维护自助服务系统,保证基础资源符合公司安全规范并遵守业界最佳实践,规模化管理众多亚马逊云科技账户、区域和可用区。
需求分析
作为软件开发工程的起点,需求分析的关键要点之一是尽量避免需求碎片化。我们结合各部门的需求和云计算的特性,把基础资源的交付需求在技术层面分为四类:
一致性保障
- 利用 Infrastructure as Code 方式维护云上基础资源。
- 基于模块化与参数化的模式,自动生成代码,保证代码风格的一致性。
- 平台化基础架构,作为统一入口,保证其权威性。
可管理性
- 代码版本化控制,利用 Git 相关功能实现代码管理。
- 利用 Policy as Code 方式,嵌入公司审计策略,如安全合规策略、标准化命名、场景化最佳实践等。
- 内部公开化代码仓库,通过自动化与人工结合方式,审批代码修改。
安全合规性
- 针对不同场景,执行相应的变更审批流程。
- 主动加被动的方式执行安全合规性审计,及时发现不合规资源。
- 最小化权限,针对人员与程序授权的不同流程化权限。
高效性
- 自助服务,有权限用户均可合理的管控各种环境的资源。
- 降低学习成本,用户通过 UI 交互方式实现控制变更、数据指标查询等。
- 微服务化架构,提供灵活的扩展能力。
流程介绍
常言道,重复的事情标准化,标准化的事情自动化,高效的标准化流程设计将为我们后续自动化打下坚实的基础。从业务流程角度来说,基本流程可分为四个环节:
- 程序化生成代码
- 测试并审核代码
- 合并代码到业务分支
- 根据代码完成基础资源变更
我们把基础资源的增、删、改操作均定义为变更行为,变更分又可以分为两类:
- 程序触发:由程序发起,根据预定好的模版来控制基础资源,如一些已经过验证与审核过的重复性工作。
- 人工触发:由用户发起,未经过验证的需求,如一些线上业务的临时调整,新服务上线等。
无论以上哪种变更,只要通过自动化或人工的审核,都可以很快的把需求部署到特定环境。当功能成熟后,程序化触发也可以作为一个基础服务,供不同业务层进行接口化调用。
程序化生成代码
Terraform 是由 HashiCorp 创建的开源“基础架构及代码”工具。这个模块的设计思路是利用 Terraform 的模块化功能,把逻辑封装到私有化模块中,这样只需要输入一些简单的自定义参数,就可以生成需要的基础资源。用户只需要根据自己的需求,选择对应的 module 即可,其中的命名规范、安全合规性以及最佳实践已经由 SRE 团队预制于 module 中了。
Module 的管理
对于 Terraform module 的管理,我们构建了一套私有化 module 模型。结构如下图:
Module 的定义
我们将 module 分成两种类型:
- 基础服务层:针对于亚马逊云科技基础服务,我们会按照云基础服务定义不同场景的 module,并支持版本化。比如 Amazon Identity and Access Management(IAM)服务中 Role 这个功能,我们针对 Amazon IAM Delegation Role、IAM Native Service Role 、Amazon Elastic Kubernetes Service (Amazon EKS) 的 IAM Roles for Service Accounts (IRSA) 等不同场景制定出不同的 module。在不同的场景下,我们会定义出其对应的命名规则,符合公司安全策略的部署参数,比如强制开启加密、关闭公网暴露、强制执行该服务的推荐配置等一系列预制模版。
- 业务组件层:对于业务组件,用户直接按需选择对应的基础服务层组件,像搭积木一样组合出完整组件即可。基础组件层对用户透明,用户只需要在自己的 module 里引用对应组件的版本,然后通过参数传递的方式来调用组件。后续业务层组件可以通过修改基础层组件的不同版本,来升级更新自己的组件。
Module 的版本化
在集中化管理的方案中,版本化是个很重要的环节。随着公司内部策略的不断变更和亚马逊云科技技术栈的快速迭代,基础组件模版也需要不停的升级,这里所指组件的升级可以分为两类:
- 兼容性升级,即对用户透明的升级
- 补丁式升级:比如 bug 修复,模块内参数调整等。
- 策略类升级:比如执行公司内部新推行的强制安全规则等。
- 非兼容性升级,即需要用户干预的升级
- 功能性升级:比如亚马逊云科技对服务的升级与上新,出现不兼容老版本的 API 接口。
- Terraform 升级:比如 Terraform 亚马逊云科技 Provider 的升级,造成一些 state 或 code 的不兼容问题。
针对以上问题,我们使用业界通常规范,主版本号+次版本号+修订版本号。使用次版本号和修订版本号来控制所有兼容性升级,即用户不更换主版本号的情况下,可以直接升级。使用大版本号控制非兼容性升级,即用户更换大版本号时需要人工介入。
Module 的集成
所有基础层 module 作为一个独立的仓库,以 submodule 的形式供其他业务组件集成。这样运维团队就拥有了集中管理的能力,只需要维护一套基础仓库,即可服务于上层不同的业务团队。
Module 集中化管理的优劣
优势:
- 确保了资源管理一致性,单一源修改,即可同步扩散至所有引用节点。
- 加强了资源合规性的把控,所有底层模块的修改都在单一源中发生,管理者可以审核控制这些变更。
- 实现了组件的集成化,用户开箱即用,不需过多关注底层逻辑。只需修改引用的组件模块或者版本,即可实现需求的变更。
劣势:
- 管理人员需要更多关注如何保证模块版本的兼容性。
- 需要建立严格的审批检查流程来控制代码的变更。
我们之所以选择这种集中化管理的方案,因为综合实际情况来看,我们团队日常需要跨越几十个亚马逊云科技账户,十几个可用区,支撑上千个业务组件,拥有集中管理的能力,其利远大于弊。
自动化生成代码
在众多的终端用户面前,每个人对代码的编写理解都会不一样,如何保证代码的质量和一致的编写风格是一个非常有挑战的事情。在大量的需求下,常规的提交代码、等待审计、合并代码的模式,无疑会消耗审核者大量的精力。为了解决这个问题,我们自研了一套服务,结合之前提到的 module 管理方式,在前端使用模版的方式引导用户填写参数,然后在后端自动渲染生出对应的代码,进而实现了变更流程的程序化。通过我们自研的协议,实现 Terraform code 在 HCL 和 JSON 之间的双向转化,如下图:
这个服务实现了前端通过模版可视化来渲染 Terraform code 和 module 的功能,用户通过浏览器,按照指引选择所需模块和填入必要参数即可完成 Terraform code 的编写。标准化的 code 书写,减轻了使用人员的学习成本和管理人员的审核压力,同时也实现了代码即文档的功能。效果如下图所示:
我们将这个功能作为完整的 API 接口进行内部公开,以方便其他平台进行调用整合,进而实现完整的自动化流程。
单元测试
代码生成后,就要进入严格的单元测试了,若代码无法通过以上测试,会被驳回,待用户修改后,重新进行单元测试。在这个环节,我们主要验证以下几个方面:
- 代码的可执行性与语法校验。
- 模拟运行结果,供审批者审核。
- 命名及资源标签的合规性校验,确保资源标签值和我们标签树系统里保持一致,避免后续对计费和安全隔离产生非必要的影响。
- 公司内部安全策略的合规性校验,比如一些安全配置的审核。
为了更好的实现自动化,我们这里引用了 Policy as Code 的模式,基于开源工具 CheckOV,我们定义了一些列策略,将不同的策略组应用到不同类型的 pipeline 中,针对 Terraform 的 plan 结果做审核校验。
审计与合并代码
审计环节,同样也是分为两种:
- 程序自动提交的申请。这些请求都是提前预制好的模版,操作均是通过验证的重复性操作,所以只要通过单元测试,我们会自动的合并代码。
- 人工提交的申请。这种请求,一般都是非常规性的业务相关的调整,我们的管理者收到请求后,会根据单元测试的结果做再次审核,确保对线上服务不会产生非预期的严重影响。
应用变更
对于程序化的申请,这个变更环节是自动的。对于人工请求的处理,管理员将会触发对应的 pipeline,获取 Terraform plan 的结果,经过仔细审核后,由管理员决定是否将变更派发下去。
架构介绍
这样一个自动化的变更审批流程是基于一个怎样的架构来实现的呢?很显然这个架构需要足够的能力来支撑整个公司级别的业务。完整的服务架构如下图:
代码编写模块
上个章节已经介绍过了,由前端和后端配合私有协议来渲染代码,除此之外还需要维护工作目录的代码状态,管理提交前代码的生命周期,比如会涉及缓存未提交的代码,重置工作目录等功能。
代码验证模块
该模块作为一个独立的服务,其包括代码校验,单元测试,提前阻挡不合规的变更,并为后续代码审核提供相关决策数据。
其中强制性策略会预制在模块逻辑中,对于一些由输入变量控制的配置,我们通过 Policy as Code 模式,按需融入到不同 pipeline 里,直接对模拟变更结果做检查,如此一来,能更好的保证代码的安全性和合规性。
Pipeline 模块
该模块包含两部分,自身的 pipeline 服务和其管理服务。
Pipeline 服务
我们使用的是 Amazon Elastic Container Service (Amazon ECS) —— 一项完全托管的容器编排服务,在统一的 docker image 的 layer 上提供 Image layer 的异构化支持。我们为在 Amazon ECS 运行的 task(基于容器运行的程序的最小定义单元)定义独立的 Amazon IAM Role,通过 IAM Role 所关联的 IAM Policy 对不同的运行的 pipeline 进行最小权限授权,进而实现了权限隔离。
Pipeline 管理服务
我们为不同的 pipeline 定义了不同的模版,以此形式在 pipeline 层面提供异构化支持,同时我们也拥有了很好的分层控制能力。
监控模块
该模块会将正常的变更周知相关组件的负责人。同时也会异步的捕获异常变更,然后发出告警,帮助我们消除配置漂移的问题。
结语
随着云厂商技术的不断发展,基础资源的供给已经变得非常灵活和高效,为我们的业务发展提供了很好的助力,同时也给运维团队带来了不小的挑战。面对效率、安全与费用成本的多重压力,一整套完善的云环境资源治理解决方案可以帮我们解决大部分日常维护管理问题。各厂商与开源社区都在努力为终端用户供各种优质的工具来支持云资源管理,无论利用何种工具,我们都要坚持把确保安全、提高协作效率作为核心目标不断推进技术演变。