如何设计一条稳定的应用交付流程?|云效工程师指北

简介: 如何设计一条稳定的应用交付流程?为持续交付的过程提供了规范化的可能,也为了引入了让人不时埋首于配置文件的小山里的麻烦。我们不妨从一次略有波折、稍显隐患的集成部署案例开始,看看如何着手设计一条更为稳定的应用交付流程。

大家好,我叫王泊,负责云效应用交付AppStack的开发。把应用部署到各个环境、一步步进行集成测试,最终发布到生产环境,是程序员工作中必不可少的组成部分;而云原生技术引入的容器化、IaC(基础设施即代码,Infrastructure as Code)等等技术与理念,为持续交付的过程提供了规范化的可能,但也引入了让人不时埋首于配置文件的小山里的麻烦。我们不妨从一次略有波折、稍显隐患的集成部署案例开始,看看如何着手设计一条更为稳定的应用交付流程。

640 (1).png

一次波折的部署

许多个迭代后,面对陪风扇一起嘎吱嘎吱转着的流水线,程序员阿伟会回忆起把系统部署到预发环境、提交最后一轮验收,然后被打回来的那个并不遥远的下午。当时他有一个酷炫的Java SpringBoot应用要上线,实现了酷炫的“在不同部署环境下、发送带环境路由标签的业务消息”的接口:

1.png

日常环境的镜像构建、部署和验收测试一路OK,但是在再次构建部署到预发环境后,阿伟发现消息丢了:预发环境的消费方并没有消费到消息。经过一系列不管黑屏白屏康到bug就是好屏的排查,发现问题起源于在预发环境使用的SpringBoot配置文件application-staging.yaml中漏配了routing.env属性,应用启动时使用了缺省配置application.yaml中的兜底值,导致消息tag打错。

具体的问题倒是解决了,不过多少会留下点顾虑:以后写配置项的时候,免不了翻来覆去diff一下,是不是漏了什么,会不会导致各个环境里的产物有微妙的结构差异引发bug……

旧交付方式的潜在问题

仍然以SpringBoot应用为例,一部分开发者将应用从传统的虚机部署迁移到Kubernetes上的容器化部署时,会使用类似下面的思路:

640 (2).png

框架提供了为不同环境编写不同application.yaml配置文件的机制,用以达到环境差异化部署的效果。我们不难构陷出小故事的主人公阿伟也使用了类似的思路:

● 使用application.yaml提供所有环境的共性(和一部分兜底)配置;
● 各环境的差异化配置由单独的application-xxx.yaml给出,覆盖兜底配置;各差异化配置不作特别的规范要求,允许属性取值不同,也允许引入某个环境特有的属性值;
● 为不同环境的镜像编写不同的Dockerfiles, 环境配置方面的差异主要在于启动应用时指定的参数不同。

一个典型的工程目录看起来像是这样:

640 (3).png

看起来很规整,但其实也引入了一些问题:

● 环境差异化配置需要靠人工核对来减少错漏,编写application.yaml这类基准配置的时候也需要慎重考虑提供什么样的兜底值,一旦有差错则排查成本相对高;
● Dockerfile往往没有很大的差异,但构建出来的产物是和具体环境强绑定的,没办法复用;多次编译可能因为某些隐患(最典型的比如依赖版本不严格)导致不同环境下的交付内容并不一致,有引入bug、招致线上问题的风险。
  ○ 比如在日常环境下完成构建后,某个(可能是间接)依赖的快照包被更新了(可能是不规范的快照包更新,也可能是安全包之类选择倾向于让接入方无感升级而使用快照版本当作release);此后部署到预发环境时,构建引用了新版本的依赖包,导致日常环境下的测试验收结论可信度下降。

单应用逐环境晋级方案的考量

吃一堑长一智,我们不妨帮阿伟的应用发布方案列出下面的考量:

