我如何在 gitlab-ci 中同时运行循环?
Posted
技术标签:
【中文标题】我如何在 gitlab-ci 中同时运行循环?【英文标题】:how do i run loops simultaneously in gitlab-ci? 【发布时间】:2022-01-08 12:06:27 【问题描述】:我的 gitlab-ci 中有以下脚本,并且希望同时运行循环,有人知道这样做的好方法吗?让它们同时运行
注意该作业是一项手动作业,我正在寻找单击一个按钮以循环遍历 bash 脚本中的所有包,如下所示
when: manual
script:
- |-
for PACKAGE in name1 name2; do
export IMAGE="$CI_REGISTRY/$GITLAB_REPO/$PACKAGE:$BUILD_TAG"
docker build -t $IMAGE -f $PACKAGE/Dockerfile .
docker push $IMAGE
done
目前它首先为name1
运行,然后在完成之后运行name2
。由于没有依赖关系,我希望同时运行两者
这是我从 SO => (https://unix.stackexchange.com/a/216475/138406) 上的答案中尝试的结果
when: manual
script:
- |-
task()
export IMAGE="$CI_REGISTRY/$GITLAB_REPO/$1:$BUILD_TAG"
docker build -t $IMAGE -f $1/Dockerfile .
docker push $IMAGE
for PACKAGE in name1 name2; do
task "$PACKAGE" &
done
这适用于常规 bash 脚本,但是当我将它与 gitlab-ci 一起使用时,它没有按预期运行,甚至没有运行任何命令,只是立即成功完成工作
有谁愿意帮助解决问题所在以及如何解决这个问题?
【问题讨论】:
研究“如何在 bash 中同时运行...”,你会得到相同的答案。 如果你知道答案,可以在下面发布答案吗? 【参考方案1】:为了实现您的用例,我建议您“并行化”构建使用多个专用 GitLab-CI 作业,而不是使用多个 bash 作业单个 GitLab-CI 作业。
概念验证:
stages:
- push
.push-template:
stage: push
image: docker:latest
services:
- docker:dind
variables:
IMAGE: "$CI_REGISTRY/$GITLAB_REPO/$PACKAGE:$BUILD_TAG"
# where $PACKAGE should be provided by the child jobs...
before_script: |
if [ -z "$PACKAGE" ]; then
echo 'Error: variable PACKAGE is undefined' >&2
false
fi
# just for completeness, this may be required:
echo "$CI_JOB_TOKEN" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
script:
- docker build -t "$IMAGE" -f "$PACKAGE/Dockerfile" .
- docker push "$IMAGE"
- docker logout "$CI_REGISTRY" || true
push-name1:
extends: .push-template
variables:
PACKAGE: name1
push-name2:
extends: .push-template
variables:
PACKAGE: name2
有关extends
关键字的详细信息,请参阅.gitlab-ci.yml reference manual。
【讨论】:
这种方法的问题是我失去了单击一个按钮来运行该作业,现在这将是 2 个作业..这是一项手动作业,仅供参考...所以如果可以在 bash 中完成,这就是我所追求的 好的,您能否更具体地说明您的约束并在您的问题中添加详细信息?顺便说一句,我绝对相信在 bash 中不可能做到这一点,因为例如你可能在 gitlab.com 上有$(nproc) = 1
,如果你明白我的意思……而 GitLab CI 将通过使用多个作业让你拥有更大的并行度。
when: manual
是唯一的约束..这是自托管的 gitlab ......所以不是 gitlab.com
好的,但您不能将多个工作标记为when: manual
吗?这样,您将在您认为合适的时候运行这几个作业。 (在doc 中,我没有看到任何阻止从事多项体力工作的因素)。
但也许您对拥有多个手动作业感兴趣,并且能够通过仅在按钮上单击一次 来运行这些 n 个作业? (不在 n 按钮上)【参考方案2】:
马上就成功了
这就是在后台运行的意思——这意味着主进程将立即继续。您必须等待后台进程完成。
- |-
task()
export IMAGE="$CI_REGISTRY/$GITLAB_REPO/$1:$BUILD_TAG"
docker build -t $IMAGE -f $1/Dockerfile .
docker push $IMAGE
for PACKAGE in name1 name2; do
task "$PACKAGE" &
done
wait
但这不会捕获任何错误,这将导致问题未被发现。您将不得不收集 pid 并单独等待:
...
childs=""
for package in name1 name2; do
task "$package" &
childs="$childs $!"
done
for pid in $childs; do
if ! wait "$pid"; then
echo "Process with pid=$pid failed"
kill $childs
wait
exit 1
fi
done
但无论如何,这很麻烦,而且是在重新发明***。安装 GNU xargs
(或者更好的 parallel
)并确保你的 docker 容器有 bash shell。然后,只需导出函数并使用 xargs 在子进程中运行它:
...
export -f task
printf "%s\n" name1 name2 | xargs -P0 -d '\n' bash -xeuo pipefail -c 'func "$@"' --
您可能想研究https://man7.org/linux/man-pages/man1/xargs.1.html 甚至https://www.gnu.org/software/bash/manual/html_node/Job-Control-Basics.html。
当然,不要在 .gitlab-ci yaml 文件中编写长脚本 - 将其全部移至专用脚本文件,以便您可以在本地测试运行。用 shellcheck 检查你的脚本。无论如何 - 使用docker-compose
也可能更简单。
无论如何,这都很奇怪,当然无论如何我都不会那样做。 Gitlab-runner 已经是为您提供并行化的工具 - 它在同一阶段并行运行多个作业。只需运行两个任务。
.todo:
script:
export IMAGE="$CI_REGISTRY/$GITLAB_REPO/$CI_JOB_NAME:$BUILD_TAG"
docker build -t $IMAGE -f $CI_JOB_NAME/Dockerfile .
docker push $IMAGE
name1:
extends: .todo
name2:
extends: .todo
这种方法将为您的管道提供关于哪些特定任务失败的可见指示,因此您无需滚动查看两个并行运行的进程的不可读日志。一份工作,一项任务。
【讨论】:
+1 以获得这个全面的答案(另请参阅mine 以查看更多关于 GitLab-CI 多作业解决方案的“样板”:) - BTW @KamilCuk 似乎有错字? ($$CI_JOB_NAME
→ $CI_JOB_NAME
)以上是关于我如何在 gitlab-ci 中同时运行循环?的主要内容,如果未能解决你的问题,请参考以下文章
Gitlab-ci:如果 MR 存在则触发 merge_request 分离管道,如果不存在则触发源分支管道。这两条管道不应同时运行
gitlab-ci.yaml:在多行 python docker 镜像中运行 python