如何在GitLab CI中用Kaniko推送镜像前执行容器扫描且不使用制品?
解决方案
问题1:推送前漏洞扫描的替代方案(无制品存储)
存在成熟的最佳实践,核心是让Kaniko构建镜像后先导出为本地镜像文件,直接在CI流水线内完成扫描,确认无高危漏洞后再推送。具体流程:
- Kaniko构建并导出镜像为tar包:使用Kaniko的
--tarPath参数,将构建好的镜像导出为tar文件到CI节点的共享存储路径(不存入GitLab制品库),同时加上--no-push参数避免提前推送。 - 加载tar包为本地镜像:扫描任务中用
docker load命令将tar包加载为本地可识别的镜像。 - GitLab容器扫描本地镜像:配置GitLab容器扫描作业,通过环境变量指定本地镜像的标签,直接扫描本地镜像而非远程仓库镜像。
- 条件触发推送:只有扫描结果无高危漏洞时,再调用Kaniko将镜像推送到目标仓库。
问题2:构建与扫描任务共用存储的配置
完全可以实现,无需依赖制品存储,主要有两种可行方式:
方式1:绑定同一Runner的本地共享目录
- 给构建、扫描、推送三个Job指定相同的
tags,确保它们运行在同一个GitLab Runner节点上。 - 在该Runner的配置文件中,挂载一个本地目录(如
/tmp/ci-shared)到Job容器内的固定路径(如/shared)。 - 构建Job将镜像tar包导出到
/shared/${CI_COMMIT_SHA}.tar,扫描Job直接从该路径加载镜像,推送Job则基于源代码重新构建(或复用tar包推送,需额外配置)。
示例CI配置片段:
stages: - build - scan - push build-image: stage: build tags: - shared-storage-runner script: - | /kaniko/executor \ --context "${CI_PROJECT_DIR}" \ --dockerfile "${CI_PROJECT_DIR}/Dockerfile" \ --tarPath "/shared/${CI_COMMIT_SHA}.tar" \ --no-push scan-image: stage: scan tags: - shared-storage-runner image: docker:latest services: - docker:dind script: - docker load -i "/shared/${CI_COMMIT_SHA}.tar" - docker tag $(docker images -q | head -1) ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA} # 配置扫描环境变量,指向本地镜像 - export CI_APPLICATION_REPOSITORY=${CI_REGISTRY_IMAGE} - export CI_APPLICATION_TAG=${CI_COMMIT_SHA} - run-container-scanning rules: - if: $CI_COMMIT_BRANCH when: on_success push-image: stage: push tags: - shared-storage-runner script: - | /kaniko/executor \ --context "${CI_PROJECT_DIR}" \ --dockerfile "${CI_PROJECT_DIR}/Dockerfile" \ --destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}" \ --destination "${CI_REGISTRY_IMAGE}:latest" rules: - if: $CI_COMMIT_BRANCH when: on_success
方式2:利用GitLab CI临时缓存(适合小型镜像)
- 构建Job将镜像tar包存入GitLab CI的
cache(缓存仅用于流水线内临时共享,不进入制品库),设置policy: push。 - 扫描Job通过
policy: pull从缓存中提取tar包,完成扫描。 - 此方式无需绑定特定Runner,但缓存有大小限制,仅适合体积较小的镜像。
示例缓存配置片段:
build-image: stage: build script: - | /kaniko/executor \ --context "${CI_PROJECT_DIR}" \ --dockerfile "${CI_PROJECT_DIR}/Dockerfile" \ --tarPath "${CI_PROJECT_DIR}/image.tar" \ --no-push cache: key: "${CI_COMMIT_SHA}" paths: - image.tar policy: push scan-image: stage: scan image: docker:latest services: - docker:dind script: - docker load -i image.tar # 扫描步骤同方式1 cache: key: "${CI_COMMIT_SHA}" paths: - image.tar policy: pull
关键注意事项
- Runner权限:使用Docker-in-Docker时,需确保Runner配置了足够的权限访问Docker daemon。
- 扫描环境变量:必须正确设置
CI_APPLICATION_REPOSITORY和CI_APPLICATION_TAG,让GitLab扫描工具识别本地镜像。 - 清理机制:流水线结束后,需通过脚本清理共享目录或缓存中的tar包,避免占用节点存储空间。
内容的提问来源于stack exchange,提问作者Eladik
相关产品推荐
相关产品推荐

