Linting Dockerfiles with Hadolint

Christian Emmer
Christian Emmer
Aug 10, 2020 · 3 min read

Linters don't just enforce style guidelines, they also catch potential issues. hadolint (Haskell Dockerfile Linter) is the most popular linter for Dockerfiles, and it's incredibly easy to use.

hadolint parses your Dockerfiles into an abstract syntax tree and then checks rules on that tree. Not only does it have its own rules specific to Dockerfiles, it also uses ShellCheck to lint RUN instructions.

Usage

Assuming you already have Docker installed because we're talking about Dockerfiles, the easiest way to run hadolint is with Docker:

docker run --rm --interactive hadolint/hadolint < Dockerfile

Where Dockerfile is a file that exists in your working directory, outside of the container.

There are some other ways to install hadolint, but running it from Docker is probably the easiest way to go.

Configuration

There are really only two things you can configure about hadolint:

  • What hadolint and ShellCheck rules to ignore
  • What container registries are "trusted"

Both of those can be configured in a $PWD/.hadolint.yaml file like so:

ignored:
  - DL3003
  - DL3018

trustedRegistries:
  - docker.io

Or you can inline-configure ignored rules like so:

# hadolint ignore=DL3007
FROM alpine:latest

# hadolint ignore=DL3003,DL3018
RUN apk --update add --no-cache git && \
    cd "$(mktemp -d)" && \
    git pull "https://github.com/hadolint/hadolint.git"

Example output

Taking the above example and removing the ignored rules:

FROM alpine:latest

RUN apk --update add --no-cache git && \
    cd "$(mktemp -d)" && \
    git pull "https://github.com/hadolint/hadolint.git"

Here's the example output:

$ docker run --rm --interactive hadolint/hadolint < Dockerfile
/dev/stdin:1 DL3007 Using latest is prone to errors if the image will ever update. Pin the version explicitly to a release tag
/dev/stdin:3 DL3003 Use WORKDIR to switch to a directory
/dev/stdin:3 DL3018 Pin versions in apk add. Instead of `apk add <package>` use `apk add <package>=<version>`

Adding to CircleCI

Linters become a lot more powerful when you add them to your CI pipeline. A linter without enforcement will surely be ignored over time.

Here's a sample of how you could add hadolint to a CircleCI .circleci/config.yml:

version: 2.1

executors:
  docker:
    docker:
      - image: docker:stable

jobs:
  lint:
    executor: docker
    steps:
      - checkout
      - setup_remote_docker
      - run:
          name: Run hadolint
          command: docker run --rm --interactive hadolint/hadolint < Dockerfile

workflows:
  version: 2
  test:
    jobs:
      - lint

See "Publishing Docker Images with CircleCI" for a more complete guide on using CircleCI to publish Docker images.

Publishing Docker Images with CircleCI
Publishing Docker Images with CircleCI
Feb 15, 2021 · 8 min read

Publishing Docker images is a common CI/CD task, and the flexibility CircleCI offers makes it a great tool for the job.

Conclusion

Linters are a great tool to prevent team arguments over style, but they're a great tool for preventing potential errors - start using hadolint with your Dockerfiles today!