注意事项 佩雷夫 :原始文章由波兰小公司Three Dots Labs的创始人之一MiłoszSmółka撰写,专门研究“先进的后端解决方案”。 作者借鉴了他在积极使用GitLab CI方面的经验,并向该开源产品的其他用户分享了积累的技巧。 阅读它们之后,我们意识到他所描述的问题离我们有多近,因此我们决定与更多的读者分享提议的解决方案。
这次,我将介绍GitLab CI中的更多高级主题。 这里的常见任务是在管道中实现非标准功能。 大多数技巧是特定于GitLab的,尽管其中一些技巧可以应用于其他CI系统。
运行集成测试
通常,使用
单元测试的代码验证
很容易连接到任何CI系统。 通常,这并不比以编程语言运行内置在标准实用程序集中的命令之一复杂。 在这样的测试中,您可能会使用各种moki和stub来隐藏实现细节,并专注于测试特定的逻辑。 例如,您可以使用内存数据库作为存储或为HTTP客户端编写存根,这些存根将始终返回已准备好的响应。
但是,迟早您将需要
集成测试,以涵盖
测试中更特殊的情况。 我不会讨论所有可能的测试类型,而只是说
集成是指使用某种外部资源的测试。 它可以是真实的数据库服务器,HTTP服务,连接的存储等。
在GitLab中,很容易将可插拔资源作为与运行脚本的容器关联的Docker容器来运行。 可以使用
services
定义这些依赖关系。 如果在
alias
字段中指定了图像,则可以按图像名称或选择的名称使用它们。
这是在MySQL中使用可插拔容器的简单示例:
integration_tests: stage: tests services: - name: mysql:8 alias: db script: - ./run_tests.sh db:3306
在这种情况下,在测试脚本中,您将需要连接到
db
主机。 使用别名通常是一个好主意,因为使用别名可以替换映像,而无需修改测试代码。 例如,您可以使用
mariadb
替换
mysql
映像,该脚本仍将正常运行。
等待容器
由于插件容器的加载需要时间,因此您可能需要等待才能发送任何请求。 一种简单的方法是使用定义的超时时间
等待它的.sh脚本。
使用Docker Compose
在大多数情况下,
services
应足够。 但是,有时可能需要与外部服务进行交互。 例如,在两个单独的容器中启动Kafka和ZooKeeper的情况(这是收集官方图像的方式)。 另一个示例是使用动态数量的节点(例如Selenium)运行测试。 运行这些服务的最佳解决方案是
Docker Compose :
version: '3' services: zookeeper: image: confluentinc/cp-zookeeper environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: image: confluentinc/cp-kafka environment: KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 ports: - 9092:9092
如果将安装与可信赖服务器上的GitLab运行
程序一起使用,则可以通过
Shell执行程序运行Docker Composer。 另一个可能的选择是
Docker in Docker (
dind
)
dind
。 但是在这种情况下,请先阅读
本文 。
使用Compose的一种方法是设置环境,运行测试,然后销毁所有内容。 一个简单的bash脚本如下所示:
docker-compose up -d ./run_tests.sh localhost:9092 docker-compose down
只要您在最小的环境中运行测试,一切都会很好。 尽管可能会出现需要安装一些依赖项的情况……在Docker Compose中还有另一种运行测试的方法-它允许您在测试环境中创建自己的Docker映像。 在其中一个容器中,运行测试并使用相应的返回码退出:
version: '3' services: zookeeper: image: confluentinc/cp-zookeeper environment: ZOOKEEPER_CLIENT_PORT: 2181 kafka: image: confluentinc/cp-kafka environment: KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 tests: image: registry.example.com/some-image command: ./run_tests.sh kafka:9092
请注意,我们消除了映射端口的需要。 在此示例中,测试可以直接与所有服务交互。
它们的启动是通过一个命令执行的:
docker-compose up --exit-code-from tests
--exit-code-from
--abort-on-container-exit
意味着
--abort-on-container-exit
,这意味着:由
docker-compose up
发起的整个环境将在其中一个容器完成后停止。 该命令的完成代码将等同于所选服务的退出代码(即,这些是上面示例中的
tests
)。 如果启动测试的命令以非零代码完成,则整个
docker-compose up
将随之退出。
将标签用作CI标签
警告 :这是一个不寻常的想法,但在我看来,它非常有用且灵活。
如您所知,GitLab具有在项目和组级别可用的标签功能。 可以在票证上设置标签并合并请求。 但是,它们与管道没有关系。

