0%

为什么需要本地开发环境容器化?

一个线上运行的应用,最开始都是在软件工程师的电脑里面开发的。因此,软件工程师的电脑里面会有一个本地的开发环境,用于IDE以及本地测试。

潜在问题

单体应用

如果项目是一个大型的单体应用,通常而言会有前端和后端开发工程师,以后端开发工程师为例,在后端开发工程师的电脑中会装有以下环境:

  • 语言的运行环境,比如JDK,Node.js等。
  • 数据库,比如MySQL,PostgreSQL。
  • 其他奇奇怪怪的东西。

如果该项目只有一个后端开发工程师,可能会有以下问题:

  • 线上运行环境与本地不一致,进而导致凭啥我本地都是好的,上线就遇到各种奇奇怪怪的问题。
  • 更换电脑之后,需要再次手动安装运行环境。
  • 操作系统升级可能会破坏已有运行环境。

如果该项目有多个后端开发工程师,在基于一个后端开发工程师可能会遇到的问题的基础上,可能还会遇到如下问题:

  • 工程师之间的操作系统版本不一样,通常不会遇到什么问题,遇到了那就呵呵哒。
  • 工程师之间的运行环境可能不一致,有可能是patch版本的差异,也可能minor版本的差异。
  • 重复的工作会被不同的人干很多次。
  • 上新人的成本高昂,需要事无巨细地指导。
  • 即使有一份完备的环境配置文档,也会出现手动配置错误。不要相信任何的手动操作,任何的手动操作都是不可靠的,无论操作者的水平多高或者多低。

如果该项目上线之后,转移给另外的一个运维团队去维护,可能会遇到如下问题:

  • 这东西怎么在本地启动?虽然有文档存在,但是在开发工程中仍然会有很多隐性的上下文。
  • 本地测试怎么跑?
  • 运维团队的工程师需要在本地安装无数的运行环境。

微服务应用

如果微服务应用是一个团队开发的,那么可能会遇到如下问题:

  • 工程师之间的运行环境可能不一致。
  • 服务之间的运行环境不一样,本地环境需要配置多个不同版本的环境。

如果是微服务应用多个团队开发的,基于上面情况遇到问题,可能还会出现如下问题:

  • 技术栈不一样,比如A团队使用Golang,B团队使用Java,C团队使用Node.js。
  • 代码风格不一致。

如果之后转移给一个独立的运维团队维护,会遇到如下问题:

  • 技术栈的多样性,导致运维团队学习成本居高不下。
  • 技术栈的多样性,同样会增加保持本地环境与线上环境的一致性的难度。
  • 代码风格的不一致,运维在修复一个bug的时候,可能会不停地切换技术栈和代码风格,甚至同一个技术栈的不同版本,运维团队的体验度会不断下降。

可能还有诸多问题是我所未考虑到的。

总结

大致总结一下上述问题:

  • 运行环境不一样,工程师之间的本地环境不一样,本地开发环境和线上运行环境不一样。
  • 技术栈的多样性,进而引入的隐性context。
  • 代码风格不一致

解决方案

基于上面的诸多问题,只能对一些问题提供解决一些解决思路。

运行环境的不一致

在所有的问题中,运行环境不一样是最普遍也是做容易解决的一个问题。在这一类问题中,最简单的解决方案就是容器化。

需要做到两个容器化:

  • 本地开发环境容器化。
  • 线上运行环境容器化。

我相信绝大多数团队都可以做到线上运行环境的容器化,因为这并不是一件很难的事情。而本地开发环境的容器化确实最容易被忽略的。

本地开发环境的容器化,可以很好地确保开发工程师之间的环境一致以及开发环境和线上环境的一致。同时,也可以很好地解决不同服务之间所采用的运行环境版版本不一致而导致开发出现的各种奇奇怪怪的问题。

技术栈的多样性

技术栈的多样性是我们所推崇和所追求的,其本身并不是问题,但是技术栈的多样性不可避免的会引入一定的副作用。而隐性上下文就是其中最明显的而又不容易被关注的。

什么是隐性上下文?简单举个例子,

  • A团队使用 node.js 开发,使用 npm 对包进行管理,可能会把单元测试脚本命令放在 package.json 中,也可能不会。
  • B团队同样使用 node.js 开发,但是使用 yarn 进行包管理,同样单元测试脚本可能放到 package.json , 也可能不会。
  • C团队使用 Java 开发,使用 gradle 进行包管理。
  • D团队使用 Kotlin 开发,使用 maven 进行包管理。

对于A团队而言,A团队知道如何把自己团队的本地环境运行起来,如何运行单元测试,可能会忘记这些内容写入到readme中或者package.json中。突然有一天,B团队的成员需要去更改一个A团队的实现,这个时候基于B团队的成员使用的技术栈而言,虽然会花点时间去阅读代码,或者基于已有的技术背景做出一些探索性的尝试,也是比较容易了解到如何本地启动A团队的服务,如何进行单元测试。

如果是C团队的程序需要更改A团队的一个实现,那么会是如何的呢?

如果有一天这个微服务应用完全交给了一个独立的运维团队运维,那么又会是什么样的呢?

这一类团队内部默认都知道的,没有通过脚本或者文档呈现出来的上下文可以被理解为隐性上下文。

如何解决隐性上下文?基于本地开发环境容器化的基础上,自动化脚本是一个比较好的实践方案。比如在每个服务代码库中,都写一个 auto/test 脚本,这脚本是负责跑单元测试,这样在不同团队之间是否会更好的管理这些隐性上下文?再比如代码风格检查也可以有一个脚本叫做 auto/check-style

代码风格不一致

服务与服务之间的代码风格不一致,这是正常的,不同的技术栈必然会导致风格不一致。

那什么是问题?

  • 服务内部的代码风格不一致。
  • 服务之间的代码风格不一致,但没有一个强有力的约束工具。

如何解决?我们所遵循的所有代码风格都应该被工具管理起来,都可以配置化。

总结

上述几个问题,解决方案就是 本地开发环境容器化以及自动化脚本。