● 产物对环境中立:环境差异化配置在部署时注入,一份镜像可以用于所有环境的部署。
● 环境配置统一:所有环境使用同样格式的配置模板和差异化的值注入,避免“兜底+覆盖”引入的配置模板差别。

具体来说,在“日常-预发-生产”的整条集成发布流程中,使用的镜像和编排只有一份;镜像中的SpringBoot应用里,也只使用application.yaml,不再引入其他差异化配置。

这样做看起来限制了一些灵活性,但核心考虑在于:通常情况下很难规范配置文件和编排的具体格式;一旦存在“一份配置兜底+多份差异化调整”的情况,理解应用代码逻辑和部署细节的成本会变高,维护、验证应用逻辑所需理解的内容也随配置文件的增加而线性增长。即使是应用的设计者或是owner,也难免随着时过境迁而忘记一些细节(“我当时为什么要加这个环境变量来着”),更不用提中途加入进行功能迭代的其他开发人员了。

640 (4).png

实际部署到Kubernetes集群中时,环境变量通过编排中容器的环境变量注入。接下来需要统一Deployment编排——如果为不同的环境使用多份编排文件,仍然会引入无意义的重复。这里我们可以使用Helm chart的形式,诸如镜像、环境变量等等在构建部署时才能决定的差异化配置,都可以通过values配置进行注入:

640 (5).png

需要定制化的部分,则是CICD系统中动态生成Values.yaml配置的脚本。这部分的复杂性相对容易控制,具体的实现则根据使用的CICD工具不同而略有差异,我们将会在后文中看到一个概略的示例。

方案改造例

现在可以回到阿伟的服务上进行改造了。

Step 1: 统一application.yaml和Dockerfile

首先我们要压缩服务中的SpringBoot application yaml配置,只留下一份:

2.png

这里使用了占位符${DEPLOY_ENV},要求环境变量提供routing.env的值。

Dockerfile则可以去掉所有环境差异化的环境变量定义、统一为一份配置,并假定环境变量都已经正确注入。

Step 2: 编写Helm chart

从创建一份空的helm chart开始:

3.png

接下来,可以把原先的编排文件按照helm模板的格式简单改写,放置到cool-service-chart/templates/目录下。以Deployment为例:

4.png

我们使用.Values.image这一helm占位符将镜像注入容器。环境变量注入的方式则有多种——变量较少的情况下可以在pod template中直接定义name和value;不过如果考虑到更长远的扩展性,也可以采用关注点分离的方式,单独定义一份ConfigMap用于定义环境变量;这样做的好处,则是添加环境变量的开发者无需理解Deployment的具体结构,甚至只需要理解“往ConfigMap的数据定义里写一个键值对就能实现环境变量注入”就可以了。

基于这些考虑,我们定义容器使用下面的ConfigMap提供键值对、注入环境变量:

5.png

Chart里的模板编写完成后,记得推送到一个git库里,方便后面使用。

Step 3: 编写Values.yaml生成脚本

在准备好Helm chart的静态模板部分之后,需要为CICD工具编写部署时生成Values.yaml的脚本。我们不妨假设阿伟的团队选择使用Jenkins建设CICD流水线:

6.png

这里我们主要关注chart-complete.sh,它需要完成如下的任务:

● 从git仓库克隆chart库的主干;
● 从环境变量中,生成values.yaml.

7.png

如果已经搭建了helm仓库,这里也可以选择把生成好的chart推到仓库。

总结

在单一应用逐环境晋级部署的过程中,往往会涉及到针对环境定制的差异化配置;为了避免Dockerfile、配置文件等冗余带来的治理成本及bug隐患,我们可以利用云原生IaC的优势,基于统一的制品和编排定义,将环境的差异化配置项延迟到部署时注入。这样,在各个环境中所部署的代码是完全一致的,提高了集成的可信程度及测试效率。

当然,从头搭建CICD体系往往也需要一定的试错;云效应用交付AppStack提供了符合前述实践的编排管理、环境治理和差异化配置能力,可以通过集成云效流水线Flow,快速搭建出整条晋级流程,欢迎大家尝试。若有收获,就点个赞吧!

