Hadolint: Complete Guide to Linting Dockerfiles

Lint Dockerfiles Using Hadolint

Want to learn how to Lint Dockerfiles Using Hadolint? This blog post will show you how. It is a complete guide on Dockerfile linting.

Dockerfiles are like blueprints for building Docker images. By linting Dockerfiles, you can catch the errors and issues early on and ensure they follow the best practices.

What is Hadolint?

Hadolint is an open-source command-line Dockerfile linter tool built using Haskell that helps you write error-free Dockersfiles. Hadolint checks your Dockerfile for possible errors, security vulnerabilities, and performance problems. It has over 9k starts on GitHub

Here is how it works.

  1. Hadolint reads the Dockerfile
  2. It parses the Dockerfile into an AST (Abstract Syntax Tree) to identify each instruction and argument associated with it.
  3. It then checks each instruction against the predefined set of rules that cover security, efficiency, and code quality. The rules are part of the Hadolint source code. You can check the list of rules here.
  4. All the rule violations get flagged by Hadolint and it creates feedback on all the detected issues.
Hadolint linting workflow for Dockerfile

The severity of the issues is categorized as follows:

  1. Info – You get suggestions for improvement in info. It is considered less severe.
  2. Style – Related to formatting or structure of the Dockerfile like using indentation or using long single lines, etc.
  3. Warning – Less critical issues and minor security concerns that need improvement.
  4. Error – These issues are severe and could potentially relate to security vulnerabilities or major best practice violations.

Now that we have a basic understanding of Hadolint, let’s move on to the installation and see it in action.

Install Hadolint

You can install Hadolint on Linux, Mac, and Windows systems.

Install in Linux

If you want to install Hadolint in your Linux system follow the below step.

Step 1: Download the latest Linux Hadolint package from Hadolint Github Release page.

wget -O hadolint https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64

Step 2: Once you downloaded the application, move it to the /usr/local/bin directory.

sudo mv hadolint /usr/local/bin/hadolint

Step 3: Give execution permission to Hadolint using the command given below.

sudo chmod +x /usr/local/bin/hadolint

Install in Mac

You can install Hadolint on your Mac system using the command given below.

brew install hadolint

To check if Hadolint is installed on your Linux or Mac system, run the command:

hadolint --version

Install in Windows

Use scoop to install Hadolint on windows

scoop install hadolint

Once you have installed hadolint you will have hadolint CLI to run the lint test against the Dockerfiles.

To understand all the CLI options you can use the –help flag.

hadolint --help

Lint Dockerfiles Using Hadolint

To use Hadolint, simply install it on your system and run the command with your Dockerfile. Hadolint will give a list of errors it finds in your Dockerfile as an output, along with a severity level and the cause of that problem.

To get a practical understanding, we will use a Dockerfile that is not optimized.

Save the following as a Dockerfile.

FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get update && apt-get install -y curl
RUN echo "hello world" | grep "world" | wc -l
CMD ["echo", "Hello, world!"]

Let’s run Hadolint against the above Dockerfile. Ensure you have the Dockerfile in the same Directory you are running the hadolint command.

hadolint Dockerfile

You will get the following output with a Warning and Info message with the rule numbers and remediation info as shown in the image below.

Hadolint output with warnings and info levels

If you check warning number 7, Hadolint gives info on the shell script as well. Hadolint under the hood uses Shellcheck to lint shell scripts that are part of the RUN instruction.

Now, If you check the exit code, you will get a non-zero exit code

hadolint-examples git:(main) ✗ echo $?                      
1
➜  hadolint-examples git:(main) ✗

If you implement all the recommendations, you will get the following Dockerfile.

# Use Ubuntu 20.04 as the base image
FROM ubuntu:20.04

# Set the default shell with -o pipefail
SHELL ["/bin/bash", "-o", "pipefail", "-c"]

# Run commands
RUN apt-get update && \
    apt-get install -y curl=8.4.0 --no-install-recommends && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* && \
    echo "hello world" | grep -c "world"

# Default command to run
CMD ["echo", "Hello, world!"]

Now, if you run the Hadolint against the remediated and updated Dockerfile you will not get any warnings or info messages. If you check the exit code, you will get a 0 as shown in the image below.

hadolint zero exit code.

Ignoring Rules

There are scenarios where you might not want to remediate all the recommendations. In such cases, you ignore specific rules using the --ignore flag.

For example, if I want to ignore DL3008 that recommends specifying versions of software packages, I can use the following command.

hadolint --ignore DL3008 Dockerfile

When working with CI/CD systems we need to standardize all the configuration and rules for lining. Here is where hadolint.yaml configuration files come in to picture.

