看起来你是在 DOOD(Docker-out-of-Docker) 场景下用 docker executor 跑 GitLab Runner:job 容器里用 docker 命令去起“兄弟容器”。此时兄弟容器的 volume 路径是由宿主机 Docker 守护进程解释的,而不是 job 容器里的路径——所以你在 job 容器内的“当前代码根目录”($CI_PROJECT_DIR 或 $(pwd))对宿主机来说并不存在,导致“访问不到代码根目录/挂载失败”。

下面给两种可行解法,任选其一。


方案 A:继续 DOOD,但把构建目录绑定为宿主机可见路径(推荐最省改动)

思路:把 Runner 的构建目录($CI_PROJECT_DIR 的上层)在 job 容器和宿主机上保持同一路径,这样当你在 job 容器里做 docker run -v /builds/...:/app 时,宿主机 Docker 也能找到这个路径。

  1. 修改 Runner 的 config.toml(docker executor 那段):
[[runners]]
  [runners.docker]
    # 关键:把宿主机 /builds 绑定进 job 容器的 /builds
    volumes = [
      "/var/run/docker.sock:/var/run/docker.sock",
      "/cache",
      "/builds:/builds"
    ]
    # 可选:确保构建目录就落在 /builds 下
    privileged = false        # DOOD 场景一般无需 privileged(按需开启)
    disable_cache = false

  # 全局设置构建目录(可选但强烈建议)
  builds_dir = "/builds"
  cache_dir  = "/cache"
  1. 确认 job 内 $CI_PROJECT_DIR 形如:
/builds/<group>/<project>  或  /builds/<concurrent-id>/<group>/<project>
  1. 在 .gitlab-ci.yml 中,运行兄弟容器或 docker build 时用这个绝对路径:
build:
  image: docker:25     # 例
  services: []         # DOOD 不需要 dind 服务
  variables:
    DOCKER_HOST: unix:///var/run/docker.sock
  script:
    - echo "$CI_PROJECT_DIR"
    - docker version
    # 兄弟容器挂载代码(宿主机会识别 /builds/... 这个真实路径)
    - docker run --rm -v "$CI_PROJECT_DIR":/app -w /app alpine:3.20 ls -la
    # 或直接构建镜像(以项目根为上下文)
    - docker build -t myapp:ci "$CI_PROJECT_DIR"

常见坑

  • 不要用 -v $(pwd):/app(这是 job 容器内路径,宿主机不认识);用 $CI_PROJECT_DIR 的绝对路径。
  • builds_dir 必须和 volumes 中的映射一致(上例都用 /builds)。
  • 如果你的 Runner 运行在 Docker 里(“docker-in-docker-executor”),也要确保外层宿主机的 /builds 目录存在并授予读写。

方案 B:改为 DinD(Docker-in-Docker)模式

思路:不再用宿主机 Docker 守护进程,而是起 docker:dind 服务,job 内的 docker CLI 连接到容器内的守护进程。这时挂载/构建上下文都发生在 job 容器网络里,$CI_PROJECT_DIR 就是本地路径,直接可见。

build:
  image: docker:25
  services:
    - name: docker:25-dind
      command: ["--mtu=1450"]  # 例:按环境调整
  variables:
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""     # 关闭 TLS 简化
  script:
    - docker version
    - docker build -t myapp:ci .
    - docker run --rm myapp:ci echo "ok"

常见坑

  • DinD 需要给 docker:...-dind 服务更高的磁盘与缓存;镜像缓存不会和宿主机共享。
  • 网络或镜像拉取慢时注意启用 registry mirror、合理的 MTU。

快速自检清单

  • Runner config.toml 的 volumes 是否包含 /builds:/builds 与 /var/run/docker.sock:/var/run/docker.sock(走 DOOD 时需要)
  • builds_dir 是否设置为 /builds(或与 volumes 对应的一致路径)
  • CI 脚本里是否使用 绝对路径 $CI_PROJECT_DIR 给 docker run -v / docker build
  • 若改用 DinD:是否设置了 DOCKER_HOST=tcp://docker:2375 且起了 docker:dind 服务

更多推荐