Publish Docker Images using make and Travis CI

Here’s a template for Makefile I have been using to get continuous publishing of a Docker Image pushed to Docker Hub using Travis CI (or for that matter any other).

It allows for semantic versioning of Docker Images, can be run from local machine and works with private DockerHub Images.


Why use make

make is ubiquitous, is readable when used correctly, has task dependencies and simplifies tasks in CI/CD environments which have traditionally used opaque, long winding shell scripts.


Writing the Makefile

Steps

  • Provide the image owner, name and then a macro for QNAME to combine them together.
OWNER=rajatvig
IMAGE_NAME=demo-image
QNAME=$(OWNER)/$(IMAGE_NAME)
  • Infer information from CI like git commit SHA, build number and provide a semantic version for the image. Use the fully qualified QNAME from above for tagging and a `latest` tag.
GIT_TAG=$(QNAME):$(TRAVIS_COMMIT)
BUILD_TAG=$(QNAME):0.1.$(TRAVIS_BUILD_NUMBER)
LATEST_TAG=$(QNAME):latest
  • Define the Lint task to make sure the Dockerfile is correct
lint:
docker run -it --rm -v "$(PWD)/Dockerfile:/Dockerfile:ro" redcoolbeans/dockerlint
  • Define the build task to build the Docker Image based off the Dockerfile in the current path and tag it with the GIT_TAG.
build:
docker build -t $(GIT_TAG) .
  • Tag the Docker Image for the semantic version and latest
tag:
docker tag $(GIT_TAG) $(BUILD_TAG)
docker tag $(GIT_TAG) $(LATEST_TAG)
  • Push the Docker Image to Docker Hub.
login:
@docker login -u "$(DOCKER_USER)" -p "$(DOCKER_PASS)"
push: login
docker push $(GIT_TAG)
docker push $(BUILD_TAG)
docker push $(LATEST_TAG)

Setting up Travis CI

Configure Travis to monitor the repository and set up the build environment.

travis env set DOCKER_USER <docker user>
travis env set DOCKER_PASS <docker password>

And then add the `.travis.yml` to publish the image.

sudo: required
language: c
services:
- docker
script:
- make lint
- make build tag push

Local Development and Testing

Use Direnv and define a `.envrc` with the following contents

#!/bin/sh
export TRAVIS_COMMIT=abcd
export TRAVIS_BUILD_NUMBER=1
export DOCKER_USER=
export DOCKER_PASS=

Then run

make lint build tag

Do not run `make push`. While it will work, it’ll also send an image with tags as written in the .envrc.


A working example for Pact Broker

  1. Source for Docker Image
  2. Docker Image
  3. Makefile

Final Makefile

Publishing Applications using the same Template

The template described can be used to publish MicroServices as shown here. The more interesting bit there is determining the Semantic Version from the `package.json` for Node based Application.

PACKAGE_VERSION=`node -pe "require('./package.json').version"` 
OWNER=rajatvig
IMAGE_NAME=product-service
QNAME=$(OWNER)/$(IMAGE_NAME)
GIT_TAG=$(QNAME):$(TRAVIS_COMMIT)
BUILD_TAG=$(QNAME):$(PACKAGE_VERSION)-$(TRAVIS_BUILD_NUMBER)
LATEST_TAG=$(QNAME):latest

Feedback is welcome.