Before we get started, if you don’t know about Docker, you should definitely have a read up about Docker.

Docker containers wrap up software and its dependencies which allows developers to build, ship and run applications anywhere.


Before starting this exercise, we had a basic build plan that clones our repo and runs a dotnet publish. We had to use a linux build agent in bamboo to use specific tools (docker, gcloud, ssh, etc.)

Docker configuration files

To “dockerize” our app, we need both a Dockerfile and a docker-compose-<environment>.yml



A simple text file that contains the commands a user can call to assemble an image, that can execute command-line instructions in succession



A tool for defining and running multi-container Docker applications, across multiple isolated environments

docker-compose transformation

We need to add our image name & tag to the docker-compose file so that our build server knows what image to deploy later on

Building the Docker image

Build the my-console-app image with the branch & build number as the tag

docker build -t${bamboo.repository.git.branch}-${bamboo.buildNumber} .

Push to our docker registry

Push the image to the gcloud docker registry, so that we can pull it & use it later on

gcloud docker -- push${bamboo.repository.git.branch}-${bamboo.buildNumber}


As we want this to run on a scheduled basis (once a day), we don’t want the containter to be always running. We’ll deploy it once per day, the container will auto start and execute our code & then close the container when completed

Docker swarm

Docker Swarm is a clustering and scheduling tool for Docker containers. With Swarm, developers can establish and manage a cluster of Docker nodes as a single virtual system.

Create deployment directory on our docker swarm

ssh dev@${bamboo.SwarmMasterIp} '[[ -d deployments/${bamboo.deploy.project} ]] || mkdir deployments/${bamboo.deploy.project}'

Deploy to docker swarm (& run the container)

Remote onto our docker swarm and download the version of the container we want to deploy

ssh -p 14122 dev@${bamboo.SwarmMasterIp} 'gcloud docker -- pull${bamboo.planRepository.branch}-${bamboo.buildNumber}'

(Secure) Copy the docker-compose file to our docker node

scp -P 14122 docker-compose-production.yml dev@${bamboo.SwarmMasterIp}:~/deployments/${bamboo.deploy.project}

Deploy our application ‘stack’ to the swarm using the config defined in our compose file

ssh -p 14122 dev@${bamboo.SwarmMasterIp} 'docker stack deploy -c ~/deployments/${bamboo.deploy.project}/docker-compose-production.yml myorg-prod --with-registry-auth'

Issues & concerns

The main issues I’d encountered while doing the above were:

1) Unsure that correct files were copied to the container A quick resolution for this was to add the following line to our Dockerfile: RUN ls or to view every file on the container: RUN find "$PWD"

2) Incorrect RUN command A hard one to find but I got there eventually - as I’d copied the RUN command from the microsoft docs, I assumed I was having problems elsewhere - it turns out that our container didn’t like the RUN ["dotnet", "my-app.dll"] command, as a ./ was missing at the start of our dll path!

3) Using the correct image For most popular docker images, there are many different tags which are build differently with different features in the container. We could have used the aspnet image as we do in all of our other docker applications (which are all APIs) but in our case, it doesn’t make sense as we don’t need all of the tools that are included in the image. We swapped to use the dotnet-runtime image (which is almost 50% smaller), meaning a faster pipeline (i.e. building, pushing and pulling the image)


To view the logs of your container while / after it has ran, portainer is a useful tool that lets you view service & container logs. If this tool isn’t available, you can do this directly by ssh’ing onto the swarm and viewing service logs:

ssh dev@$DockerSwarmNode
docker service logs <serviceID>

You can find the serviceID from running either of the following:

docker ps
docker ps | grep my-app

Remoting onto containers

Not applicable for our scenario but useful for long running tasks or persisting containers such as API’s.

docker exec -t -i <containerID> /bin/bash