GitLab模板兼容改造:单模板触发构建与扫描多作业方案咨询
解决方案:GitLab CI模板兼容扩展镜像扫描功能
问题背景
现有一个供用户通过extend关键字复用的GitLab作业模板.build_kaniko,需在完全保持向后兼容性的前提下为其添加镜像扫描功能。部分用户会多次扩展该模板构建多镜像,核心需求:
- 模板名称不变,用户无需修改现有引用逻辑
- 每次扩展模板时,自动生成对应构建作业和依赖该构建的扫描作业,流水线结构示例:
. (stages) ├── build │ ├── build_container(用户自定义作业) │ └── scan_build_container(自动生成,依赖build_container) ├── deploy │ ├── deploy_container(用户自定义作业) │ └── scan_deploy_container(自动生成,依赖deploy_container) └── ...其他阶段
尝试trigger关键字无法实现需求,因其仅支持触发单个作业。
用户现有使用模板的场景示例:
单镜像构建/部署场景
include: - project : 'ci-tools/container-image-ci-templates' file : 'kaniko-image.gitlab-ci.yml' ref: master stages: - build - deploy build_container: rules: - if: $CI_COMMIT_BRANCH stage: build extends: .build_kaniko variables: REGISTRY_IMAGE_PATH : "registry.foo.bar/MYPROJECT/MYIMAGE:$CI_COMMIT_SHORT_SHA" CONTEXT_DIR: "dockerfiles_folder" DOCKER_FILE_NAME: "Dockerfile_ubuntu" deploy_container: rules: - if: $CI_COMMIT_TAG stage: deploy extends: .build_kaniko variables: PUSH_IMAGE: "true" REGISTRY_IMAGE_PATH : "registry.foo.bar/MYPROJECT/MYIMAGE:$CI_COMMIT_TAG" CONTEXT_DIR: "dockerfiles_folder" DOCKER_FILE_NAME: "Dockerfile_ubuntu"
多镜像构建场景
... build_container_container1: rules: - if: $CI_COMMIT_BRANCH stage: build extends: .build_kaniko variables: REGISTRY_IMAGE_PATH : "registry.foo.bar/MYPROJECT/MYIMAGE:$CI_COMMIT_SHORT_SHA" CONTEXT_DIR: "dockerfiles_folder" DOCKER_FILE_NAME: "Dockerfile_ubuntu_1" build_container_container2: rules: - if: $CI_COMMIT_BRANCH stage: build extends: .build_kaniko variables: REGISTRY_IMAGE_PATH : "registry.foo.bar/MYPROJECT/MYIMAGE:$CI_COMMIT_SHORT_SHA" CONTEXT_DIR: "dockerfiles_folder" DOCKER_FILE_NAME: "Dockerfile_fedora" ...
实现方案
推荐方案(GitLab 15.0+):动态作业生成
利用GitLab CI的generate关键字(15.0及以上支持),在原模板中自动生成扫描作业,完全保持用户现有使用方式不变。
模板文件kaniko-image.gitlab-ci.yml内容
# 自动合并扫描阶段到用户流水线 stages: - build - scan - deploy # 基础构建逻辑模板(保留原构建逻辑) .build_kaniko_base: image: gcr.io/kaniko-project/executor:v1.9.0-debug script: - # 生成Docker认证配置 - echo "{\"auths\":{\"$(echo $REGISTRY_IMAGE_PATH | cut -d/ -f1)\":{\"auth\":\"$(echo -n "$REGISTRY_USER:$REGISTRY_PASS" | base64)\"}}}" > /kaniko/.docker/config.json - # 执行Kaniko构建 - /kaniko/executor --context "${CI_PROJECT_DIR}/${CONTEXT_DIR}" --dockerfile "${CI_PROJECT_DIR}/${CONTEXT_DIR}/${DOCKER_FILE_NAME}" --destination "${REGISTRY_IMAGE_PATH}" $( [ "${PUSH_IMAGE}" = "true" ] && echo "--push" ) # 基础扫描逻辑模板(可替换为实际使用的扫描工具) .scan_kaniko_base: image: aquasec/trivy:0.44.0 script: - trivy image --severity HIGH,CRITICAL --exit-code 1 "${REGISTRY_IMAGE_PATH}" rules: - if: $SKIP_SCAN != "true" # 提供跳过扫描的兼容开关 stage: scan # 原模板名称不变,用户直接extends即可 .build_kaniko: extends: .build_kaniko_base generate: # 动态生成扫描作业,作业名为scan_<当前构建作业名> scan_${CI_JOB_NAME}: extends: .scan_kaniko_base variables: REGISTRY_IMAGE_PATH: "${REGISTRY_IMAGE_PATH}" needs: ["${CI_JOB_NAME}"] # 扫描作业依赖对应构建作业
效果说明
- 用户无需修改任何现有代码,继续使用
extends: .build_kaniko - 每个构建/部署作业会自动生成对应扫描作业,例如
build_container对应scan_build_container - 扫描作业在
scan阶段执行,仅在对应构建作业成功后触发 - 通过设置
SKIP_SCAN=true变量可临时跳过扫描,保持向后兼容
兼容方案(GitLab <15.0):子流水线触发
针对不支持generate关键字的旧版本GitLab,使用子流水线实现扫描作业的自动生成。
模板文件kaniko-image.gitlab-ci.yml内容
# 自动合并扫描阶段到用户流水线 stages: - build - scan - deploy # 基础构建逻辑模板 .build_kaniko_base: image: gcr.io/kaniko-project/executor:v1.9.0-debug script: - # 执行原构建逻辑 - echo "{\"auths\":{\"$(echo $REGISTRY_IMAGE_PATH | cut -d/ -f1)\":{\"auth\":\"$(echo -n "$REGISTRY_USER:$REGISTRY_PASS" | base64)\"}}}" > /kaniko/.docker/config.json - /kaniko/executor --context "${CI_PROJECT_DIR}/${CONTEXT_DIR}" --dockerfile "${CI_PROJECT_DIR}/${CONTEXT_DIR}/${DOCKER_FILE_NAME}" --destination "${REGISTRY_IMAGE_PATH}" $( [ "${PUSH_IMAGE}" = "true" ] && echo "--push" ) - # 生成扫描作业配置文件 - | cat > scan_job.yml << EOF scan_${CI_JOB_NAME}: image: aquasec/trivy:0.44.0 stage: scan script: - trivy image --severity HIGH,CRITICAL --exit-code 1 "${REGISTRY_IMAGE_PATH}" rules: - if: \$SKIP_SCAN != "true" needs: ["${CI_JOB_NAME}"] EOF - # 触发子流水线执行扫描 - curl --request POST --form "token=${CI_JOB_TOKEN}" --form "ref=${CI_COMMIT_REF_NAME}" --form "yaml_file=@scan_job.yml" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/trigger/pipeline" after_script: - rm -f scan_job.yml # 原模板名称不变 .build_kaniko: extends: .build_kaniko_base
注意事项
- 需确保
CI_JOB_TOKEN具备触发流水线的权限,可在项目设置中调整权限配置 - 扫描工具可替换为Clair、Anchore等,只需修改扫描作业的
image和script内容
内容的提问来源于stack exchange,提问作者Diogo Guerra
相关产品推荐
相关产品推荐

