Lesser Known Dockerfile Instructions

👋 Hi! I’m Bibin Wilson. In each edition, I share practical tips, guides, and the latest trends in DevOps and MLOps to make your day-to-day DevOps tasks more efficient. If someone forwarded this email to you, you can subscribe here to never miss out!

Most developers are familiar with common instructions like FROM, RUN, CMD, COPY, and EXPOSE, but there are other powerful yet lesser-known instructions.

In this edition we will explore some lesser-known but useful Dockerfile instructions. I have also added info on how these instructions behave when the images are deployed in Kubernetes.

Let’s get started.

1. SHELL

The SHELL instruction lets you change the default shell used for commands run in RUN instructions.

By default, Docker uses sh -c. However, you can switch to other shells such as PowerShell on Windows or bash for Linux.

SHELL ["/bin/bash", "-c"]
RUN echo "Using Bash shell now!"

The SHELL command in a Dockerfile impacts how commands are run during image build and in the container by default.

Kubernetes generally bypasses the Dockerfile’s SHELL setting unless you explicitly configure the pod's command or args to use it.

2. HEALTHCHECK

The HEALTHCHECK instruction helps monitor your container's health.

It allows you to specify a command that Docker will run with a specific interval to check if the container is functioning correctly.

Here is an example.

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD curl --fail http://localhost/ || exit 1

The above instruction ensures the container runs smoothly by checking the specified endpoint every 30 seconds. If the health check fails, Docker will mark the container as unhealthy.

This instruction only shows if the container is healthy or unhealthy. There is no default restart if the container becomes unhealthy.

HEALTHCHECK is mainly beneficial in scenarios where Docker itself is responsible for monitoring the container’s health.

Kubernetes ignores Docker HEALTHCHECK instructions. Instead, Kubernetes uses its own probe mechanisms (Liveness, Readiness and Startup Probes)

3. STOPSIGNAL

The STOPSIGNAL instruction sets the system call signal that will be sent to the container to stop it.

SIGTERM and SIGKILL are Linux concepts for managing processes:

SIGTERM requests graceful termination with cleanup, while SIGKILL forcefully stops a process immediately without cleanup.

By default, Docker uses SIGKILL, which forcefully terminates the container without giving the application time to clean up.

Changing this to SIGTERM or another signal can allow for a graceful shutdown, where the application has time to save state and release resources.

For example,

STOPSIGNAL SIGTERM

When Kubernetes needs to terminate a pod, it first sends a SIGTERM signal to all containers in the pod, regardless of the STOPSIGNAL specified in Docker.

The container will have terminationGracePeriodSeconds (default 30 seconds) to shut down gracefully.

If the container hasn't stopped within this grace period, Kubernetes will send a SIGKILL signal, which cannot be caught or ignored.

4. ONBUILD

The ONBUILD instruction sets triggers that are executed when the image is used as a base for other images. You can compare this to a startup script in a VM image, which runs automatically when the VM is started with that image.

For example,

ONBUILD COPY requirements.txt /app/
ONBUILD RUN pip install --no-cache-dir -r requirements.txt
ONBUILD COPY . /app

When another Dockerfile uses the flask-base:1.0 image as its base, the ONBUILD instructions will automatically execute. This eliminates the need to duplicate steps like copying the requirements.txt file, installing dependencies, and copying application files to the /app directory in every Dockerfile used by different teams.

Practical Example

The following Dockerfile includes all the instructions we discussed above. You can test it with a simple Flask app and a corresponding requirements.txt file.

FROM python:3.11-slim

WORKDIR /app

RUN apt-get update && apt-get install -y --no-install-recommends \
    curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

SHELL ["/bin/bash", "-c"]

EXPOSE 5000

STOPSIGNAL SIGTERM

ONBUILD COPY requirements.txt /app/
ONBUILD RUN pip install --no-cache-dir -r requirements.txt
ONBUILD COPY . /app

HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD curl --fail http://localhost:5000/ || exit 1

CMD ["python", "app.py"]

Reply

or to participate.