GitLab Docker-in-Docker CI/CD场景下如何正确透传卷挂载
问题根因
挂载失效的核心原因是Docker套接字挂载后的路径上下文错位:
- 把宿主机
/var/run/docker.sock挂载进CI作业容器后,容器内执行的所有docker/docker-compose命令,实际是直接调用宿主机上的Docker daemon,而非作业容器内部的Docker进程 - 此时docker-compose解析相对路径挂载(比如
./user_conf.d:/etc/nginx/user_conf.d)时,基准路径是宿主机Docker daemon的运行上下文,不是CI作业拉取代码所在的容器内路径 - 宿主机对应路径下根本不存在
user_conf.d/app.conf文件,Docker会自动创建空目录挂载进nginx容器,就出现了目录为空的现象
解决方案
推荐优先使用第一种方案,性能更高配置更简单。
方案1:直接复用宿主机Docker(推荐)
不需要嵌套运行Docker(dind),通过路径映射让宿主机Docker能访问到Runner拉取的代码:
- 修改GitLab Runner配置文件
/etc/gitlab-runner/config.toml,把Runner的默认构建目录映射到宿主机同路径:
executor = "docker" [runners.docker] image = "alpine" volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache", "/builds:/builds"]
- 修改
.gitlab-ci.yml,移除不必要的dind服务,使用CI内置的绝对路径变量指定compose工作目录:
image: docker/compose:latest stages: - deploy deploy: stage: deploy only: - production script: - cd $CI_PROJECT_DIR - docker image prune -f - docker-compose build --no-cache - docker-compose up -d
配置完成后,Runner容器内的/builds目录(CI拉取代码的默认根目录)会和宿主机的/builds目录实时同步,宿主机Docker解析./user_conf.d时就能找到实际的代码文件,挂载正常生效。
方案2:使用Docker-in-Docker(dind)隔离模式
如果需要Docker环境和宿主机完全隔离,可以调整dind配置实现目录共享:
- 修改GitLab Runner配置文件
/etc/gitlab-runner/config.toml,开启特权模式(dind运行必需):
executor = "docker" [runners.docker] image = "alpine" privileged = true volumes = ["/cache"]
- 修改
.gitlab-ci.yml,把CI作业的代码目录挂载到dind服务容器内,同时指定Docker连接地址:
image: docker/compose:latest services: - name: docker:dind volumes: - $CI_PROJECT_DIR:$CI_PROJECT_DIR stages: - deploy deploy: stage: deploy only: - production variables: DOCKER_HOST: tcp://docker:2376 DOCKER_TLS_CERTDIR: "/certs" script: - cd $CI_PROJECT_DIR - docker image prune -f - docker-compose build --no-cache - docker-compose up -d
注意事项
- 方案1直接复用宿主机Docker,没有嵌套虚拟化开销,性能更好,但CI作业可以直接操作宿主机上的所有Docker容器,仅适合内部可信项目使用
- 方案2的Docker环境和宿主机完全隔离,安全性更高,但需要开启特权模式,嵌套虚拟化会带来10%~20%左右的性能损耗
内容的提问来源于stack exchange,提问作者petRUShka
相关产品推荐
相关产品推荐

