如何在GitLab CI指定作业中不使用Docker?解决连接报错
使用GitLab共享运行器,基于Alpine镜像管理Terraform和Ansible云仓库。第一阶段用docker:dind构建镜像正常,但后续阶段使用构建好的镜像时,明明不需要调用Docker,却仍报错:
ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
提供的简化版.gitlab-ci.yml如下:
stages: - image - validate image-job: stage: image image: docker:dind variables: IMAGE_TAG: {{ sanitized_value }} script: - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY - docker build -t $IMAGE_TAG ci-support - docker push $IMAGE_TAG validate-job: stage: validate image: $IMAGE_TAG environment: production interacts_with_docker: false # <-- 尝试过的配置 script: - terraform plan - ansible-playbook --check some-playbook.yaml
接受的替代方案:配置docker-cli(无需完整守护进程),从镜像作业的Docker服务获取信息让作业继续。
排查镜像内部自动执行脚本
报错核心原因是$IMAGE_TAG镜像可能包含自动调用docker命令的启动脚本(比如ENTRYPOINT或CMD),即便作业脚本没写docker info,镜像启动时也会自动执行相关命令,导致连接Docker守护进程失败。
解决步骤:
- 检查
ci-support/Dockerfile中的ENTRYPOINT或CMD指令,确认是否存在自动运行Docker相关命令的配置。 - 若存在,要么删除这些自动执行的Docker命令,要么在CI作业中覆盖entrypoint:
在validate-job中添加:
此配置会跳过镜像默认的entrypoint,直接执行你定义的脚本。entrypoint: [""]
禁用GitLab CI的Docker服务注入
即便设置了interacts_with_docker: false,GitLab共享运行器仍可能尝试挂载Docker套接字或注入相关环境变量。可通过显式禁用相关变量避免:
在validate-job的variables中添加:
variables: DOCKER_HOST: "" DOCKER_TLS_CERTDIR: ""
清空Docker相关环境变量后,镜像内的脚本就不会尝试连接不存在的Docker守护进程。
替代方案:仅配置docker-cli无守护进程
如果镜像确实需要docker-cli(比如部分Ansible模块依赖),但不需要运行守护进程,可在构建镜像时仅安装docker-cli:
修改ci-support/Dockerfile:
# 基于Alpine镜像 FROM alpine:latest # 仅安装docker-cli、terraform和ansible,不安装Docker守护进程 RUN apk add --no-cache docker-cli terraform ansible # 移除自动启动Docker的entrypoint/cmd ENTRYPOINT [] CMD []
这样镜像内仅包含docker-cli,无守护进程,也不会自动执行Docker命令。若需在作业中获取Docker服务信息,由于不同阶段的GitLab运行器不会复用同一Docker服务,更稳妥的方式是直接避免在validate阶段调用任何Docker命令。
内容的提问来源于stack exchange,提问作者Nicole O'Connor

