当前位置: 首页 > 科技观察

Gitlab动态子流水线实践

时间:2023-03-12 04:42:46 科技观察

Gitlab动态子流水线Gitlab的多项目流水线支持一个项目的流水线触发另一个项目的流水线,并且可以将整个流水线以及流水线之间的相互依赖可视化在一个里面,解决协同项目之间的问题。Gitlab从12.7版本开始引入了父子管道特性,在12.9版本引入了动态子管道特性。子流水线可以按照阶段顺序自由执行,无需等待父流水线的无关工作,将配置拆分成更小的块,减少理解整体配置的认知负担,并且由于导入是在子流水线中完成,命名空间也减少了冲突的可能性,界面体验也得到了提升。Gitlab子流水线项目后台项目组有一个Gitlab项目专门用于生成自定义容器镜像。项目下有很多目录。每个目录对应一个自定义图像。目录下有Dockerfile和相关文件。名为buildXXX.sh的脚本构建和上传图像。为了有一个权威的、稳定的、方便的地方来构建这些镜像,我想到了利用Gitlab动态子管道的特性,搜索项目中的所有镜像来构建shell脚本文件,并提取镜像名称和标签在脚本中。然后生成以每个镜像名称和标签命名的动态步骤,最后由人员手动触发镜像的构建。这可能不是一个很好的解决方案,比如会产生很多不必要的工作,没有完全自动化,缺少对图像之间依赖关系的处理等等,但也是一种思路,这些问题也是可以解决的通过进一步分析Dockerfile之间的关系,对本次改动涉及的文件等进行优化解决。下面两张图就是最终的效果。管道作业列表的整体结构。父流水线与Gitlab官网提供的案例相同。它由两个作业(名称可以自定义)generate-config和child-pipeline组成。之前的名为generate-config的job会生成一个名为generated-config的job.ymlGitlabpipeline定义文件,其中包含需要动态运行的job,通过artifacts机制传递给后续名为child-pipeline的job,以及触发它。为了清晰起见,以下代码中暂时省略了generated-config.yml文件shell脚本,稍后补上。stages:-prepare-imagegenerate-config:stage:preparescript:-generated-config.yml将在这里生成,暂时忽略工件:paths:-generated-config.ymlchild-pipeline:stage:imagetrigger:include:-artifact:generated-config.ymljob:generate-configtemplate由于每个动态生成的job的定义都是一样的,所以在generated-config.yml中使用Gitlabpipeline模板机制定义了一个Job模板,以复用和精简代码。以下代码片段来自generated-config.yml文件的第一部分。我们可以看到定义了一个名为build_image的模板。模板定义的作业将被手动触发并使用docker和oc命令启动镜像以运行构建脚本。在构建脚本中,先给脚本赋予执行权限,然后进入脚本所在目录,最后运行脚本。具体脚本文件将由每个特定作业中的SCRIPT_PATH变量提供。例如,从第11行开始名为redis-cluster:5.0.7-ocp的作业引入了build_image模板并提供了SCRIPT_PATH变量的值。.job_template:&build_imagestage:buildwhen:manualimage:nexus.yourcompany.com/tools/docker-18.09.7/oc:4.6.21script:-chmod+x${SCRIPT_PATH}-cd${SCRIPT_PATH%/*}-/bin/sh./${SCRIPT_PATH##*/}redis-cluster:5.0.7-ocp:变量:SCRIPT_PATH:/tmp/TBzsZA42/0/docker-images/redis-cluster/build-openshift.sh<<:*build_image生成配置在生成动态子流水线的脚本中,首先生成模板部分,创建并输出到文件中。generate-config:stage:preparescript:-|-echo-e".job_template:&build_imagestage:buildwhen:manualimage:nexus.yourcompany.com/tools/docker-18.09.7/oc:4.6.21脚本:-chmod+x\${SCRIPT_PATH}-cd\${SCRIPT_PATH%/*}-/bin/sh./\${SCRIPT_PATH##*/}">添加generated-config.yml生成各个Job,依次查找build*.sh文件,搜索dockerpush提取镜像名称和Tag,用tab分成两列,遍历每一行读取文件和镜像遍历,使用echo命令追加到文件中环形。generate-config:stage:preparescript:-生成模板的脚本-|-find-iname'build*.sh'\|xargsgrep-ios".*docker\s*push\s*.*/[^/\\\$]*"\|sed's|\.sh:|.sh\t|g'\|sed-e's|\([^\t]*\)\t.*\/\([^\/]*\)|\1\t\2|g'\|在读取文件图像时;做SCRIPT_PATH="$CI_PROJECT_DIR${file:1}";\echo-e"$image:variables:SCRIPT_PATH:"${SCRIPT_PATH}"<<:*build_image"\>>generated-config.yml;\done下面是生成的generated-config.yml片段。.job_template:&build_imagestage:buildwhen:manualimage:nexus.yourcompany.com/tools/docker-18.09.7/oc:4.6.21script:-chmod+x${SCRIPT_PATH}-cd${SCRIPT_PATH%/*}-/bin/sh./${SCRIPT_PATH##*/}redis-cluster:5.0.7-ocp:变量:SCRIPT_PATH:/tmp/TBzsZA42/0/docker-images/redis-cluster/build-openshift.sh<<:*build_imageredis-cluster:5.0.7:variables:SCRIPT_PATH:/tmp/TBzsZA42/0/docker-images/redis-cluster/build.sh<<:*build_image完整定义以下是完整的项目流水线定义:阶段:-准备-imagegenerate-config:阶段:准备脚本:-|-echo-e“.job_template:&build_image阶段:构建时间:手动图像:nexus.yourcompany.com/tools/docker-18.09.7/oc:4.6.21脚本:-chmod+x\${SCRIPT_PATH}-cd\${SCRIPT_PATH%/*}-/bin/sh./\${SCRIPT_PATH##*/}">generated-config.yml-|-find-iname'build*.sh'\|xargsgrep-ios".*docker\s*push\s*.*/[^/\\\$]*"\|sed's|\.sh:|.sh\t|g'\|sed-e's|\([^\t]*\)\t.*\/\([^\/]*\)|\1\t\2|g'\|在读取文件图像时;做SCRIPT_PATH="$CI_PROJECT_DIR${file:1}";\echo-e"$image:variables:SCRIPT_PATH:"${SCRIPT_PATH}"<<:*build_image"\>>generated-config.yml;\doneartifacts:paths:-generated-config.ymlchild-pipeline:stage:imagetrigger:include:-artifact:generated-config.yml作业:generate-config