Best Practices When It Comes to Writing Docker Related Files

Nick Janetakis - Oct 3 '18 - - Dev Community

This article was originally posted on June 19th 2018 at: https://nickjanetakis.com/blog/best-practices-when-it-comes-to-writing-docker-related-files


Everything listed below is based on personal experience and opinions. These are things that have worked well for me and the clients I've worked with while freelancing over the years.

It's also worth mentioning that this list always changes based on new experiences and I'll be updating this post as new patterns / styles emerge.

Dockerfile

  • Use Alpine as a base image unless you can't due to technical reasons
  • Pin versions to at least the minor version, example: 2.5-alpine not 2-alpine
  • Add a maintainer LABEL to keep tabs on who initially made the image
  • Only include ARG and ENV instructions if you really need them
  • Use /app to store your app's code and set it as the WORKDIR (if it makes sense)
  • When installing packages, take advantage of Docker's layer caching techniques
  • If your app is a web service, EXPOSE 8000 unless you have a strong reason not to*
  • Include a wget driven HEALTHCHECK (if it makes sense)
  • Stick to the [] syntax when supplying your CMD instructions

* This is explained in more detail below under the docker-compose.yml section.

docker-compose.yml

  • List your services in the order you expect them to start
  • Alphabetize each service's properties
  • Double quote all strings and use {} for empty hashes / dictionaries
  • Pin versions to at least the minor version, example: 10.4-alpine not 10 alpine
  • Use . instead of $PWD for when you need the current directory's path
  • Prefer build: "." unless you need to use args or some other sub-property
  • If your service is a web service, publish port 8000 unless it doesn't make sense to
Alphabetizing your service's properties, really?

Yep. Some services require having a bunch of properties and not giving them a specific order means you'll likely order things in different ways across projects or even services.

It's just 1 more thing to think about, but by having them alphabetized you no longer have to waste brain cycles grouping things up manually and you can scan a list of properties quickly.

Exposing and Publishing on port 8000?

That last one requires an explanation. I work with Flask, Rails, Phoenix and Node apps on a pretty regular basis. Each of these use different ports by default for their app server.

Rails uses 3000, Flask uses 5000, Phoenix uses 4000 and most Express apps use 3000.

When it comes to accessing these services in your browser, it's confusing because you always think, wait is it localhost:3000 or localhost:4000?

By defaulting to 8000 for your web services there's no more second guessing yourself. If you have a multi-service app then increment the port by 1, such as 8001, 8002, etc..

.dockerignore

  • Don't forget to create this file :D
  • Don't forget to add the .git folder
  • Don't forget to add any sensitive files such as .env.production

Example Apps for Popular Web Frameworks

I've put together a few example applications that stick to these best practices. You can find them all on https://github.com/nickjj/docker-web-framework-examples.

Fully working Docker Compose based examples that you can reference:

If you don't see your favorite web framework listed above, open up a PR! This repo is meant to be a community effort where we can work together to make high quality example apps that demonstrate Dockerizing popular web frameworks and libraries.

What are some of your best practices? Let me know below!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .