Introduction
Linting can be used to verify that your Dockerfiles are adhering to a set of predefined guidelines. There are lots of linters available, but let’s look at using hadolint
.
In our last blog post we created a DockerfileGood
that uses multi-stage builds to reduce the image size and attack surface. However, it still contains further issues that need addressed.
Prerequisites
This blog post assumes:
Lint Example
Let’s recreate our DockerfileGood
file from the last blog. Then we will run the hadolint
linter against it to see where we can improve it.
1) Create Dockerfile
Create DockerfileGood
:
FROM ubuntu:24.04
WORKDIR /app
# Pretend to install build tools
RUN dd if=/dev/zero of=mock-build-tools.zip bs=100M count=1
# Pretent to use build tools to create our script
RUN echo "print(\"Hello World\")" > main.py
# Remove our mocked build tools
RUN rm mock-build-tools.zip
# Create a new image and only copy over the files we want to keep
FROM ubuntu:24.04
COPY --from=0 /app /app
CMD echo "Hello World"
And run our linter command:
docker run --rm -i hadolint/hadolint hadolint - < DockerfileGood
Immediately you will see this needs improvements:
-:9 DL3059 info: Multiple consecutive `RUN` instructions. Consider consolidation.
-:12 DL3022 warning: `COPY --from` should reference a previously defined `FROM` alias
-:14 DL3025 warning: Use arguments JSON notation for CMD and ENTRYPOINT arguments
2) Fix Issues and re-run
Let’s fix our issues, and create DockerfileBetter
:
FROM ubuntu:24.04 as build
WORKDIR /app
# Pretend to install build tools
# Pretent to use build tools to create our script
# Remove our mocked build tools
RUN dd if=/dev/zero of=mock-build-tools.zip bs=100M count=1 \
&& RUN echo "print(\"Hello World\")" > main.py \
&& RUN rm mock-build-tools.zip
# Create a new image and only copy over the files we want to keep
FROM ubuntu:24.04
COPY --from=build /app /app
CMD ["echo", "Hello World"]
Now re-run our linter:
docker run --rm -i hadolint/hadolint hadolint - < DockerfileBetter
You will see this passes as expected.
3) Change Trust Registries
Let’s take this a step further and enforce a private registry. We can utilise the --trusted-registry
parameter for this:
docker run --rm -i hadolint/hadolint hadolint --trusted-registry docker.rhuaridh.co.uk - < DockerfileBetter
You will then see this image:
-:1 DL3026 error: Use only an allowed registry in the FROM image
-:12 DL3026 error: Use only an allowed registry in the FROM image
That’s it! We can now check to make sure staff are not using base images from untrusted sources.
Summary
Linting can be a useful tool to enforce best practice and to help secure your Dockerfiles.
For further help on configuring Hadolint, please check out their documentation.
If you’re using CICD, check out their continuous-integration section in their documentation.