CI/CD思想指南
缘起
2020年,让大多数务工青年领到到了比自己读书期间都要久的寒假。17年前,我们也经历过相同的苦难,思来想去,时间竟然过的如此之快,当年的小屁孩们也都在各行各业中发光发热,是时候要开始学会记录生活的点滴。
明明有很多CI/CD工具,大名鼎鼎如Jekenis,Gitlab,为什么想要自己造轮子?J,G们想要解决的是各种软件工程的过程,涵盖的多自然重,其灵活性又体现在诸多的插件和钩子中,而最主要的钩子又是shell脚本(绕了半天还是脚本,为什么不直接点呢?)。我们可能想要的就是能够解决实际问题(就是自己魔改的springboot项目,vue项目,基于客户现场环境的快速交付),那么自己的工具肯定才是最好的。
疫情就是命令
疫情就是命令,只有不断的更快的做好自己的工作,才能腾出时间去成长,成为更好的自己,为社会带来更大的价值和财富。作为从全栈工程师,我们的工作内容是从客户脑中的想法到服务运维,如果没有合适的工具,解决重复性的体力工作,那么就会逐步成为,想法可能非常多,总觉得自己的舞台太小,但是又必须在这个舞台上,依旧只能写业务代码的梦想派工程师。
闭上眼睛想一想,从业务工作到运维工作,重复性最强的就是系统部署,几乎不存在需要思考的内容。业界也称为CD(持续交付),今天的主题就是它了。
永恒不变的是变化
通过工具节省重复性工作的时间如果不能打动读者开展自动化持续交付设计,我是非常理解你的。我也没有因为节省那些工作的时间而产生设计的热情。真正激发热情的是由于总是存在需求的变化,这导致脑力劳动时间大大增加,当大脑高速运转的时候是完全不会想去做低级的,体力的事情。然而事情又必须是自己来做(能者多劳,多劳者应多得),自己和自己过不去,那就太没有必要了,这么一想,设计一个属于自己的CD工具,刻不容缓。
CI在下,CD在上
如果说客户至上,靠近客户的就是软件包,他们只需要这个可以使用的知识成果。相对于软件包的是它的实现源码,当然它的源码又是我们程序员兄弟劳动的成果。
内部CI
持续集成(CI),是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。
大白话就是要按时提交代码到版本库中,作为程序员,自动化测试可能很远,这又可能是另外一篇博客的内容。作为使用成熟语言的成熟程序员,我认为编译和发布这些已经不是持续集成的意义,毕竟在语言层面,IDE层面已经确保了代码都可以编译和发布的(故意提交错代的幼稚行为不在讨论的范围内)。
在IDE层面使用各种检查插件,确保代码的优雅和健壮,这是被推荐的。
总之,能把代码正确的推送到代码仓库,结合自生的实际情况进行自动化测试,就完成了对内的工作。
外部CD
持续交付(CD),是一种软件工程手法,让软件产品的产出过程在一个短周期内完成,以保证软件可以稳定、持续的保持在随时可以发布的状况。它的目标在于让软件的构建、测试与发布变得更快以及更频繁。这种方式可以减少软件开发的成本与时间,减少风险。
大白话就是把程序包部署到客户的服务器中,把服务展示出来。通常说CI和CD不分家,这是由于只有有了源码才可以有程序包,这是单纯的母鸡下蛋过程。但是从工具的角度上看,CD完全可以是一个工具,至于CI之后(通常意义上就是提交代码之后)要不要通知CD,如何通知,这个是仁者见仁,智者见智的事情,也是本文所想表达的观点,
隔断
本文的观点:CI和CD工具上应分开,以更好的分别适应对内和对外的环境差异性
开发环境可以严格一致,现场环境难求相同
随着团队协作意识的不断提高,完全可以使用物理方法(云化开发主机)和规则(编码规范)统一每个人的开发环境,确保任何人理论上都可以无缝替代。
现场环境完全由客户给定(通常不可能和开发环境相同),无论操作系统,网络环境,还是软件版本,太多的可变因素,与其追求高度一致,不然想着如何才能匹配现场环境。
所以这也说明,CI工具要面对的环境是一致的,可以呆板一些,CD工具面对的环境差异大,应该设计的更通用和灵活。
开发环境容易排错,现场环境则很难
开发环境有控制台,有断点调试,有链路追踪,本质上是牺牲性能确保一旦出现问题,就能把问题揪出来曝光,方便工程师对其处理。
现场环境通常只有日志,同时这个日志和开发环境的不太一样(毕竟开发环境排错的工具太多,很少会去直接关注日志,所以业务部分写日志的地方可能也不多),本质上是牺牲了追踪错误的能力换来性能的提升。
这说明,CI工具提示错误的方式方法可以很多,可以让人善心悦目,CD工具很难强求能非常友好的提示错误,因此设计上要尽可能简单直观,没有多余的操作,也尽量留下操作痕迹,方便事后追踪和完善工具。
总结
本设计思想中,CD工具是基于软件源码。软件源码作为分开CI和CD的隔板。
山高水深
书中得来终觉浅,实际操作得始终。
CD工具的设计原则有三:
- 技术偏向服务器,能用shell和python解决的不考虑其他。
- 结合软件项目情况,优先思考灵活变化的内容(例如配置)如何自动化。
- 能一个固定套路解决的问题就只要一个套路。
黑猫白猫
Linux 、shell、Python
技术没有好坏,只要能解决问题就是合适的。既然CD要解决客户现场环境的交付问题,那么尽可能的使用自带的编程技术(shell和python),建议使用一台主机(物理机或虚拟机)专门来做CD,以适配现场的网络情况。
曼珠沙华
美丽的事物有时候也是致命的。
自动的总是千篇一律的,自然最怕的个性化配置,但是之所以一套代码可以多处部署提供不同的服务也就是支持个性化配置,既然是跑不掉的,那么就要想办法解决。
思路一:CD工具向软件请求其配置模版,在CD过程中,通过值守人员配置处理。
思路一的实现方案很多,但是都必须软件支持。但是正因为软件是我们写的,CD工具也是我们做的,那么需要软件支持这种别人看起来很困难的事情,在我们眼里就是用左手写还是右手写的小事情了。
以springboot项目为例。
- 多写一个main方法(确保和另外一个常规用于运行的main方法在平行的两个目录中,确保它们使用相同的配置文件),增加CD工具获取项目所有配置文件的能力。
@SpringBootApplication
public class RunApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(RunApplication.class, args);
ConfigurableEnvironment environment = context.getEnvironment();
System.out.println("我来了");
// todo 获取配置,写出到当前目录
System.out.println("我走了");
context.close();
}
}
上述代码中运行后会自动关闭,具体如何写出配置文件,这个可以根据自生项目情况进行修改。
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.tor.app.Application</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
别忘记了,多个main入口时,需要给springboot打包插件指定入口。
- 使用maven命令行启动上述方法(基于源码启动)。
mvn exec:java -Dexec.mainClass="com.tor.run.RunApplication"
该命令在具有spring-boot-maven-plugin插件的pom.xml的同级目录中执行。
其主要目的是无论是否存在外部配置文件,内部配置文件对应的参数(数据库连接,缓存连接等)是否正确,都能成功的运行并可以根据自己的想法,写出配置信息。
此时,可以得出配置信息,具体的方案最终另整理成文。
思路二:CD工具从外部获得配置模版,在CD过程中,通过值守人员配置处理。
思路二从设计角度上是基于软件包交付的,即在CI过程后,应让现场环境有办法获取最终软件包和配置文件,再通过类似思路一的方式,通过程序实现CD过程中手动配置,思路二的难点在于需要软件开发过程中通过仓库做好包管理,这本身更加适用于单产品项目多用户部署的团队,毕竟仓库包管理并不是一件很容易的事情,至少需要安装私有仓库,还要考虑网络带宽,CI过程中产生准备的配置文件等等。
千言万语化为赞
工具是为了减少体力劳动量的,如果使用工具本身提留劳动减少,但是脑力劳动量增大,那么工具就没有任何意义。
这意思是,从源码到部署完成,经历了源码拉取,源码打包,配置模版,分发,停服务,个性化配置,启动服务各个阶段,每个阶段的工作应该有shell脚本或python脚本进行串联。
社交时代,千言万语想要抒发,思考了一分钟之后,你想要做的可能就是点个赞,简单就好,一招搞定。