Hadolint es una herramienta de linea de comandos que nos permitirá analizar nuestros Dockerfiles y ayudarnos a que los mismos cumplan con una serie de reglas y buenas prácticas.
PROMO DigitalOcean#
Antes de comenzar, quería contarles que hay una promoción en DigitalOcean donde te dan un crédito de USD 200.00 durante 60 días para que puedas probar los servicios que este Proveedor Cloud ofrece. Lo único que tienes que hacer es suscribirte a DigitalOcean con el siguiente botón:
O a través del siguiente enlace: https://bit.ly/digitalocean-itsm
Como funciona#
Hadolint lee el Dockerfile.
Mediante AST ( Abstract Syntax Tree) identifica las instrucciones y los argumentos contenidos en el archivo.
Valida cada instrucción contra una seria de reglas predefinidas que cubren seguridad, eficiencia y calidad de código. Las reglas son parte del código fuente de Hadolint. Podremos encontrar las reglas predefinidas aquí
Todas las reglas que se incumplan serán mostradas en la salida en consola y de esta manera crear feedback con todos los problemas detectados.
Instalando Hadolint#
Linux#
Descargamos el ejecutable desde el Sitio Oficial de Hadolint en GitHub:
wget -O hadolint https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64
Luego lo movemos al directorio /usr/local/bin:
sudo mv hadolint /usr/local/bin/hadolint
Le damos permisos de ejecución:
sudo chmod +x /usr/local/bin/hadolint
Mac OS#
A través de Homebrew podremos instalarlo facilmente:
brew install hadolint
Y chequeamos su versión actual:
hadolint --version
Windows#
Usando scoop:
scoop install hadolint
Docker (Recomendado)#
Descargamos la imagen:
docker pull hadolint/hadolint
O si queremos directamente analizar un Dockerfile:
docker run --rm -i hadolint/hadolint < Dockerfile
Analizando Dockerfiles#
Lo mejor para entender como funciona Hadolint es hacerlo práctico, entonces, teniendo el siguiente 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!"]
Teniendo el Dockerfile guardado en el mismo directorio donde vamos a ejecutar lo siguiente:
hadolint Dockerfile
Dockerfile:1 DL3007 warning: Using latest is prone to errors if the image will ever update. Pin the version explicitly to a release tag
Dockerfile:2 DL3009 info: Delete the apt-get lists after installing something
Dockerfile:3 DL3059 info: Multiple consecutive `RUN` instructions. Consider consolidation.
Dockerfile:3 DL3008 warning: Pin versions in apt get install. Instead of `apt-get install <package>` use `apt-get install <package>=<version>`
Dockerfile:3 DL3015 info: Avoid additional packages by specifying `--no-install-recommends`
Dockerfile:4 DL3008 warning: Pin versions in apt get install. Instead of `apt-get install <package>` use `apt-get install <package>=<version>`
Dockerfile:4 DL3015 info: Avoid additional packages by specifying `--no-install-recommends`
Dockerfile:4 DL3009 info: Delete the apt-get lists after installing something
Dockerfile:5 SC2126 style: Consider using 'grep -c' instead of 'grep|wc -l'.
Dockerfile:5 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then considerexplicitly setting your SHELL to /bin/ash, or disable this check
Obtendremos la siguiente salida con mensajes de tipo Warning e Info con las reglas y como solucionarlos como se muestra arriba.
Si prestamos atención a la linea 5, Hadolint nos provee información sobre una instrucción shell. Hadolint utiliza Shellcheck tras bastidores para validar scripts shell que son parte de la instrucción RUN.
Si implementamos todas las recomendaciones, tendriamos el siguiente 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!"]
Y analizando nuevamente el Dockerfile nos encontraríamos con un mensaje de salida 0 (exitoso):
hadolint Dockerfile
echo $?
0
Excepcionando Reglas#
Hay casos en los cuales no queremos solucionar todas las recomendaciones (bien sea porque necesitemos un Dockerfile con bastantes RUN porque somos masoquistas
), podemos excepcionar algunas reglas especificas usando el parámetro --ignore
Por ejemplo, si quisiéramos excepcionar la regla DL3008 que recomienda tener versiones especificas de los paquetes que instalemos a la imagen, lo excepcionamos de la siguiente manera:
hadolint --ignore DL3008 Dockerfile
Cuando trabajamos con CI/CD, podemos estandarizar toda la configuración de las reglas a través de un archivo hadolint.yaml.
hadolint.yaml#
Este archivo puede compartirse con desarrolladores o ingenieros de software quienes codean Dockerfiles.
Pasemos a explicar un poco los parámetros con la Documentación en la mano:
failure-threshold
: Especificamos el nivel en el cual va a fallar la comprobación. Por ejemplo, de manera predeterminada Hadolint devuelve un valor distinto a 0 para fallar. Podemos configurar ese nivel de fallo solo para Warning y Errors pudiendo Info y Style ser ignorados.ignored
: Si quieres ignorar reglas especificas, puedes listarlas debajo del parámetroignore
.override
: Este parámetro es muy útil si querríamos sobrescribir el nivel de severidad de reglas especificas. Por ejemplo, la regla DL3015 es de tipoInfo
, sin embargo, podemos modificarla para que se de tipoWarning
. Entonces, cuando Hadolint se ejecute, esa regla especifica (DL3015) será mostrada como warning.trustedRegistries
: En la mayoría de las organizaciones, solo se permite el uso de un registro de imágenes interno. Si quisiéramos permitir mas de un registro agregando sus endpoints. En caso que el Dockerfile contenga imágenes de otros registros, la comprobación fallara.
Aqui tenemos un ejemplo, el cual debe ser guardado como .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
hadolint --config .hadolint.yaml Dockerfile
Configurando CI/CD#
¿Un ejemplo con GitLab? Un ejemplo con GitLab :)
Supongamos que ya tenemos nuestro archivo de pipeline (.gitlab-ci.yml
) con los stages lint y build. En el stage Lint vamos a declarar las tareas para ejecutar Hadolint y:
stages:
- lint
- build
Lint Analisys:
stage: lint
image: hadolint/hadolint:v2.12.0-alpine
script:
- mkdir -p reports
- hadolint -f gitlab_codeclimate Dockerfile* > reports/hadolint-$(md5sum Dockerfile | cut -d" " -f1).json
artifacts:
name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
expire_in: 1 week
when: always
reports:
codequality:
- "reports/*"
paths:
- "reports/*"
allow_failure: true
Bulding image:
stage: build
script:
...
Creamos una carpeta que se llame reports, y luego guardamos en un archivo .json el resultado de Hadolint, el cual almacenamos como un artefacto por 1 semana. Con allow_failure
controlamos si queremos que permite que falle el stage y poder continuar con la ejecución de los siguientes stages.
Si tuviéramos la versión de GitLab Enterprise, pudiésemos ver los resultados en tiempo real en nuestro panel de stage con la opción gitlab_codeclimate
.
Ventajas de usar Hadolint#
Mejora la calidad de código de nuestros Dockerfiles, identificando errores y optimizando la cantidad de capas de la imagen resultante.
Reduce los riesgos de seguridad identificando posibles vulnerabilidades, como imágenes antiguas, etc.
Mejora el rendimiento identificando posibles problemas que puedan reducirlo, como por ejemplo construir imágenes innecesariamente grandes.
Mejora la consistencia de nuestros Dockerfiles y haciendo cumplir las buenas praticas de la empresa u organización.
Hasta aquí el artículo, espero les haya gustado, ¡hasta la próxima!
Referencias#
- Hadolint: Complete Guide to Linting Dockerfiles: https://devopscube.com/lint-dockerfiles-using-hadolint/
- Using Hadolint, a dockerfile linter, to enforce best practices https://www.airplane.dev/blog/hadolint
Artículos sobre Docker#
- Como Instalar Docker en Linux
- Como Instalar Portainer: El Mejor Gestor Gráfico de Docker en Linux
- Conceptos y Comandos Básicos en Docker
- Construyendo Imágenes Personalizadas en Docker con Dockerfile
- Desplegando Aplicaciones con Docker Compose
- Como Configurar un Registro Privado de Docker en Linux
- SupervisorD: Gestionando Procesos en Docker
- Buenas Prácticas al Escribir Dockerfiles
- Crear Imágenes Multi-Arquitectura en Docker con buildx
- Hadolint: Verificando nuestros Dockerfiles