乐趣区

关于云原生:如何设计一条稳定的应用交付流程|云效工程师指北

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

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

一次挫折的部署

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

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

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

旧交付形式的潜在问题

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

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

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

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

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

● 环境差异化配置须要靠人工核查来缩小错漏,编写 application.yaml 这类基准配置的时候也须要慎重考虑提供什么样的兜底值,一旦有过错则排查老本绝对高;
● Dockerfile 往往没有很大的差别,但构建进去的产物是和具体环境强绑定的,没方法复用;屡次编译可能因为某些隐患(最典型的比方依赖版本不严格)导致不同环境下的交付内容并不统一,有引入 bug、导致线上问题的危险。
○ 比方在日常环境下实现构建后,某个(可能是间接)依赖的快照包被更新了(可能是不标准的快照包更新,也可能是平安包之类抉择偏向于让接入方无感降级而应用快照版本当作 release);尔后部署到预发环境时,构建援用了新版本的依赖包,导致日常环境下的测试验收论断可信度降落。

单利用逐环境升级计划的考量

吃一堑长一智,咱们无妨帮阿伟的利用公布计划列出上面的考量:

● 产物对环境中立:环境差异化配置在部署时注入,一份镜像能够用于所有环境的部署。
● 环境配置对立:所有环境应用同样格局的配置模板和差异化的值注入,防止“兜底 + 笼罩”引入的配置模板差异。

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

这样做看起来限度了一些灵活性,但外围思考在于:通常状况下很难标准配置文件和编排的具体格局;一旦存在“一份配置兜底 + 多份差异化调整”的状况,了解利用代码逻辑和部署细节的老本会变高,保护、验证应用逻辑所需了解的内容也随配置文件的减少而线性增长。即便是利用的设计者或是 owner,也不免随着时过境迁而遗记一些细节(“我过后为什么要加这个环境变量来着”),更不必提中途退出进行性能迭代的其余开发人员了。

理论部署到 Kubernetes 集群中时,环境变量通过编排中容器的环境变量注入。接下来须要对立 Deployment 编排——如果为不同的环境应用多份编排文件,依然会引入无意义的反复。这里咱们能够应用 Helm chart 的模式,诸如镜像、环境变量等等在构建部署时能力决定的差异化配置,都能够通过 values 配置进行注入:

须要定制化的局部,则是 CICD 零碎中动静生成 Values.yaml 配置的脚本。这部分的复杂性绝对容易管制,具体的实现则依据应用的 CICD 工具不同而略有差别,咱们将会在后文中看到一个概况的示例。

计划革新例

当初能够回到阿伟的服务上进行革新了。

Step 1: 对立 application.yaml 和 Dockerfile

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

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

Dockerfile 则能够去掉所有环境差异化的环境变量定义、对立为一份配置,并假设环境变量都曾经正确注入。

Step 2: 编写 Helm chart

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

接下来,能够把原先的编排文件依照 helm 模板的格局简略改写,搁置到 cool-service-chart/templates/ 目录下。以 Deployment 为例:

咱们应用.Values.image 这一 helm 占位符将镜像注入容器。环境变量注入的形式则有多种——变量较少的状况下能够在 pod template 中间接定义 name 和 value;不过如果思考到更久远的扩展性,也能够采纳关注点拆散的形式,独自定义一份 ConfigMap 用于定义环境变量;这样做的益处,则是增加环境变量的开发者无需了解 Deployment 的具体构造,甚至只须要了解“往 ConfigMap 的数据定义里写一个键值对就能实现环境变量注入”就能够了。

基于这些思考,咱们定义容器应用上面的 ConfigMap 提供键值对、注入环境变量:

Chart 里的模板编写实现后,记得推送到一个 git 库里,不便前面应用。

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

在筹备好 Helm chart 的动态模板局部之后,须要为 CICD 工具编写部署时生成 Values.yaml 的脚本。咱们无妨假如阿伟的团队抉择应用 Jenkins 建设 CICD 流水线:

这里咱们次要关注 chart-complete.sh,它须要实现如下的工作:

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

如果曾经搭建了 helm 仓库,这里也能够抉择把生成好的 chart 推到仓库。

总结

在繁多利用逐环境升级部署的过程中,往往会波及到针对环境定制的差异化配置;为了防止 Dockerfile、配置文件等冗余带来的治理老本及 bug 隐患,咱们能够利用云原生 IaC 的劣势,基于对立的制品和编排定义,将环境的差异化配置项提早到部署时注入。这样,在各个环境中所部署的代码是完全一致的,进步了集成的可信水平及测试效率。

当然,从头搭建 CICD 体系往往也须要肯定的试错;云效应用交付 AppStack 提供了合乎前述实际的编排治理、环境治理和差异化配置能力,能够通过集成云效流水线 Flow,疾速搭建出整条升级流程,欢送大家尝试。

原文链接
本文为阿里云原创内容,未经容许不得转载。

退出移动版