Saltar al contenido
Monitor con código abierto en un editor, en una sala a oscuras con una luz cálida al fondo

Dockerfiles avanzados: HEALTHCHECK, heredoc y montajes de BuildKit

Segunda parte de las buenas prácticas con Dockerfiles: comprobaciones de salud, sintaxis heredoc y RUN --mount para secretos, caché y claves SSH.

Por Víctor Piles TemporalSRE y técnico de sistemasPublicado el 4 min de lectura

Si habéis llegado aquí sin leer la primera parte, os recomiendo leerla y volver. En esta segunda entrega sigo con consejos y buenas prácticas para escribir Dockerfiles, a un nivel más avanzado.

En resumen: añadid un HEALTHCHECK para que Docker sepa si el contenedor funciona de verdad y consultadlo con docker inspect; usad la sintaxis heredoc de BuildKit para escribir varios comandos o crear archivos sin copiarlos; y usad RUN --mount para que la compilación acceda a secretos, cachés o claves SSH sin dejarlos en la imagen.

Generad comprobaciones de salud

  • La instrucción HEALTHCHECK indica a Docker cómo probar un contenedor para verificar que funciona correctamente. Por ejemplo, un servidor puede quedarse en un bucle infinito de procesos y no aceptar más conexiones aunque el proceso siga en marcha.
  • Ahorra tiempo en la detección de errores: podéis inspeccionar vuestros contenedores.
  • El sistema detecta errores que a una persona le costaría ver.
  • La comprobación se ejecuta a intervalos de segundos desde que arranca el contenedor. Si una comprobación se alarga más de la cuenta por cualquier motivo, se considera fallida.
FROM nginx
WORKDIR /usr/share/nginx/html
COPY . .
HEALTHCHECK --interval=10m --timeout=10s \
CMD curl --fail http://localhost/ || exit 1

En este caso se comprueba cada 10 minutos que el servidor web es capaz de servir la página en 10 segundos.

Consultad las comprobaciones de salud

Para ver el resultado de las comprobaciones, inspeccionad los contenedores levantados:

docker inspect --format='{{json .State.Health}}' $IDContenedor
{"Status":"healthy","FailingStreak":0,"Log":[{"Start":"2022-10-19T18:00:00.809087707Z","End":"2022-10-19T18:00:00.909087707Z","ExitCode":0,"Output":"Web test"}]}

En este caso se inspecciona el contenedor en formato JSON. Se ve que el estado es healthy y que muestra la salida de nuestra web.

Cread archivos con la sintaxis heredoc

  • BuildKit incorpora mejoras de rendimiento, de seguridad y más. Entre ellas, acepta la sintaxis heredoc, con la que lo complejo se vuelve sencillo: por ejemplo, crear archivos sin copiarlos al contenedor.
  • BuildKit es el motor de compilación por defecto desde Docker Engine 23.0; en versiones anteriores hay que activarlo con la variable de entorno DOCKER_BUILDKIT=1 al hacer el docker build.
  • Añadid también al principio del Dockerfile la línea # syntax=docker/dockerfile:1.
# syntax=docker/dockerfile:1
FROM alpine
RUN <<EOF
apk update
apk upgrade
EOF

En este caso, con la instrucción RUN, se actualiza el sistema.

# syntax=docker/dockerfile:1
FROM httpd
COPY <<EOF /usr/local/apache2/htdocs/index.html
<h1>¡Hello World!</h1>
<p>Test web</p>
EOF

En este caso se genera una web accesible escribiendo el código directamente en la imagen.

Cread montajes

RUN --mount permite crear montajes a los que el proceso de compilación puede acceder para hacer acciones. Por ejemplo, la compilación puede leer secretos, como credenciales de AWS, y subir contenido a S3 sin necesidad de variables de entorno a la vista.

Hay distintos tipos de montaje:

  • Bind: el montaje por defecto; enlaza directorios con permisos de solo lectura.
  • Cache: monta directorios temporales para la caché de compiladores y gestores de paquetes.
  • Secret: montaje para acceder a secretos.
  • SSH: permite que el contenedor acceda a las claves SSH a través del agente.

Ejemplos:

# syntax=docker/dockerfile:1
FROM python:3
RUN pip install awscli
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
  aws s3 cp test.txt s3://bucket/test.txt --expires 2022-10-31T20:30:00Z

En este caso se accede a un bucket de S3 mediante secretos y se copian archivos. El secreto se pasa al compilar, por ejemplo con docker build --secret id=aws,src=$HOME/.aws/credentials .

# syntax=docker/dockerfile:1
FROM alpine
RUN apk add openssh-client
RUN mkdir -pm 700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
RUN --mount=type=ssh \
ssh git@github.com 2>&1 | tee /dirname

En este caso, con el agente SSH, la compilación accede al destino y vuelca la salida con tee a un archivo. El agente se pasa al compilar con docker build --ssh default .

Usar secretos y montajes en lugar de copiar credenciales a la imagen es una de las cosas que reviso en la gestión de vulnerabilidades, y la compilación de imágenes forma parte de los pipelines que monto en infraestructura como código, GitOps y CI/CD. Si necesitáis algo, escribidme desde contacto.

Publicado originalmente en inglés en Medium.

Volver al blog

Contadnos vuestro caso

En una llamada gratuita de 20 minutos vemos dónde estáis y por dónde empezar. Sin compromiso.

Reservar llamada de 20 minutos
WhatsApp