Bamboo in Docker: Build Fails Due to a Missing Working Directory When Using Docker Runner
Platform notice: Server and Data Center only. This article only applies to Atlassian products on the Server and Data Center platforms.
Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.
*Except Fisheye and Crucible
Problem
Project sources are missing when a job is configured to run in a Docker container, and if Bamboo (agent) itself runs in a container and mounts /var/run/docker.sock.
Building a custom Bamboo server or agent images with docker cli installed, and running the image with -v /var/run/docker.sock:/var/run/docker.sock
is one of the ways to make Docker Runner available if Bamboo server (if local agent is used) or a remote agent runs in a container. This way, when Bamboo calls docker cli, it's the host Docker daemon that is triggered because of docker.sock mount.
However, if a server or agent container has been started either with a named docker volume or an absolute host path that is different from ${BAMBOO_HOME}
(${BAMBOO_AGENT_HOME}
if a remote agent executes a job), the build container that Bamboo launches will not mount job workdir.
Symptoms
Missing files in a working directory since docker container will mount an empty host directory which Docker will create. This can result in errors like missing pom.xml for a Maven build. The exact error log depends on the build tool used in a task. Here's an example of a failed Maven build (from job build logs):
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.261 s
[INFO] Finished at: 2020-12-01T09:18:18+02:00
[INFO] ------------------------------------------------------------------------
[ERROR] The goal you specified requires a project to execute but there is no POM in this directory (/home/eugene/Downloads/atlassian-bamboo-7.1.1/bamboo-home/xml-data/build-dir/TEST-TES4-JOB1). Please verify you invoked Maven from the correct directory. -> [Help 1]
Cause
Here are a few examples of docker run syntax when build containers will not mount workdir by default:
docker run d -name=bamboo-agent -v my-vol:/opt/atlassian-bamboo/agent-home atlassian/bamboo-agent-base
or
docker run d -name=bamboo-agent -v /root/bamboo-volume:/opt/atlassian-bamboo/agent-home atlassian/bamboo-agent-base
When using default volume mount bindings in job docker configuration, the environment variables will be resolved to /
opt/atlassian-bamboo/agent-home/temp
and /opt/atlassian-bamboo/agent-home/xml-data/build-dir/PROJECT-PLAN-JOB
As a result, Bamboo will start a build container with the following volume mount binding:
-v /opt/atlassian-bamboo/agent-home/xml-data/build-dir/PROJECT-PLAN-JOB:/opt/atlassian-bamboo/agent-home/xml-data/build-dir/PROJECT-PLAN-JOB
Since /opt/atlassian-bamboo/agent-home/xml-data/build-dir/PROJECT-PLAN-JOB
does not exist on a Docker host machine (and remember, a host Docker daemon is used because of docker.sock mount), Docker will create this directory and mount it to the container. As a result, /opt/atlassian-bamboo/agent-home/xml-data/build-dir/PROJECT-PLAN-JOB
is empty both on the host and in the build container.
Solution
There are two solutions, depending on how Bamboo server (or agent) container has been started.
Absolute Host Path in Volume Mount Binding
If an absolute path was used in Bamboo (agent) home volume mount binding:
- stop container
- create a host path identical to Bamboo home path, for example
/opt/atlassian-bamboo/agent-home
- copy Bamboo home to a newly created directory (for example from
/root/bamboo-volume
to/opt/atlassian-bamboo/agent-home
) - start Bamboo server (agent) container with a new volume mount binding:
-v /opt/atlassian-bamboo/agent-home:/opt/atlassian-bamboo/agent-home
Named Docker Volume
If a named volume was used, there's no universal solution that automatically works for all jobs. Since named volumes are stored in /var/lib/docker
(or whatever Docker root is configured), an absolute path to the volume should be provided in volume mounts when a job is configured, for example:
This approach has 2 downsides:
- an absolute path to job's working directory needs to be provided, which you may not know upfront but can predict by using project, plan and job keys
- a custom volume mount binding has to be provisioned for every new job that's run in Docker