Using Makefiles With Docker
Over the last few months I’ve been utilizing Makefiles to manage Dockerized applications. Recently I’ve found them easier to maintain than managing a bunch of shell scripts.
Using the project from the
Moving From Docker-osx-dev to the Docker Toolbox
article, create the following Makefile in the project directory:
makefile_dir := $(abspath $(shell pwd))
docker_group := mygroup
docker_image := myimage
docker_ver := 1.0.0
docker_tag := $(docker_group)/$(docker_image):$(docker_ver)
docker_port := 8080
docker_src := /src
host_port := 8080
.PHONY: list docker-build docker-run docker-push docker-dev
list:
@grep '^[^#[:space:]].*:' Makefile | grep -v ':=' | grep -v '^\.' | sed 's/:.*//g' | tr -d ':' | sort
docker-tag:
@echo $(docker_tag)
docker-build:
docker build --tag $(docker_tag) .
docker-bash:
docker run -it --rm -p $(host_port):$(docker_port) $(docker_tag) bash
docker-dev:
docker run -it --rm -v $(makefile_dir):$(docker_src) -p $(host_port):$(docker_port) $(docker_tag) bash
docker-daemon:
docker run -p $(host_port):$(docker_port) -d $(docker_tag)
Target descriptions
list
: List the available targets. Use this by running:
$ make list
and since it’s also the default target
you can use it kind of like a help
message by just running:
$ make
I just copy and pase this line into every Makefile. I cobbled this
target
together over a few weeks of experimentation and lots of time in
Google and Stack Overflow.
docker-tag: I split the components of the Docker
tag
into three components:- docker_group: The image group name. This helps with pushing docker images to Docker Hub to have a group for your container images.
- docker_image: The image name.
- docker_ver: The image version. Have a separate variable helps both for
manually updating the image version, but also helps with automation tools.
Running this target when you need to use this build as the base for another image. So given the example Makefile above running:
$ make docker-tag
prints:
mygroup/myimage:1.0.0
docker-build: Simply builds the image with the correct name. Just run:
$ make docker-build
docker-bash: Runs the container and drops you into a bash prompt inside the container.
$ make docker-bash
Start the NodeJS application:
$ npm start
Then you can browse to http://dockerhost:8080 and view the hellow world output.
docker-dev: Runs the container and drops you into a bash prompt inside the container with a volume mapping from the Makefile directory mapped over the
/src
directory. This allows you to edit the files in an editor or IDE on your workstations and have the changes reflected inside the container.$ make docker-dev
Start the NodeJS application:
$ npm start
Then you can browse to http://dockerhost:8080 and view the hellow world output.
docker-daemon: Simply builds the image with the correct name. Just run:
$ make docker-daemon
Then you can browse to http://dockerhost:8080 and view the hellow world output.
Some notes
- Makefiles can be finicky when it comes to syntax, so I use and editorconfig file.
I prefix all the docker related
targets
withdocker-
so when I addtargets
related to other technologies into the same Makefile they are easier to reference (or at least keep them separated in my head).For instance if you wanted to use GruntJS or GulpJS to execute some more complicated NodeJS task you can add another
target
likegrunt-build
, orgrunt-serve
,gulp-build
, etc… and keep then separate from your Docker tasks.Then you can just execute something like:
$ make gulp-build