hadolint.yaml

handolint.yaml is the configuration file for Hadolint. You can customize how Hadolint handles the output and recommendations using the configuration file.

This is particularly useful when you want standardization and customization for linting Dockerfile across organizations or projects. This template can be shared with developers or devops engineers who develop Dockerfiles.

You can refer to the official documentation for all the supported parameters.

Let’s take a look at the key parameters.

  1. failure-threshold: To specify at what level the lint should fail or give a non-zero exit code. For example, by default, Hadolinit gives a non-zero exit code for all levels. With this parameter, you can configure non-zero exit codes for the errors & warnings. Info and style will be ignored for non-zero exit codes.
  2. ignored: If you want to ignore specific rules, you can list them under the ignore parameter.
  3. override: This parameter is specifically useful if you want to override the severity of specific rules. For instance, the DL3015 rule comes under info. However, you want to categorize it as a warning. So you can add DL3015 under the warning category under override. For all Hadolint runs that use this config, DL3015 will be listed as a warning.
  4. trustedRegistries: In most organizations, you are allowed to use only internal container registries. If you want to allow only images from specific container registries, you can add those registry endpoints under these parameters. If the Dockerfile has images from other registries, the lint will fail.

Here is a sample config with all the key parameters. Save the following config as .hadolint.yaml

failure-threshold: warning
format: tty
ignored:
- DL3007
override:
  error:
  - DL3015
  warning:
  - DL3015
  info:
  - DL3008
  style:
  - DL3015
trustedRegistries:
- docker.io
- techiescamp.com:5000
- "*.gcr.io"
- quay.io

You can use the config file with Hadolint as shown below

hadolint --config .hadolint.yaml Dockerfile

Using Hadolint in Docker Image Build Pipeline

As a standard practice, Developers can run Hadolint while creating Dockerfiles before pushing it to the repository. However, the key use of Hadolint comes in the Docker Image build pipeline.

You can add Dockerfile linking using Hadolint as part of the Docker build CI pipeline. When a PR is raised for Creating/Updating Dockerfile, the first step in the pipeline would be linting.

If the Dockerfile does not adhere to the Hadolint rules, the build fails and developers can use the Hadolint feedback to rectify the issues with Dockerfile.

You can customize the rules and configs using the hadolint.yaml file as per your organization’s standards and project requirements.

This way you catch all the errors in the Dockerfile and ensure it adheres to standard best practices before it gets committed to the main branch.

Run Hadolint Using Docker

There is a way to use Hadolint without installing it in your system, we can use the Docker image for Hadolint. The command to use the Hadolint Docker image is given below.

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

The best part of using this command is, if there is no Hadolint Docker image in your system it downloads the Docker image first and then scans the Dockerfile.

Hadolint Online Version

There is an online version of Hadolint where you can lint your Dockerfiles from the browser. This is useful for quick testing.

You can access the online version here.

Hadolint Online Version.

Benefits of using Hadolint

As per this IEEE research paper on Dockerfile smells, Nearly 84% of GitHub projects in their dataset had smells in their Dockerfile code, especially the DL-smells.

Using Hadolint has many benefits, some are listed below:

  1. Improves Dockerfile quality: Hadolint identifies errors in your Dockerfile, which improves and optimizes the Dockerfile
  2. Reduce security risk: Hadolint can identify security vulnerabilities in your Dockerfile, such as using old base images, and helps in reducing the attack surface.
  3. Improves performance: Hadolint can find issues in your Dockerfile that reduce the performance of Docker images, such as building unnecessarily large images.
  4. Increases consistency: Hadolint ensures that your Dockerfiles are consistent with best practices, which makes them compliant with your organization’s policies.

Tips for using Hadolint

Here are a few tips for using Hadolint:

  1. Start by fixing the most severe errors: Hadolint will assign a severity level to each error it finds. First, fix the most severe errors because these are the most likely to cause problems.
  2. Enable all of the rules: Hadolint comes with a set of default rules that are enabled by default. However, there are also a number of optional rules that can be enabled. Consider enabling all of the rules to make Hadolint work efficiently. You can customize these rules again based on your exclusion requirements.
  3. Configure Hadolint as you need: You can also modify the rules that are enabled, and the severity levels of different violations, and you can also specify the output format.

Conclusion

Linting Dockerfile is a good practice during development as in Infra pipelines. I highly suggest you add Hadolint as part of your Docker image build pipeline to have secure and optimized container images.

Do you use any other linting tools for Dockerfile? or do you have any doubts regarding Docker linting?

Either way, let me know your thoughts in the comment section.

Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like