Home / Docker & Containers
DevOps & Containerization Guide

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 Dockerfile must start with a FROM instruction (the only exception being an initial ARG used 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 LABEL directive 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 inspect and 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 RUN statement 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:
    1. Automatic Archive Extraction: Unpacks local tar archives (.tar, .tar.gz, .tgz) directly into destination image directories.
    2. Remote URL Downloads: Retrieves files straight from remote HTTP/HTTPS endpoints into the container layer.
# Automatically unpacks compressed archive into /opt/bin/
ADD application-dist.tar.gz /opt/bin/

⚡ Interview Goldmine: COPY vs. ADD Rule of Thumb

Always default to COPY for local files and project dependencies. COPY is explicit, transparent, and avoids unexpected tar auto-extraction or security risks associated with unverified remote files. Reserve ADD exclusively 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 ENV are inherited by all child processes and inspectable via docker inspect or docker 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 RUN commands in the Dockerfile.
  • The default Linux shell is ["/bin/sh", "-c"]. Overriding to bash enables flags like pipefail, 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: EXPOSE acts as architectural documentation between image builders and operators; it does not open or publish ports to the host network interface unless explicitly mapped via -p or -P at 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 VOLUME path 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 is SIGTERM).
  • 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 --entrypoint flag).
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 until SIGKILL forces 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.