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 .
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"
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"]
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
--------------------
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
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.
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 |