注意事项 佩雷夫 :原始文章由波兰小公司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
另请参阅我们的博客: