Docker-in-Docker卷挂载异常:一级容器有文件,二级容器为空
这个问题我之前在Linux环境下用Jenkins挂载宿主机docker.sock的场景里也碰到过,核心原因是你在Jenkins里执行的docker run命令,实际是由宿主机的Docker引擎来执行的,而非Jenkins容器内部的Docker,这就导致路径映射出现了错位——你挂载的是Jenkins容器内部的工作区路径,但宿主机上根本没有这个路径,所以容器自然得到了空目录。
1. 先搞清楚路径映射的本质
你启动Jenkins容器时,把宿主机的$PWD/volumes/jenkins_home挂载到了容器内的/var/jenkins_home。但当Jenkins里执行docker run -v /var/jenkins_home/workspace/...:/tmp/build时,这个命令是交给宿主机的Docker运行的,宿主机的Docker会去查找宿主机上的/var/jenkins_home/workspace/...路径,而不是Jenkins容器里的。显然这个路径在宿主机上不存在,Docker会自动创建一个空目录挂载进去,这就是/tmp/build为空的原因。
而你同事的Mac环境能正常运行,是因为Docker Desktop在Mac上基于虚拟机运行,它会自动把Mac宿主机的目录和虚拟机内的目录做映射,Jenkins容器里的路径在虚拟机里是存在的,所以挂载能正常生效。
2. 具体解决方案
有两种可靠的方式可以解决这个问题:
方式一:启动Jenkins时传入宿主机工作区根路径作为环境变量
修改Jenkins的启动命令,新增一个环境变量把宿主机上的Jenkins数据卷路径传给容器:
docker run -d --network=host \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /usr/bin/docker:/usr/bin/docker \ -v $PWD/volumes/jenkins_home:/var/jenkins_home \ -e JENKINS_HOST_HOME=$PWD/volumes/jenkins_home \ # 新增这行,传入宿主机路径 --name ci-jenkins bb/ci-jenkins
然后在你的Jenkinsfile里,用这个环境变量构建挂载路径:
sh 'docker run -i --rm -v ${env.JENKINS_HOST_HOME}/workspace/forkMV_jenkins-VOLTRON-3057-KQXKVJNXOU4DGSUG3P27IR3QEDHJ6K7HPDEZYN7W6HCOTCH3QO3Q:/tmp/build collab/collab-services-api-mvn-builder:2a074614 mvn -B -T 2C install'
这样宿主机的Docker就能找到正确的路径,挂载的目录就会有文件了。
方式二:在Jenkins容器内获取宿主机路径映射关系
如果你不想修改Jenkins启动命令,可以在Jenkins里通过docker inspect获取宿主机上的Jenkins数据卷路径:
def jenkinsHostHome = sh(script: 'docker inspect ci-jenkins | grep -oP "(?<=\\\"source\\\": \\\").*?(?=\\\"\\, \\\"destination\\\": \\\"/var/jenkins_home)"', returnStdout: true).trim() sh "docker run -i --rm -v ${jenkinsHostHome}/workspace/forkMV_jenkins-VOLTRON-3057-KQXKVJNXOU4DGSUG3P27IR3QEDHJ6K7HPDEZYN7W6HCOTCH3QO3Q:/tmp/build collab/collab-services-api-mvn-builder:2a074614 mvn -B -T 2C install"
不过这种方式依赖docker inspect的输出格式,稳定性稍差,优先推荐第一种方式。
3. 快速验证方法
你可以先在Jenkins容器里手动测试挂载是否正常:
- 进入Jenkins容器:
docker exec -it ci-jenkins bash - 执行测试挂载命令(替换成你宿主机的实际路径):
docker run -it --rm -v /path/to/your/host/volumes/jenkins_home/workspace/xxx:/tmp/build alpine ls /tmp/build
如果能看到文件,说明路径没问题,把这个路径替换到Jenkinsfile里即可。
内容的提问来源于stack exchange,提问作者Ondra Žižka

