持续部署不仅仅是针对应用程序

56 阅读4分钟

当我们把更多的生产服务推向持续部署,以实现更快、更安全的发布时,我们发现我们可以把持续部署的理念融入我们的文化和我们堆栈的所有领域。

Cross-posted to Braintree's Product and Technology Blog:持续部署不仅仅是为了应用程序

image.png

我们现在持续部署用Ruby和Java编写的重要的内部库,并计划加强这一努力,以包括内部工具。我们的工程师在为共享库做贡献时经历的过程是这样的:

  • 开发人员查看共享库并进行修改
  • 开发人员打开一个拉动请求
  • Jenkins测试、构建并发布库的测试版本
  • 拉动请求被审查和迭代
  • 在迭代过程中,开发者可以在一个或多个使用该共享库的应用程序中升级到测试版本
  • 一旦拉动请求被合并,Jenkins就会发布一个新版本的库
  • 开发人员就可以在应用程序中升级该库

我们发现,持续部署我们的库消除了重复性的工作,并帮助我们在单体库不可行的情况下快速推进共享代码计划。 新的工程师现在可以通过阅读简单的脚本而不是描述我们发布过程的冗长文档来轻松地集成和贡献于库。从开放的拉动请求中部署测试版本,使工程师有能力对跨越应用程序和共享库的功能进行迭代,而不需要提前合并到主库。

以下是我们为使这一过程尽可能简单而采取的步骤。

版本管理

第一个大问题是如何对库进行版本管理。对于语义上的版本管理,我们会使用major.minor.patch (例如:v2.3.1 ),但是当你要发布主分支的每一次提交时,这就不太合适了。

我们对版本划分进行了几次迭代,我们目前的版本方案看起来像major.datetime.description.git_revision 。例如,用于消费的版本可能是4.20181210231852.master.ef57297 ,而拉动请求可能是0.94.20181210231646.pr.24fcfd5

  • 主要版本。我们使用0 的主版本来测试版本。而且我们只在做向后不兼容的修改时增加主版本。
  • 拉动请求号:如果这是一个拉动请求,我们会包括拉动请求号。
  • 日期。日期有两个作用。首先,它确保新发布的版本比旧版本排序更高。其次,它允许你在不查看git修订版的情况下,一眼就能知道这个库有多老。
  • 描述。我们在主版本中加入master ,在PR中加入pr 。我们这样做是为了清楚地表明一个版本是从哪里构建的。虽然我们也用主要版本来表示,但对人类来说,看到描述会更清楚。
  • Git修订版。这使我们能够准确地知道哪个版本的代码产生了这个版本。

拉动请求

我们还想鼓励工程师们在共享库中迭代修改,而不是过早地将他们的工作成果合并到主库。我们想让跨越共享库边界的工作变得尽可能的简单。

为了支持这种行为,我们在每个拉动请求上建立并发布每个共享库的一个版本,其版本永远不会取代主库的建立。我们使用0 的主版本来表示该构建不是当前或未来主版本的发布。我们使用一个与拉动请求编号相匹配的次要版本,这样库的消费者就可以锁定该次要版本以获得对他们拉动请求的更新。

我们的构建系统向拉动请求发布评论,并附上已发布的版本,以确保新的工程师立即发现这个工作流程。 image.png

Jenkins向我们的拉动请求发布了一条信息

使用库

我们的版本模式意味着库的Ruby消费者可以将自己固定在一个主要版本上,并在不破坏其集成的情况下获得升级。

例如,这将在ruby Gemfile中通过使用tilde操作符引用最新版本。

gem "mylib", "~> 2.0"

对于拉动请求,在ruby Gemfile中看起来像这样。

gem "mylib", "~> 0.89.0"

在ruby中,这意味着你可以用bundle update mylib 将库更新到当前主要版本的最新版本。

也欢迎消费者销往特定版本,比如在ruby中是这样的。

gem "mylib", "4.20181210231852.master.ef57297"

而在maven的pom.xml中。

 <dependency>
   <groupId>braintree</groupId>
   <artifactId>mylib</artifactId>
   <version>4.20181210231852.master.ef57297</version>
 </dependency>

接下来的步骤

我们正在将更多的库和内部工具转换为这种方式。让我们知道你是如何在你的文化中建立持续部署的!