背景
随着互联网行业的兴起,敏捷开发、Devops被越来越多的公司提及或实施,力求有效地降低交付过程所耗费的成本并提高交付的效率。
持续交付通过建立自动化的构建、测试、部署机制,实现业务快速上线的过程。
在微服务架中,由于每个服务都是一个独立的,可部署的单元,由一个服务或多个服务组合对外提供服务,服务拆分粒度更细、服务之间依赖更加的复杂,服务的开发、测试、上线也必将带来更大的挑战。
微服务环境下持续交付面临的挑战
任何事情都有两面性,在享受微服务便利的同时,也必须面对微服务交付所带来的挑战。
经常听到大家聊到微服务架构时,聊得最多的是服务的拆分、实施微服务时采用的框架、技术选型、K8S、SpringCloud等等,所见到微服务架构项目,大多都没有真正做到“服务的独立部署”。
这里的的“独立部署”并不仅仅是简单的自动化部署,自动化部署相对简单,通过一些自动化工具、脚本等我们可以做到自动化部署。而微服务为什么不能简单的做到独立部署,不是“不能部署”而是“不敢部署”。
- 微服务依赖关系错综复杂,没有依赖的统一管理和依赖检查。
- 微服务是虽然在物理上被拆分成多个小的服务,但从交付角度来看仍以一个整体对外提供服务。
- 无统一的视图对开发、测试、生产环境的各个阶段进行管理。
- 服务上线后无完备的手段对服务的监控、安全、容灾、扩缩容、流量保护等。
因此微服务的实施不光是Devops的过程,更是一套生态环境、一套标准化开发、测试、生产上线的流程。
需要达成的目标
在持续交付中,我们需要构建一个标准交付流程,将开发、测试、运维、实施以及用户结合成一个整体。我们希望:
- 让软件构建、部署、测试和发布过程对所有人可见,促进合作。
- 有效的反馈,以便在整个过程中,我们能够尽早地发现并解决问题。
- 通过预定义流程保障不同角色在自己关注的领域内正确、高效的完成任务。
- 使团队能够通过一个完全自动化的过程在任意环境上部署和发布软件的任意版本。
怎样实施
基于微服务或云原生基础平台(持续构建平台、容器云平台、监控平台、网关平台、微服务编程框架)结合微服务的特性,抽象定义了服务的整个生命周期:从服务的定义、构建、依赖鉴权、部署、提测、发布、回收等各个阶段以流程的形式来规范开发、测试、运维等角色在各自领域的职责。
在服务各生命周期内通过定义事件或流程来串联各基础平台,各基础平台对事件响应并作出相应动作以确保微服务在整个生命周期内的可观测和可管理。
服务定义
在整个微服务的生命周期内,从微服务的定义开始,服务元数据会保存到分布式和版本化配置系统,为了规范在微服务环境中服务对外表述我们将从以下方面来定义服务:
- 服务统一描述符
- 服务依赖标识
- 服务类型
- 服务维护者
- 服务授权级别
- 服务黑白名单
- 服务证书、秘钥
服务初始化事件:
在服务被创建的时候,基于服务的定义我们制定了如下服务初始化事件,并将事件发送到各基础平台作出相应动作:
- 生成服务基础元数据 - (基础元数据管理平台)
- 生成服务的监控大盘模板 - (监控平台)
- 生成服务证书、公钥、私钥等资源 - (容器云平台)
- 绑定各环境下服务的域名 - (网关平台)
服务构建
基于自研的微服务环境下的编程框架,实现了服务治理的能力,提供了监控日志埋点、Metric、Trace等能力。
服务构建会基于编程框架的特性作以下动作:
- 扫描服务依赖列表
- 扫描API列表(为统计和追踪API提供更精确的API管理,排除Restful格式下PathVariable干扰)
- 强制版本升级检查
- 排除依赖Jar包的检查
除以上强制性的动作外,在服务构建的时候还可以根据需求注入不同插件以实现:代码静态扫描,动态分析,Sonar检查,Swagger生成等动作。
服务构建以自定义插件扫描的方式输出 服务依赖列表、API列表、Swagger文档、强制版本升级检查、排除依赖Jar包检查等动作,能最大限度的保障在微服务环境下
服务定义的完整性、依赖描述的准确性,提前避免部署运行时的兼容性。
服务依赖授权
在微服务环境下,我们提供了一套标准的基于TLS的访问控制策略。通过服务构建时扫描出的依赖服务列表,在服务部署之前需要先申请对被依赖服务的授权申请,被依赖服务(维护者)通过授权申请后
自动进入标准授权流程完成对依赖服务的授权操作。
服务部署
微服务环境中部署一个应用是很大的挑战,不能够像单体应用一样要求服务多副本部署,能正常启动就行了。
在微服务环境里由于一个应用由多个微小的服务组成并对外提供统一的服务,服务之间的相互依赖关系、服务之间的访问控制权限、服务对资源的消耗、服务健康检查机制、服务上下游拔测手段、服务之间流量路由和管理等问题将是我们不得不面对和解决的。
我们通过标准化流程管理组件来观察和规范服务部署、资源回收、线上运维等流程,标准化流程管理组件会将各事件抽象成“元语”,将“元语”下发到各组件执行并根据执行情况来串联起整个流程。
根据开发、测试、生产运维环境需求我们制定了如下流程:
- 服务部署流程
- 服务授权流程
- 灰度流量调整流程
- 资源回收流程
这里我们将以部署流程来重点讲解,其主要节点包括:资源规划、前置检查、资源申请、服务部署、功能验证、服务准入等操作。
资源规划
将一个应用拆分为多个微服务,每一个微服务单独部署,服务数量会成倍增加,因此有必要在部署时对消耗的资源进行规划,否则会造成资源的极大浪费,增加公司运营成本。
在资源规划时不能简单粗爆的限制CPU、内存、磁盘、网络带宽等,我们应该根据服务的特性把服务划分为不同的类型,比如:IO密集型、CPU密集型、GPU机器学习型、性能测试等,这样提交给容器云平台(资源调度)时能将服务正确的调度到不同类型的NODE节点上。
前置检查 && 资源申请
在部署之前除了进行一系列检查外,还需要申请并临时锁定申请到的资源,防止在部署的过程中其它服务抢占资源造成部署失败,主要包括如下几点:
- 镜像检查
- 依赖服务授权检查
- 依赖版本检查
- 配置文件检查
- 可用资源(CPU、内存、磁盘)申请(锁定资源) 检查是否有足够的资源支持本次部署
- 域名资源申请(锁定域名)冲突检查
- 监控模板是否生成
服务部署 && 功能测试
当完成上述前置检查和资源申请后进入到部署环节,容器云平台接收到部署事件后开始验证部署计划并执行部署计划完成部署,部署执行完成后验证部署结果。
- 容器是否启动完成
- 服务是否启动成功
- 服务注册是否成功
- 服务配置(框架、业务、流量、依赖等)是否拉取正确
- 上下游服务是否正常访问
- 服务健康检查
- 加入健康拔测任务
服务准入
完成服务部署及功能测试后进入到服务准入阶段,我们就可以导入流量完成服务准入了,由于一些服务既作为边界服务又作为其它服务的被依赖服务,在微服务环境下我们拆分为内网准入和外网准入两个概念。
内网准入:
微服务环境内依赖和被依赖关系,为了便于描述我们称被依赖服务为 服务端 ,依赖服务称为客户端,服务端服务需要被客户端服务发现,客户端服务调用服务端服务的流量规则等都属于内网准入的范围。
外网准入:
作为边界或边缘服务而言,网关平台绑定域名与部署实例,分配流量规则、流量比例等操作属于外网准入的范围。
在服务部署及功能测试通过后,下发准入命令,将部署服务其置为准入状态,这 客户端 就能发现刚刚部署好的服务,网关平台接收到准入命令后开始挂载域名分配流量规则等操作完成服务的整个部署。
服务准入只作为本文微服务生命周期内的一个流程事件,只是简单介绍了流程和动作,涉及到更复杂的流量路由、寻址等更高级的应用场景像:流量灰度、流量染色、自定义流量路由、流量负载、流量可视化管理等不在本文讨论范围内,感兴趣的朋友可以查阅 service mesh 等相关资料。
资源回收
微服务环境下的交付最重要的是尽量减少流量的损失,降低出错机率,提高服务的可用性,除了部署流程外当一个服务需要下线,或者当部署过程中出错后我们需要进入到资源回收流程。
资源回收流程与部署流程正好相反,主要节点包括:
- 生成服务快照
- 停止健康拔测
- 禁止容器调度
- 解绑域名
- 内网弹出(微服务环境内不能被发现)
- 服务注销
- 服务Shutdown
- 回收容器
- 释放资源
资源回收流程又分为普通回收流程、蓝绿回收、强制回收流程等,在服务部署过程的不同阶段对应不同的回收流程,这时不作详细介绍。
特别提示:在资源回收的不同阶段应该设置不同事件执行完成检查点,对错误事件的响应不同,一些不影响流量的事件可以自动忽略强制回收,一些关键节点上的错误需要人工干预。比如说解绑域名、与内网弹出必须保持其 时序性、幂等性、一致性等原则,可设计全局原子钟、分布式锁等方式来实现。
服务配置管理
服务在上线和部署过程中,出现问题最多的是配置管理问题,为了最大限度的减少开发、测试、生产环境部署的差异性特作如下规定:
- 一次部署对应一次配置
- 配置的生成由开发环境产生,是否“环境敏感”、是否“可动态下发”的配置项需要显示的标明
- 配置以K-V的形式保存随提测、发布流程流转到其它分区环境
- 配置项在提测、生产环境部署时不能被新增、删除、修改,配置项的值可以修改
- 环境敏感项在提测、生产环境需要确认和修改
- 运行时配置变更和下发仅限于 标明 “可动态下发”的配置项
- 完成配置下发配置版本自动更新,并可回滚到历史配置版本
环境分区与提测发布流程
为了尽可能的保证开发、测试、生产环境服务表述的一致性,减少因环境造成的上线差异性,同时基于对环境隔离、权限认证、资源规划的考虑,划分为3套环境(开发、测试、生产)。
分区提测:
开发并自测完成后提交提测发布计划:选择将要提测到的测试分区,提测流程会作服务分区初始化,依赖服务分区授权等检查,完成检查后生成分区提测单。
分区发布:
在提测通过后,根据提测发布计划提起发布流程,同样的在发布流程中我们也会作服务分区初始化,依赖服务分区授权检查及配置文件流转确认等,然后生成分区发布单。
特别说明一下:为了尽可能的在测试中靠近生产,尽最大限制减少因网络、权限等环境因素造成的差异性,不同的测试分区对应不同的生产分区,原则上部署在同一中心。
总结
本文中我们了解到在微服务环境下持续交付所面临的问题与挑战,同时也大致清楚了在微服务环境中为了持续交付我们所付出的努力,最后再强调一下:微服务环境下的持续交付并不是自动化的devops,其核心还是有没有规范和流程去保证微服务正确的独立部署。
作者: 天涯浪子 WX:wyuxiao729 欢迎交流讨论
参考
- Microservice Architecture(https://martinfowler.com/articles/microservices.html)
- The Twelve Factors (https://12factor.net)
- Challenges of micro-service deployments