如何配置GitLab Runner实现一次仅运行一个流水线?
解决GitLab流水线并发冲突的方案
针对你遇到的同一Runner同时触发多个流水线导致VM被提前关闭的问题,以下是几种可行的解决方法:
1. 使用GitLab原生的流水线级并发控制
GitLab的workflow块支持全局控制流水线的并发数,这和作业级的concurrency不同,它能限制整个项目的流水线同时只运行一个,其余自动排队。
在你的.gitlab-ci.yml开头添加如下配置:
workflow: concurrency: group: "${CI_PROJECT_PATH}" # 用项目路径作为并发组,确保同一项目的流水线互斥 cancel-in-progress: false # 设为false表示不取消正在运行的流水线,新流水线进入队列等待
这个方案是官方原生支持的,无需额外脚本,配置简单,是最推荐的方法。
2. 限制私有Runner的并发数为1
如果这台私有Runner仅为当前项目服务,可以直接修改Runner的配置文件config.toml,将全局并发数设为1:
concurrent = 1 # 该Runner一次只能处理一个作业,自然不会同时运行多个流水线
修改后重启GitLab Runner服务即可。这种方法适合Runner专属当前项目的场景,不用改动CI配置。
3. 自定义流水线锁机制
如果需要更灵活的控制(比如跨项目共享锁),可以通过GitLab API和变量实现自定义锁:
步骤:
- 在项目中创建一个项目访问令牌,授予
api权限,将令牌存为CI/CD变量(比如GITLAB_TOKEN)。 - 在
vm-start阶段添加锁检查逻辑,获取到锁后再启动VM;在vm-stop阶段释放锁。
示例CI配置:
vm-start: script: - | # 循环检查锁状态,直到获取到锁 while true; do # 调用API获取锁变量的值 LOCK_STATUS=$(curl --silent --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/variables/PIPELINE_LOCK" | jq -r '.value') # 如果锁未被占用,设置为锁定状态 if [ "$LOCK_STATUS" != "locked" ]; then curl --silent --request PUT --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" --data "value=locked" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/variables/PIPELINE_LOCK" break fi echo "已有流水线在运行,等待30秒后重试..." sleep 30 done # 这里添加启动Azure VM的命令 after_script: # 如果作业失败,自动释放锁,避免死锁 - | if [ "$CI_JOB_STATUS" == "failed" ]; then curl --silent --request PUT --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" --data "value=unlocked" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/variables/PIPELINE_LOCK" fi vm-stop: script: # 这里添加停止Azure VM的命令 after_script: # 无论作业成功或失败,都释放锁 - curl --silent --request PUT --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" --data "value=unlocked" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/variables/PIPELINE_LOCK"
注意:需要在项目的CI/CD变量中预先创建PIPELINE_LOCK变量,初始值设为unlocked。
内容的提问来源于stack exchange,提问作者HelmBurger
相关产品推荐
相关产品推荐

