What is Docker Build Check and what problem does it solve?

Ajeet Singh Raina - Aug 8 - - Dev Community

Docker has become an indispensable tool for developers to package and deploy applications. A crucial aspect of efficient Docker development is ensuring the correctness of your Dockerfile. This is where Docker Build Checks come into play.

Typically, when you run a build, Docker executes the build steps in your Dockerfile and build options as specified. With build checks, rather than executing the build steps, Docker checks the Dockerfile and options you provide and reports any issues it detects.

Is Docker Build Check a new feature?

Yes. Docker Build Checks is a feature introduced in Dockerfile 1.8 that allows you to validate your build configuration without actually executing the build. By running docker build --check ., you can identify potential issues in your Dockerfile early in the development process, saving time and effort.

How does it work?

Checks run as a build invocation, but instead of producing a build output, it performs a series of checks to validate that your build doesn't violate any of the rules.

You can use the --check flag with the docker build or docker buildx build command to run the checks.

For Example,

$ docker build --check .
Enter fullscreen mode Exit fullscreen mode

This command will run the checks and report any issues it finds without executing the build steps. If there are any issues, they will be reported in the output.

Sample App: Flask + Python

The provided Python script creates a basic web application that displays the number of times it has been accessed. It utilizes Flask for the web framework and Redis to store the visit count.

How it Works?

When someone accesses the root URL (e.g., http://localhost:5000), the hello function is triggered. The function increments the 'hits' counter in Redis. It then retrieves the current value of 'hits' and displays it in a user-friendly message.

File: app.py

cat app.py 
from flask import Flask
from redis import Redis
import os
import socket

app = Flask(__name__)
redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)


@app.route('/')
def hello():
    redis.incr('hits')
    return f"This webpage has viewed {redis.get('hits').decode('utf-8')} times and hostname is {socket.gethostname()}.\n"
Enter fullscreen mode Exit fullscreen mode

Let's create a Dockerfile for this app.py

FROM python:3.11-slim

RUN pip3 install flask redis && \
    groupadd -r demouser && useradd -r -g demouser demouser && \
    mkdir /src && \
    chown -R demouser:demouser /src

USER demouser

COPY app.py /src/app.py

WORKDIR src

ENV FLASK_APP=app.py REDIS_HOST=redis

EXPOSE 5000

CMD ["flask", "run", "-h", "0.0.0.0"]
Enter fullscreen mode Exit fullscreen mode

Let's try to run docker build --check

 [internal] load build definition from Dockerfile                            0.0s
 => => transferring dockerfile: 398B                                            0.0s
 => [internal] load metadata for docker.io/library/python:3.11-slim             2.8s
 => [auth] library/python:pull token for registry-1.docker.io                   0.0s
 => [internal] load .dockerignore                                               0.0s
 => => transferring context: 2B                                                 0.0s

WARNING: WorkdirRelativePath - https://docs.docker.com/go/dockerfile/rule/workdir-relative-path/
Relative workdir "src" can have unexpected results if the base image changes
Dockerfile:12
--------------------
  10 |     COPY app.py /src/app.py
  11 |     
  12 | >>> WORKDIR src
  13 |     
  14 |     ENV FLASK_APP=app.py REDIS_HOST=redis
--------------------
Enter fullscreen mode Exit fullscreen mode

The issue is clearly related to https://docs.docker.com/reference/build-checks/workdir-relative-path/

Modify the following line in your Dockerfile to:

WORKDIR /src
Enter fullscreen mode Exit fullscreen mode
 docker build --check .
[+] Building 3.2s (4/4) FINISHED                                docker:desktop-linux
 => [internal] load build definition from Dockerfile                            0.0s
 => => transferring dockerfile: 399B                                            0.0s
 => [internal] load metadata for docker.io/library/python:3.11-slim             3.1s
 => [auth] library/python:pull token for registry-1.docker.io                   0.0s
 => [internal] load .dockerignore                                               0.0s
 => => transferring context: 2B                                                 0.0s
Check complete, no warnings found.
Enter fullscreen mode Exit fullscreen mode

BuildKit has built-in support for analyzing your build configuration based on a set of pre-defined rules for enforcing Dockerfile and building best practices. Adhering to these rules helps avoid errors and ensures good readability of your Dockerfile.

Common Dockerfile Warnings

Warning Code Description
stage-name-casing Stage names should be lowercase
from-as-casing The 'as' keyword should match the case of the 'from' keyword
no-empty-continuation Empty continuation lines will become errors in a future release
consistent-instruction-casing All commands within the Dockerfile should use the same casing (either upper or lower)
duplicate-stage-name Stage names should be unique
reserved-stage-name Reserved words should not be used as stage names
json-args-recommended JSON arguments recommended for ENTRYPOINT/CMD to prevent unintended behavior related to OS signals
maintainer-deprecated The MAINTAINER instruction is deprecated, use a label instead to define an image author

References:

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .