Linting — Writing Dockerfiles like a software developer
This article is part of a series on “Writing Dockerfiles like a software developer”, to find all the other articles click here.

When starting any coding, I’m usually really glad my IDE already gives me loads of tips, they are usually the first way to prevent mistakes in any scale (imho), from non-intended behavior to security issue.
Tools
With Dockerfiles it shouldn’t be different, there are a few tools to do that, that seems to be the most used ones are:
- dockerfile-lint by Project Atomic: A Node.js tool, it will help you with the file syntax and also allow you to write your own semantic analysis, like for instance defining rules of the tag you’re basing from.
- Hadolint (Haskell Dockerfile Linter): A linter that tries to embrace the Docker best practices, it creates an AST an performs it’s analysis, also has embed ShellCheck to perform static analysis for the
RUNinstructions.
For this article and my personal usage I chose Hadolint, I still consider dockerfile-lint to force some business rules, if I do I’ll write an article about it, from now on, Hadolint it is.
Hadolint
Basic usage
That’s pretty simple, since it’s a Haskell software I’d recommend you to use a Docker image instead of compiling or downloading it (feel free to).
First, a simple example:
From that moment you can see how simple and effective it is, configuration free we already got our first issue.
Now what I like the most of, is that Hadolint seems to have gotten inspired by Shellcheck on how the errors are organized, see the code DL3007, this basically refers to their knowledge base, which you can see here. In this case we can go directly to the given error by appending it to their wiki url: https://github.com/hadolint/hadolint/wiki/DL3007
To fix this sample, you can define a tag other than late:
Passing arguments to the binary
When using this Docker image you’ ll notice that you can’t simply pass an option and use stdin the same way as before, let’s try it:
To overcome that issue we will:
Note the - at the end, this symbolizes thestdin . Also now we invoke the hadolint binary right after passing the image name.
Changing the output format
To output json for instance:
That’s a really nice touch, you can for instance automate some notifications which contain the wiki URL on it by parsing the json and prepend the wiki url.
Ignoring a rule
The configuration file is my favorite one, it’s pretty neat to have a file in your project defining the rules for you Dockerfiles.
If you name it as .hadolint.yaml it will be auto picked!
The trick here is that you have to allow the Docker container to access the configuration file, my trick is to mount it under a directory, /project for instance, change the workdir and now I don’t even have to use stdin anymore, since it’s all available within the container. And for that, also observe I’m using the hadolint/hadolint:latest-debian image, since the latest tag is a scratch container only containing the binary, not allowing us to mount the directory.
Running multiple files at once
Now that we have the trick to mount our directory, let’s just add more and more files to the list:
The ShellCheck
For the given Dockerfile: (damn… it looks horrible, but we have linter for it)
It’s that simple and embed to the tool, you can also ignore ShellCheck rules as simple as in the Hadolint ones:
That’s it
That covers the basic and a bit more of it’s usage, I’d recommend putting it into your CI, later in this articles series I’ll show you how to achieve it!
For more on ShellCheck click here
For more on Hadolint click here
More
When the next articles are ready I’ll post them on my twitter, also update this index, feel also free to find me on GitHub as well!
