In this blog post, I’ll walk you through how I streamlined my Docker-based workflows by linting Dockerfiles with Hadolint in Jenkins pipelines. By integrating this powerful tool, I’ve managed to elevate my pipeline’s efficiency and ensure code quality at every step.
The Quest for the Perfect Linter
As a firm believer in building Docker images that are not only efficient but also secure, linting Dockerfiles became a priority. Among various options, Hadolint stood out as the most promising candidate. Not only could it assess Dockerfile best practices, but it also possessed a unique capability to evaluate bash commands within Docker RUN commands – a feature that I really like to possess.
The Groovy Script that Made It Happen
To bring Hadolint into my Jenkins pipeline, I crafted a Groovy script. This script dynamically identifies all Dockerfiles within the designated src/main/
directory and its subfolders and works with multimodule Maven projects this way aswell. It then proceeds to fetch the Hadolint configuration file, a crucial piece of the puzzle that governs linting rules. This file can be uploaded to a central location and then just downloaded in the pipeline run.
// list all Dockerfiles within src/main/, then download the hadolint config file and run a hadolint container linting every Dockerfile found def call() { def dockerFiles = findFiles(glob: '**/src/main/**/Dockerfile') if(dockerFiles) { sh 'wget -O hadolint.yaml https://my-vcs-url.com/hadolint.yaml' dockerFiles.each { dockerFile -> def dockerFilePath = dockerFile.getPath() echo "Linting Dockerfile: ${dockerFilePath}" def hadolintResult = sh( script: """ docker run --rm -i -v "\$(pwd)/hadolint.yaml:/.config/hadolint.yaml" hadolint/hadolint < ${dockerFilePath} """, returnStatus: true ) if (hadolintResult == 0) { echo "Linting passed for ${dockerFilePath}" } else { echo "ERROR: Linting failed for ${dockerFilePath}" error("Linting failed for ${dockerFilePath}") } } } else { echo "No Dockerfile files found to lint." } }
Aborting the Pipeline on Error
An important aspect of this setup is how Hadolint’s behavior impacts the pipeline. Hadolint evaluates Dockerfiles against its ruleset and, importantly, returns a non-zero status code when a rule evaluates to an error level. This unique behavior serves as an automatic quality gate within your pipeline. If any aspect of the Dockerfile violates best practices or security guidelines, the script swiftly detects it and the pipeline is gracefully aborted, preventing the creation of a potentially flawed Docker image. To implement a stricter ruleset or switch an error-inducing rule to a more lenient level the hadolint configuration file can be used.
Rule Fine-Tuning with Hadolint Configuration
Hadolint comes with a default ruleset, but its true power lies in its configurability. The hadolint.yaml
configuration file enables you to fine-tune each rule’s severity level – be it error, warning, or information. This empowers you to tailor the linting process to your project’s specific needs, ensuring that every line of code adheres to your desired standards. Every rule can be overridden in its severity allowing you to skip errors or force even information level rules to abort the pipeline should they be violated.
Reusable Flexibility for Your Pipeline
If you’re a fan of organization-wide consistency, you can encapsulate this script into a global library within Jenkins. This fosters a harmonious linting process across various pipelines, safeguarding the quality and security of your Docker images. On the other hand, if you prefer the script to be more hands-on, you can seamlessly integrate it directly into your individual pipelines. The key is in its versatility – whether you’re striving for a centralized approach or a project-specific touch, this script accommodates your needs with grace.
Navigating an Alpine-based Quirk
While the journey was largely seamless, a minor hiccup arose when dealing with the Alpine-based image of Hadolint. The configuration file’s location varied, requiring a small tweak. However, I promptly addressed this quirk by opening a pull request in the Hadolint GitHub repository.
Closing this post, I’ve illustrated the process of linting Dockerfiles with Hadolint in Jenkins pipelines. The provided Groovy script automates the linting process, utilizing Hadolint’s status code for robust quality control. Delve into rule refinement, navigate Alpine-related nuances, and embrace the journey of optimizing Dockerfile development within Jenkins.