Blog by Sergej Jevsejev

Best task runner for Vanilla Docker projects

· by Sergej Jevsejev · Read in about 3 min · (548 Words)

What is Vanilla Docker project?

It is 100% native Docker-only environment. It means whenever you execute everything is done via Docker:

  • No Vagrant or similar custom VM
  • No tools are installed on the host machine. No NPM, PHP, Ruby executions from the host.

The project development environment has to be completely independent of the host machine. You can call it Vanilla Docker project.

Short explanation why nothing should be installed to the host machine is:

  • when you provisioned your project you should not provision your host
  • you will have a problem when you have several projects referencing different versions of the same application. For e.x.: node

Task runners for Vanilla Docker projects

The majority of projects has task runners. They are either:

  • internal - they bundle as part of the framework in the language the project is.
  • external - runners like Apache Ant or makefile.

But what is the best for the Vanilla Docker projects?

Most likely you will have some tasks which include shell reference docker, something like ... node npm install. Remember - we don’t want to execute npm them from the host machine.

Let’s take an example of Apache Ant task runner. In order to execute npm install you need to execute:

docker exec webratio/ant build-frontend-task

Since Apache Ant is JVM based, it will launch JVM then will try to execute npm install. The task will look something like that:

<target name="build-frontend">
    <exec executable="docker" failonerror="true">
        <arg line="run -t --rm -v ${PWD}:/usr/src/app -w /usr/src/app node node node_modules/gulp/bin/gulp.js"/>

Since Apache Ant will already be running inside the Docker, you will need to launch Docker within the Docker. Docker is not really like to do that.

Well you can crazy with something that Kubernetes does, but I do not recommend:

docker run --rm -e "HOST_PWD=$PWD" \
    -e "HOST_HOME=$HOME" \
    -v "$PWD":/src \
    --volume=/:/rootfs:ro \
    --volume=/sys:/sys:ro \
    --volume=/usr/local/bin/docker:/usr/local/bin/docker:rw \
    --volume=/var/lib/docker/:/var/lib/docker:rw \
    --volume=/var/run:/var/run:rw \
    --volume="$HOME"/.docker/config.json:/root/.docker/config.json:ro \
    --net=host \
    --privileged=true \
    --pid=host \

Please don’t. Problems then begins only begins:

  • Running task runner as root is high-security risk. You can potentially do harm on your host machine.
  • Data folder mapping is an issue because Inside the container data is in a different location than on the host. For ex.: on the host ~/projectA/, but in the container already /src.
  • It is complex to maintain
  • etc. …

This problem will happen also with any task runner: PHP, Ruby, Java, or any language. You just don’t want to run Docker within the Docker.

Magic pill

It is a shell. Yes, that simple. sh, bash, make, you choose. But it needs to be launched from the shell.

In the case of npm install the makefile will looks like this:

# NPM constant for readability
NPM = docker run -it --rm -v $(PWD):/src -v $(HOME)/.ssh:/home/1000/.ssh:ro -v $(HOME)/.npm:/home/1000/.npm sjevs/node npm

.PHONY: build-frontend
	@echo Installing NPM dependencies of project
	$(NPM) install

to execute it:

make build-frontend

And that’s it. No problems described above in language based task runners.

Benefits from makefile for Vanilla Docker

  • Docker container is launched from the shell, no need to launched Docker with the Docker
  • The project is self-provisioned. The only dependency on the host is to have Docker
  • Tasks are still structured
  • Shell autocompletion


The best task runner for Vanilla Docker project is shell script or make.