Using Makefiles to improve Docker image build experience

Makefile is a building tool that's been around forever; and while some of us may remember it from building our first couple projects (and may hate those times and the struggle); But I believe it's an awesome tool that by just adding a single file to our project It can speed / easy up our daily work flow on: how we build, run locally, etc our 'Dockerized' projects.

TLDR Github project: https://github.com/danielm/docker-compose-makefiles

Lets suppose that in our project we want:

  • Build our docker images
  • We have at least 2 environments: production and development
  • We want to version our images, we will use Git's commit hashes and environment name: {GITHASH}-{ENVIRNONMENTNAME}.

I like going straight to the point, so lets look at the files we need:

project/
├── docker-compose.yml
├── docker-compose.development.yml
├── docker-compose.production.yml
├── .env
└── Makefile

Nothing special here, a base docker-composer, and the other two to customize/extend each of our environments.

So let's look at our Makefile, you can split it in three points:

  1. We include our .env file and then we use some sed magic to export all variables as env (that way those variables will be available to all sub-commands ran by make)
  2. Create another env variable, by looking at the current git commit and use it hash.
  3. Define all target(make commands) we want to use.
# Include env vars
include .env

# Export them all
export $(shell sed 's/#.*//g; /^$/d; s/=.*//' .env)

# For versioning
TAG_VERSION ?= $(shell git log --format="%h" -n 1)
export TAG_VERSION := $(TAG_VERSION)

# Pattern rule to build environment-specific containers
build:
	docker compose -f docker-compose.yml -f docker-compose.$(ENVIRONMENT).yml build 

# Target to start environment-specific images
up:
	docker compose -f docker-compose.yml -f docker-compose.$(ENVIRONMENT).yml up -d

down:
	docker compose -f docker-compose.yml -f docker-compose.$(ENVIRONMENT).yml down

logs:
	docker compose -f docker-compose.yml -f docker-compose.$(ENVIRONMENT).yml logs -f

push:
	docker push ${DOCKER_REPOSITORY}/${PROJECT_NAME}:${TAG_VERSION}-${ENVIRONMENT}

release:
	docker tag ${DOCKER_REPOSITORY}/${PROJECT_NAME}:${TAG_VERSION}-${ENVIRONMENT} ${DOCKER_REPOSITORY}/${PROJECT_NAME}:latest
	docker push ${DOCKER_REPOSITORY}/${PROJECT_NAME}:latest

Now we have access to these commands:

# Build our image and tags it with: {GITHASH-ENVIRONMENTNAME}
$ make build

# Bings it up
$ make up

# ... and down
$ make down

# Shows log outup
$ make logs

# Push the current tag built by 'build'
$ make push

# Pushes a new tag 'latest' from our current built
$ make release

This was just a simple example on how you could optimize a little bit how you build your projects!

Here is a full project to try it out: https://github.com/danielm/docker-compose-makefiles

Note: Included a NodeJS project (just printing Hello-World) just to demonstrate a full project building flow

About
Related Posts
  • Fancy words in Tech Episode III: Design patterns

    This is a immense topic, but on this post I will try to summarize the core concepts and explain the most common design patterns in software (or at least those I've personally run into during my career); like a "cheatsheet", or like a public personal note, that most likely will need to keep updating.

  • Fancy words in Tech Episode II: GraphQL

    It's been around for many years, and like other buzz-words many companies choose the tech just because "certain FANG company uses", then It must be good for my solution. Here i will try to summarize the most important key points of this technology, when and where is intended to be used and what a developer does when working on a project like this.

  • The SOLID Programming Principles OOP(s)!

    We can think of these as a general guide. There are many more, here are the ones I come up often, they are five and go by the acronym of S.O.L.I.D. The good thing about SOLID is that helps you decouple/breaking apart your code. Giving our modules independence of each other and make our code more maintainable, scalable, reusable and testable.

Comments
The comments are closed on this section.
Hire me!

I'm currently open for new projects or join pretty much any project i may fit in, let me know!

Read about what I do, or contact me for details.