I am running Docker in Docker (specifically to run Jenkins which then runs Docker builder containers to build a project images and then runs these and then the test containers).
This is how the jenkins image is built and started:
docker build --tag bb/ci-jenkins .
mkdir $PWD/volumes/
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 \
--name ci-jenkins bb/ci-jenkins
Jenkins works fine. But then there is a Jenkinsfile
based job, which runs this:
docker run -i --rm -v /var/jenkins_home/workspace/forkMV_jenkins-VOLTRON-3057-KQXKVJNXOU4DGSUG3P27IR3QEDHJ6K7HPDEZYN7W6HCOTCH3QO3Q:/tmp/build collab/collab-services-api-mvn-builder:2a074614 mvn -B -T 2C install
And this ends up with an error:
The goal you specified requires a project to execute but there is no POM in this directory (/tmp/build).
When I do docker exec -it sh
to the container, the /tmp/build
is empty. But when I am in the Jenkins container, the path /var/jenkins_home/...QO3Q/
exists and it contains the workspace with all the files checked out and prepared.
So I wonder - how can Docker happily mount the volume and then it's empty?*
What's even more confusing, this setup works for my colleague on Mac. I am on Linux, Ubuntu 17.10, Docker latest.
A better approach is to use Jenkins Docker plugin and let it do all the mountings for you and just add
-v /var/run/docker.sock:/var/run/docker.sock
in itsinside
function arguments.E.g.
Alternative Solution with Docker cp
I was facing the same problem of mounting volumes from a Build that runs in a Docker Container running in a Jenkins server in Kubernetes. As we use
docker-in-docker
,dind
, I couldn't mount the volume in either ways proposed here. I'm still not sure what the reason is, but I found an alternative way: usedocker cp
to copy the build artifacts.Multi-stage Docker Image for Tests
I'm using the following Dockerfile stage for Unit + Integration tests.
Jenkins Pipeline For tests
docker cp
to copy the build artifacts from inside the test docker container that can be started after running the tests in a named container.Post
stageAt this point, I solved the problem with a
docker run --name test:SHA
and then I usedocker start test:SHA
and thendocker cp test:SHA:/path .
, where.
is the current workspace directory, which is similar to what we need with a docker volume mounted to the current directory.After some research, calming down and thinking, I realized that Docker-in-Docker is not really so much "-in-", as it is rather "Docker-next-to-Docker".
The trick to make a container able to run another container is sharing
/var/run/docker.sock
through a volume:-v /var/run/docker.sock:/var/run/docker.sock
And then the
docker
client in the container actually calls Docker on the host.The volume source path (left of
:
) does not refer to the middle container, but to the host filesystem!After realizing that, the fix is to make the paths to the Jenkins
workspace
directory the same in the host filesystem and the Jenkins (middle) container:And voilá! It works. (I created a symlink instead of moving it, seems to work too.)
It is a bit complicated if you're looking at colleague's Mac, because Docker is implemented a bit differently there - it is running in an Alpine Linux based VM but pretending not to. (Not 100 % sure about that.) On Windows, I read that the paths have another layer of abstraction - mapping from
C:/somewhere/...
to a Linux-like path.I hope I'll save someone hours of figuring out :)