进行一些细化可以使您在作业脚本中访问合并请求的标签。 在GitLab 11.6中,一切变得更加容易,因为 如果管道
only: merge_requests
使用
only: merge_requests
,则会出现
CI_MERGE_REQUEST_IID
环境变量(是的,它具有
IID
而不是
ID
)。
如果
only: merge_requests
未使用
only: merge_requests
或您正在使用旧版本的GitLab,仍然可以使用API调用获取MR:
curl "$CI_API_V4_URL/projects/$CI_PROJECT_ID/repository/commits/$CI_COMMIT_SHA/merge_requests?private_token=$GITLAB_TOKEN"
我们需要的领域是
iid
。 但是,请记住,许多MR可以针对给定的提交返回。
收到MR IID后,仅需转到
Merge Requests API并使用答案中的
labels
字段即可:
curl "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID?private_token=$GITLAB_TOKEN"
登入
不幸的是,目前
无法使用
$CI_JOB_TOKEN
访问项目API(至少在项目不是公共的情况下)。 如果项目的访问权限受限(内部或私有),则要在GitLab API中进行授权,您将需要生成个人API令牌。

但是,这不是最安全的解决方案,因此请小心。 如果令牌落入坏人之手,则对您所有项目的写权限可能会随之出现。 降低风险的一种方法是创建一个单独的帐户,该帐户有权读取存储库并为该帐户生成个人令牌。
您的变量有多安全?
几个版本之前,“
变量”部分称为“
秘密变量” ,这听起来像是为了可靠地存储凭据和其他关键信息而创建的。 实际上,这些变量只是对没有维护者特权的用户隐藏。 它们未在磁盘上加密,并且泄漏很容易通过脚本中的环境变量发生。
添加任何变量时请记住这一点,并考虑在更安全的解决方案(例如,
来自HashiCorp的Vault )中
保密 。
用例
由标签列表决定如何处理。 这里有一些想法:
- 使用它们来细分测试。
- 使用带有冒号作为分隔符的键值语义(例如,标签,如
tests:auth
, tests:user
) - 包括作业的某些功能。
- 如果标签存在,则允许调试特定作业。
调用外部API
尽管GitLab随附了一组可用的功能,但您很有可能希望使用可以与管道集成的其他实用程序。 当然,最简单的实现方法是调用良好的旧
curl
。
如果创建自己的工具,则可以教他们听
GitLab Webhooks (请参阅项目设置中的“
集成”选项卡)。 但是,如果您打算将它们与任何关键系统一起使用,请确保它们满足高可用性要求。
示例:Grafana批注
如果您使用
Grafana ,则
注释是在图表上标记随时间推移发生的事件的好方法。 不仅可以通过在GUI中单击来手动添加它们,还可以通过调用
Grafana REST API来添加它们:

要访问API,您将需要生成一个API密钥。 考虑创建一个访问权限受限的单独用户:

在项目设置中定义两个变量:
GRAFANA_URL
-Grafana安装的URL(例如https://grafana.example.com
);GRAFANA_APIKEY
生成的API密钥。
为了能够重用它,请将脚本
与常用脚本一起放入
存储库中 :
现在,您可以使用必要的参数将其调用添加到CI配置中:
deploy: stage: deploy script: - $SCRIPTS_DIR/deploy.sh production - $SCRIPTS_DIR/grafana-annotation.sh "$VERSION deployed to production" deploy-production
可以将这些调用放在
deploy.sh
脚本中,以简化CI配置。
奖励:快速提示
GitLab在所有可用于配置CI的关键字方面都有
出色的文档 。 我不想在这里重复其内容,但我会指出一些有用的情况。 单击标题以查看相关文档。
通过为CI变量定义模式,可以为某些分支定义自定义程序集。 例如,这可能有助于识别紧急修复的推送修复,但不要滥用它:
only: refs: - branches variables: - $CI_COMMIT_REF_NAME =~ /^hotfix/
GitLab在每个CI作业中都有许多
预定义的变量 -请使用它们。
使用它们来避免重复。
从11.3版开始,您还可以使用
extend关键字 :
.common_before_script: &common_before_script before_script: - ... - ... deploy: <<: *common_before_script
默认情况下,管道中收集的所有工件将被转移到所有后续作业。 如果您明确列出作业所依赖的工件,则可以节省时间和磁盘空间:
dependencies: - build
或者-相反-如果不需要,则完全跳过所有内容:
dependencies: []
如果作业不使用这些文件,请跳过存储库克隆:
variables: GIT_STRATEGY: none
仅此而已!
感谢您的阅读! 有关反馈和问题,请通过
Twitter或
Reddit与我联系。
更多的GitLab技巧可以在以前的文章中找到:
译者的PS
另请参阅我们的博客: