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.
- Hadolint reads the Dockerfile
- It parses the Dockerfile into an AST (Abstract Syntax Tree) to identify each instruction and argument associated with it.
- 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.
- All the rule violations get flagged by Hadolint and it creates feedback on all the detected issues.
The severity of the issues is categorized as follows:
- Info – You get suggestions for improvement in info. It is considered less severe.
- Style – Related to formatting or structure of the Dockerfile like using indentation or using long single lines, etc.
- Warning – Less critical issues and minor security concerns that need improvement.
- 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.
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:
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.
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
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.
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.
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.
There are scenarios where you might not want to remediate all the recommendations. In such cases, you ignore specific rules using the
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.
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.
- 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.
- ignored: If you want to ignore specific rules, you can list them under the ignore parameter.
- 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.
- 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
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.
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:
- Improves Dockerfile quality: Hadolint identifies errors in your Dockerfile, which improves and optimizes the Dockerfile
- Reduce security risk: Hadolint can identify security vulnerabilities in your Dockerfile, such as using old base images, and helps in reducing the attack surface.
- Improves performance: Hadolint can find issues in your Dockerfile that reduce the performance of Docker images, such as building unnecessarily large images.
- 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:
- 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.
- 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.
- 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.
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.