Dockerfile Keywords Explained & Interview Nuggets 🐳
A deep dive into Dockerfile directives, build vs. runtime mechanics, caching performance, security guardrails, and must-know interview trade-offs.
Published by AHP • cicdclouds.com
1. Image Inception & Metadata Directives
A Dockerfile is a declarative configuration file containing sequential commands evaluated by the container build engine (such as Docker Engine or BuildKit) to assemble an immutable container image. Every build context begins by establishing a base operating system lineage and assigning descriptive operational metadata.
1. FROM — Base Image Definition
- Defines the primary foundational platform or parent operating system layer for the build stage.
- Every valid
Dockerfilemust start with aFROMinstruction (the only exception being an initialARGused to dynamically set variable base image tags). - For minimal, bare-metal microservice builds with zero operating system overhead (such as compiled Go or Rust binaries), use
FROM scratch.
# Syntax example with build stage alias
FROM ubuntu:22.04 AS base-environment
2. MAINTAINER (Deprecated)
- Historically assigned the author or operational contact details for the image.
- Modern Practice: Fully superseded by the generic
LABELdirective for key-value flexibility and schema standardization.
# Deprecated syntax:
# MAINTAINER devops@cicdclouds.com
# Modern standard:
LABEL maintainer="devops@cicdclouds.com"
3. LABEL — Object Metadata
- Appends structured metadata, versioning tags, team ownership, and architectural details to the final image inspection record.
- Labels are queryable via
docker inspectand can be parsed programmatically across automated CI/CD security and governance pipelines.
LABEL version="2.4.0" \
description="Production API Gateway" \
environment="production" \
team="PlatformOps"
2. Build-Time Processing & Filesystem Population
These directives manipulate files and execute operating system commands strictly during image compilation (docker build), committing intermediary read-only filesystem layers into the local storage driver.
4. RUN — Build-Time Execution
- Executes system-level commands, runs package managers, compiles source code, creates directories, and alters the target image filesystem.
- Each
RUNstatement creates an intermediate cacheable layer. In production Dockerfiles, chain related commands with&&and remove package installer caches within the same instruction to minimize overall image size.
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
5. COPY — Host-to-Container Ingestion
- Transfers files or directories directly from the local build context on the host machine into the target image filesystem.
- Provides a transparent, deterministic copy mechanism with support for user ownership flags (
--chown) and multi-stage extraction (--from).
COPY --chown=appuser:appgroup ./config.yaml /app/config.yaml
6. ADD — Advanced Ingestion & Extraction
- Performs host-to-image file copying similar to
COPY, but provides two specialized automation features:- Automatic Archive Extraction: Unpacks local tar archives (
.tar,.tar.gz,.tgz) directly into destination image directories. - Remote URL Downloads: Retrieves files straight from remote HTTP/HTTPS endpoints into the container layer.
- Automatic Archive Extraction: Unpacks local tar archives (
# Automatically unpacks compressed archive into /opt/bin/
ADD application-dist.tar.gz /opt/bin/
⚡ Interview Goldmine:
COPYvs.ADDRule of ThumbAlways default to
COPYfor local files and project dependencies.COPYis explicit, transparent, and avoids unexpected tar auto-extraction or security risks associated with unverified remote files. ReserveADDexclusively when native archive decompression is explicitly intended.
3. Variables, Scoping & Shell Configuration
7. ARG — Build-Time Parameters
- Defines variables passed into the build process using the CLI flag
--build-arg <varname>=<value>. - Ephemeral: Does not persist into running containers or the final inspected image environment. Never store sensitive build tokens or private SSH keys directly in
ARG; use BuildKit secrets instead.
ARG APP_VERSION=1.0.0
RUN echo "Compiling binaries for release v${APP_VERSION}"
8. ENV — Runtime Environment Variables
- Sets environment variables that persist both during build layers and across the container's operational lifetime at runtime.
- Variables set by
ENVare inherited by all child processes and inspectable viadocker inspectordocker exec -it <container> env.
ENV APP_PORT=8080 \
APP_ENV=production \
LOG_LEVEL=warn
9. SHELL — Default Execution Interpreter
- Changes the default shell executable and flags used by subsequent
RUNcommands in the Dockerfile. - The default Linux shell is
["/bin/sh", "-c"]. Overriding to bash enables flags likepipefail, ensuring commands inside piped chains fail immediately on errors.
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
4. Port Declarations, Volumes & Security Hardening
10. EXPOSE — Network Port Documentation
- Declares the intended incoming network ports the containerized service listens on.
- Informational:
EXPOSEacts as architectural documentation between image builders and operators; it does not open or publish ports to the host network interface unless explicitly mapped via-por-Pat runtime.
EXPOSE 8080 8443
11. USER — Least Privilege Enforcement
- Defines the UID/GID or username running subsequent build instructions and the final container runtime process.
- Production Security Standard: Never run container workloads as
root. Always declare and switch to a non-privileged user to mitigate potential container breakout vulnerabilities.
RUN groupadd -r appgroup && useradd -r -g appgroup -u 10001 appuser
USER appuser
12. VOLUME — Persistent & Shared Storage Points
- Declares an externally managed mount point inside the container image.
- Anything written to a
VOLUMEpath bypasses the temporary copy-on-write (CoW) container storage layer, ensuring persistent storage management and maximum I/O throughput.
VOLUME ["/var/log/app", "/data/storage"]
13. STOPSIGNAL — Graceful Termination Signals
- Configures the exact system call interrupt signal sent to the container process when issuing
docker stop(default isSIGTERM). - Essential for services like NGINX (
SIGQUIT) to finish processing active client sessions before closing sockets.
STOPSIGNAL SIGQUIT
5. Runtime Process Initialization: CMD vs. ENTRYPOINT
Determining how a container launches its primary process (PID 1) is one of the most frequently asked concepts in DevOps technical evaluations.
14. CMD — Default Command or Arguments
- Supplies default parameters or a default fallback command for a container.
- Easily overridden by passing arbitrary arguments at the end of the runtime command:
docker run <image> <override-command>.
CMD ["python3", "server.py"]
15. ENTRYPOINT — The Fixed Binary / Executable
- Configures a permanent executable target that container invocations run against.
- Cannot be overridden simply by appending CLI arguments (requires the explicit
--entrypointflag).
ENTRYPOINT ["python3", "server.py"]
The Recommended Synergy: Executable + Default Argument
Industry-standard microservice design pairs ENTRYPOINT as the non-negotiable executable and CMD as the overridable default arguments:
# Container behaves like an executable binary CLI tool
ENTRYPOINT ["python3"]
CMD ["app.py"]
Running docker run my-python-app defaults to executing python3 app.py. Passing custom arguments like docker run my-python-app test.py dynamically executes python3 test.py without breaking the wrapper!
6. ⚡ Quick Interview Comparison Tables
Keep these architectural distinctions top of mind for cloud and platform engineering interviews.
Comparison Matrix 1: COPY vs. ADD
| Feature / Property | COPY |
ADD |
|---|---|---|
| Local Filesystem Copying | ✅ Yes (Host to container) | ✅ Yes (Host to container) |
| Tar Auto-Extraction | ❌ No (Copies archive as-is) | ✅ Yes (Automatically decompresses recognized archives) |
| Remote URL Download | ❌ No | ✅ Yes (Downloads remote files into layer) |
| Build Cache Predictability | High (Strict file checksum verification) | Moderate (Remote file changes can invalidate cache unexpectedly) |
| DevOps Best Practice | Preferred Standard for all standard app assets | Restricted strictly to automatic compressed tar extractions |
Comparison Matrix 2: CMD vs. ENTRYPOINT
| Feature / Property | CMD |
ENTRYPOINT |
|---|---|---|
| Core Purpose | Provides overridable defaults for the container. | Defines the fixed, immutable executable (PID 1). |
| CLI Argument Override | Effortless: Directly superseded by any CLI argument passed to docker run. |
Strict: CLI arguments are appended as positional parameters to the executable. |
| Hard Override Mechanism | docker run <image> <new-cmd> |
Requires explicit flag: docker run --entrypoint <new-bin> <image> |
| CLI Tool Behavior | Acts like an arbitrary task runner or script. | Transforms the container into a self-contained executable utility. |
Comparison Matrix 3: ARG vs. ENV
| Aspect | ARG |
ENV |
|---|---|---|
| Scope Lifetime | Build-time only (during docker build). |
Build-time AND Runtime (during docker run). |
| Persistence in Image | ❌ No (Discarded after image layers compile). | ✅ Yes (Persists across all derived containers). |
| Runtime Modification | N/A (Unavailable at runtime). | Overridable via docker run -e KEY=VAL. |
| Typical Use Cases | Specifying package versions, build tokens, and compilation flags. | Database endpoints, port configurations, and application profiles. |
7. Production Pitfalls & Troubleshooting Guide
Building reliable container images requires mastering caching behavior and lifecycle signals. Here are the three most common production failures and how to avoid them:
1. The Shell Form vs. Exec Form Signal Trap (PID 1 Zombie Processes)
When specifying CMD or ENTRYPOINT, Docker allows two distinct syntax formats:
- Exec Form (Recommended):
["executable", "param1", "param2"]— Runs the executable directly as PID 1. It directly receives UNIX termination signals (SIGTERM,SIGINT), enabling clean application shutdowns and connection draining. - Shell Form (Avoid in Production):
command param1 param2— Evaluated as/bin/sh -c "command param1". The shell becomes PID 1, and your application runs as a child process. Most shells do not forward signals to child processes, causing containers to hang untilSIGKILLforces a hard termination after 10 seconds.
2. Build Cache Invalidation Pitfall
Docker evaluates caching from top to bottom. If any step invalidates the cache, all subsequent steps must re-execute:
# ❌ BAD: Invalidates cache on every single code change
COPY . /app
RUN npm install
# ✅ GOOD: Dependencies are cached until package.json changes
COPY package*.json /app/
RUN npm install
COPY . /app
3. Secret Leakage in Image Layers
Deleting a sensitive file in a subsequent RUN instruction does not remove it from previous image layers. Anyone running docker history or inspecting image blobs can extract raw secrets. Always use multi-stage builds or BuildKit secret mounts (RUN --mount=type=secret) to handle tokens securely.