Better local development with Docker and Make

Adrian Angel Sanz Melchor
4 min readApr 27, 2021

Why?

These days everybody has abandoned the idea of running full blown virtual machines and find docker a better tool for local development, or staging/production environments, there’s a lot of reasons for switching to docker but TL;DR is much more faster and lightweight.

Our projects where usually made using ansible+vagrant+VB to set-up a local environment, ansible was used as well to set-up the rest of the environments. When we moved to docker, we removed Ansible from the stack, to keep all our environments on docker and as similar as possible (we keep using Ansible, but not this way anymore, still a wonderful tool ❤)

All the useful playbooks (ansible group of tasks) that we used to deploy, export and import db dumps and so on, will not be used… So, I needed a way of doing this without having developers complaining about executing 6 commands to get everything working, that’s where the Makefile comes in.

Makefiles are commonly used to build C/C++ applications, but at the end, they usually execute a set of commands on the system, so we can use it as a sort of “bash script” (IT’S NOT A BASH SCRIPT) to make developers (and my) life easier

How?

Makefile syntax is tricky to understand, I recommend passing by https://makefiletutorial.com/ while experimenting

So, let’s start with a simple example:

Let’s say you want to create a make tasks that runs yarn build inside the “front” service on a docker-compose stack, with multiple compose files, to do so you will create a Makefile with something like:

And to use it, you just will run “make build”.

This makes life easier for everyone, and in case you don’t want to use that compose file, you can change it on the Makefile or in the CLI like: “make build COMPOSE_FILE=docker-compose.staging.yml”

Running arguments on commands

Okay, but what if I want something like “make logs front” to check logs of docker services… You can do it! Just with a little hack:

I added a bit of complexity from a real example we have. First the “USER_UID” would be the equivalent of running “USER_UID=$(id -u)” on bash. Second notice the filter-out and the end of the makefile this will allow us to run something like “make logs front” or “make logs back” and will end-up executing a docker-compose log of the service we wrote. This “hack” goes against Make usage, but for our use case is fine, it has some drawbacks tho.

  1. Running a make with multiple arguments will require double quotes: ‘make logs back front’ will not work, ‘make logs “back front”’ will do
  2. Running non-existent commands will not fail, it will output nothing and exit as 0, so running “make log” instead of “make logs” will just output nothing and will exit as 0

Running more complex commands (export a database to s3)

This example will export a drupal database and upload it to s3 using pipes (aws cli allows it, and it’s wonderful)

This is one of the more complex commands we run on our Makefiles, but as you can see for the developer, or even for me on a pipeline will be like “make ext-db”

Setting up helps for make

This is an extra tip for you! Recently we added helps, and running “make help” or “make” will display helps on the commands to do so, you should have this:

Things to note is the “help” command the “## something” and .DEFAULT_GOAL. With this you can set-up a help that looks like this:

The other thing to note, is that you can concatenate make commands, to create a new command that will launch the full procedure set-up, making it easy to decouple steps that could be run multiple times, like a front build from react, or a collectstatics from django. (with @ before a command, the command will not be displayed: https://makefiletutorial.com/#command-echoing-silencing)

How do I continue?

Well, I’ve shown you some examples that we have for our use case, this might not be useful for you, you’ll need to make use of your I M A G I N A T I O N to come up with something that works for you, I will leave a full example of a current Makefile we use (django+react+ELK stack):

It’s quite complex, play with it, try things out, be careful with paths and good luck :D

--

--

Adrian Angel Sanz Melchor

Just a spanish DevOps who likes sharing useful knowledge, working proudly @ Cipher