听过持续集成的人应该都知道Jenkins的鼎鼎大名,如果我们代码仓库选择了Gitlab,那可能还会听说另一种相对小巧的持续集成方案:Gitlab CI,这个从Gitlab 8.0开始就已经集成的工具正在变得越来越强大,如今已经可以在大多数场景下取代Jenkins了。
使用Gitlab CI非常简单,在项目的根目录下新建一个".gitlab-ci.yml"文件,并将规则写入即可,例如一个执行nodeJs单元测试的步骤可以这么写:
# 启用的步骤
# 每个stage表现为gitlab/pipeline页面对应构建任务stages列的一个按钮
stages:
- test
# 定义指定步骤的一个子任务,test-job为该子任务的名称,可以随意起名
test-job:
# 指明当前子任务属于哪个步骤
stage: test
# 当前子任务的脚本将在指定docker容器中运行
# 实际上Gitlab CI会运行这个镜像,并将项目文件整个挂载到容器的工作目录下
image: node:8.1.2-slim
# 需要依赖的服务,Gitlab CI会运行这些服务
# 并以一定的规则将其链接到image指定的容器中
# 也就是说,image内的容器可以通过一个名称访问services中的容器
services:
- mongo:3.2
# 指明执行这个任务的机器
# Gitlab CI需要将任务运行在Gitlab Runner中
tags:
- docker
# 将要执行的脚本
# 如果指明了image,则脚本会在image对应的容器中执行
# 否则会直接在Gitlab Runner中运行
script:
- npm i
- npm test
# 文件缓存策略
cache:
key: "$CI_BUILD_REF_NAME"
paths:
- node_modules/
当我们提交代码到Gitlab时,Gitlab首先检测到.gitlab-ci.yml文件并解析出其中的任务:
- 获得一个步骤:test
- 获取test步骤下的一个任务:test-job
- 在tags指定的标签为docker的Gitlab Runner机器上,拉取node:8.1.2-slim和mongo:3.2两个镜像。
- 运行mongo:3.2,运行node:8.1.2-slim并将项目文件挂载成工作目录,接着将mongo:3.2服务以mongo这个名称链接到node:8.1.2-slim容器内以供访问。
- 在node:8.1.2-slim容器内执行script中的命令。
- 以分支名为key,缓存node_modules文件,下次提交时自动加载。
总体来说,使用还是相对简单的。
但也存在一些场景可能会希望在本地模拟Gitlab CI的运行,比如我们在学习阶段,不确定写法是否可行又不想推到Gitlab形成记录时,或者,需要在本地验证单元测试代码,但希望可以像Gitlab CI一样挂载一个干净的数据库容器时,这些特殊的情况下,本地如果有一套类似的机制就会非常有帮助。
实际上,实现一个没那么复杂的Gitlab CI确实不难,只要我们理解了Gitlab CI的运行机制问题就清晰多了,大致需要实现下面4个功能:
- 至少能运行脚本命令。
- 可以将脚本命令放入指定的容器中执行。
- 可以将依赖的服务链接到指定的容器中。
- 最好在任务结束时能自行清理。
在本地实现的话,优选方案可以是shell脚本(所以windows用户请飘过 ~):
#!/bin/sh
network="local_c