27 décembre 2014

Multiple Dockerfiles for project

When you start to use docker for the application you're developing, you need to choose if the Dockerfile you write is designed to

  • Build from source and produce binary
  • Package built binary for production application
  • Build from source and hot-reload source code for quick development cycles

Docker doesn't let you (yet) set the file you want to use as a Dockerfile, and enforce your use Dockerfile.
A possible workaround is for you to define a "Build from source" Dockerfile at project root, so it can ADD the source directory, and build binary in a target directory, then add to this directory another Dockerfile designed to produce the production image, just adding the binary with runtime dependencies. You still miss the 3rd use case, that require the docker image you run to allow hot-reload of source code you bind-mount in container.

After some experiments with various approach, my preference is to build the Docker build context by myself. So I have 3 Dockerfiles : Dockerfile.dev, Dockerfile.build, Dockerfile.prod.

  • First one uses a VOLUME to access project source code and run the app with hot-reload enabled (typically, play run). This let you use your IDE to hack the code and see the resulting app running in Docker container.
  • Second one build the application and package it for production execution (mvn package). This is the reference build environment, the one you probably use for CI as well. You can setup Jenkins to archive the resulting artifacts, or can just run it and execute a cp or cat command to export it from Docker container.
  • Last one to use the built artifact (from previous step) and ADD it to another image that only define required runtime dependencies, so the image is as small as possible. Such an image can't be used isolated, as it relies on the build one, so for sample can't be used with trusted builds, until Docker team offer some way to support non-trivial build scenarios.

To work around lack of a --file option for docker build command (#2112), I'm passing the build context explicitly as a tar.gz archive - there is no overweight doing this, as docker build commands does the same with current folder.

gtar --transform='s|Dockerfile.dev|Dockerfile|' -cz * | docker build -t dev -

As I'm running OSX and the included tar command does not support --transform option (sic) I had to install gnu-tar with homebrew, so the gtar command I'm using. As this is not a trivial command this can be set within a makefile, so you can just run make dev|build|prod.

Hope this will be useful for you as well.