Docker Docker Docker

I've been using Docker for many years now. During this time I've noticed that I can make life a little difficult for my self ... and, undoubtedly, everyone else around me. For a brief moment, let me discuss my Docker journey in a few words:

My Docker Journey

Phase: Ignorance

What is this thing? Why do I need another Vagrant?

Phase: Naivety

Ooooooh, it's like apt; I can "install" and run Elasticsearch with a single command

Phase: Enlightened

It's redefining the atomic unit of software development: Packaging. Distribution. Runtime with Containment / Isolation. All the Security

Phase: Pomposity

Everything should be in a container. Don't you run zsh in a container too?

Phase: Bitter Pomposity

Yeah, so like, my auto-complete doesn't work anymore because all these IDEs don't understand that my build tools are containers. It's so annoying. They need to get with the times

Phase: Angry Pomposity

Sigh. Yes, OSXFS sucks. Just install Linux

Phase: Rage

Did you update the Makefile without updating CI? You broke the fucking build again. Oh, it was me. Sorry mate 😅

NB: git commit --amend is your friend 😂

Phase: Indifference

I have all my dev tools installed locally and in containers

What's the Point?

Hopefully you recognise a few of these phases. It's taken me a long time to realise:

  1. You can't force everyone to use Docker
  2. You shouldn't force yourself to use Docker
  3. You should support agnostic development environments

I'm not saying this is new. I'm not suggesting I'm the only person that does this. I'm not going to try and convince you this is life-changing. This is me admitting that it took a very long time to establish some common sense when working on projects and providing my teams with sensible development environments.

The Docker Shell Pattern

The idea is threefold:

  1. Provide a Makefile
  2. Include targets for dshell and dclean
  3. Only use make targets

Provide a Makefile

Seriously. I've seen so many, and created a few myself, ./bin/start.sh scripts over the last few years that I may passive aggressively snort if I see another. Just use a Makefile. It's easier, I promise. Lets stop writing scripts with if [[ $1 == "start" ]];.

  • Provide small targets that provide a single purpose to be run
  • Provide goals that utilise two or more single purpose targets
  • ALWAYS provide an up target and sing it in the style of Serj Tankian when executing said target

What's the beauty of this?

  1. (Almost) Every system has make pre-installed
  2. You can use these targets to develop without Docker ... shocking, I know
Example
lint:
	@mix format --check-formatted

format:
	@mix format --check-equivalent

deps:
	@mix deps.get

compile: deps
	@mix compile

up:
	@mix run --no-halt

test:
	@MIX_ENV=test mix test ${TESTS}

coveralls:
	@MIX_ENV=test mix coveralls

clean:
	@mix clean

Include targets for dshell and dclean

Now ... wouldn't it be nice if we provided a simple interface for the people that want to use Docker?

Just run make dshell and you'll be presented with a new bash terminal. Now you can execute your make targets like those sinful developers that don't use Docker.

dshell:
    # `--service-ports` publishes your ports, which you'd normally only get from `docker-compose up`
    @docker-compose run --rm --service-ports --entrypoint=bash elixir

dclean:
    @docker-compose down -v --rmi=local

Profit

That's it. I said it was simple. Use those make targets for local development, CI and within your Docker Shell for a happy, simpler, life.