点击下方链接,免费体验应用交付平台 AppStack。

https://www.aliyun.com/product/yunxiao/appstack?channel=yy_practice

lQLPDhtDba1KT2_NBDjNB4CwgwE-eOLUK_gCPyXeUECTAA_1920_1080.png

相关实践学习
2分钟自动化部署人生模拟器
本场景将带你借助云效流水线Flow实现人生模拟器小游戏的自动化部署
SVN版本控制系统
SVN是现在软件开发之中的主流软件版本控制工具,在工作之中利用SVN可以有效的解决多人开发的代码管理问题,本课程将为读者讲解SVN服务器的配置以及基于MyEclipse的SVN客户端插件的配置与使用,并且在讲解之中着重讲解了冲突的产生于解决。
相关文章
|
1月前
|
弹性计算 监控 JavaScript
云效Flow:打造高效、稳定的CI/CD流程实战指南
【10月更文挑战第7天】本文介绍了“云效Flow”这一CI/CD工具,通过实际案例展示了其在Node.js项目中的应用,包括自动化构建、测试及部署流程。云效Flow支持多种开发语言与框架,集成第三方服务,提供详尽的新手引导,简化了CI/CD流程的搭建,提升了开发效率与软件质量,特别适合初创团队和大型企业使用。
93 4
|
2月前
|
存储 网络安全 开发工具
快速认识和上手云效代码管理应用
要体验云效代码托管Codeup的本地命令行操作和SSH克隆/提交,请先安装Git并配置SSH公钥。登录Codeup后,新建代码库并设置相关信息。可从其他平台导入代码。提交代码支持网页和本地客户端两种方式。库管理员可邀请成员协作,并按需设置角色。此外,Codeup内置代码检测服务,支持自动触发扫描。功能开发完成后,可通过合并请求进行代码评审,确保编码质量。
97 1
|
3月前
|
缓存 运维 前端开发
阿里云云效操作报错合集之如何解决在使用流水线构建net8应用时遇到无法构建的报错
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
3月前
|
弹性计算 监控 JavaScript
【颠覆传统!】云效Flow——让你的CI/CD流程如虎添翼,轻松驾驭高效稳定的自动化部署之旅!
【8月更文挑战第8天】现代软件开发中,持续集成(CI)与持续部署(CD)至关重要。我最近使用了“云效Flow”,一款专为高效稳定的CI/CD流程设计的工具。它支持多种语言与框架,并易于集成第三方服务。只需注册并创建项目,平台便提供新手引导。以Node.js项目为例,代码托管在GitHub上后,在云效Flow中设置流水线,通过YAML自定义构建与测试步骤。代码提交后,构建自动执行。部署环节可利用内置策略,如一键发布到阿里云ECS,并支持蓝绿部署确保平滑切换。此外,云效Flow还具备监控与告警功能。总之,云效Flow简化了CI/CD流程,提高了开发效率与软件质量,适合各种规模的团队使用。
80 2
|
5月前
|
敏捷开发 Cloud Native 测试技术
阿里云云效产品使用问题之应用发布是否支持角色转移
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
5月前
|
敏捷开发 自然语言处理 测试技术
阿里云云效产品使用问题之是否支持发布单审批流程
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
4月前
|
弹性计算 运维 Kubernetes
阿里云云效操作报错合集之构建流程中遇到 "origin_value 类型错误,取不到DOCKER_URL" 这样的错误,该怎么办
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
4月前
|
敏捷开发 Java 测试技术
阿里云云效产品使用合集之流水线、应用和项目集该如何迁移
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
4月前
|
敏捷开发 弹性计算 测试技术
阿里云云效产品使用合集之应用模板功能如何用于之前已创建的项目的关联
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
5月前
|
安全 Java Shell
阿里云云效产品使用问题之要配置云效只重启应用的流水线,该如何操作
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。