Skip to content

Dockerfile Reference

This is a comprehensive reference for all Dockerfile instructions. A Dockerfile is a text document containing instructions that Docker reads to build an image automatically.

Syntax Overview

dockerfile
# Comment
INSTRUCTION arguments
  • Instructions are case-insensitive but conventionally written in UPPERCASE.
  • Instructions are executed in order, top to bottom.
  • Each instruction creates a new image layer (with some exceptions).
  • The first instruction must be FROM (or ARG before FROM).

Parser Directives

Parser directives must appear at the very top of the Dockerfile, before any other instruction or comment:

dockerfile
# syntax=docker/dockerfile:1
# escape=\

FROM node:20-alpine
...
DirectiveDescriptionExample
syntaxSets the Dockerfile frontend (BuildKit)# syntax=docker/dockerfile:1
escapeSets the escape character# escape=\ (default) or # escape= ` ``

FROM

Sets the base image for the build stage.

dockerfile
# Basic usage
FROM ubuntu:22.04

# With alias for multi-stage builds
FROM node:20-alpine AS builder

# With platform specification
FROM --platform=linux/amd64 golang:1.22-alpine

# Using an ARG variable
ARG BASE_IMAGE=node:20-alpine
FROM ${BASE_IMAGE}

# Start from nothing (for statically compiled binaries)
FROM scratch

FROM Options

OptionDescriptionExample
--platformTarget platform--platform=linux/amd64
AS nameName the build stageAS builder

RUN

Executes a command during the image build process.

dockerfile
# Shell form (runs in /bin/sh -c)
RUN apt-get update && apt-get install -y curl

# Exec form (runs directly, no shell processing)
RUN ["apt-get", "install", "-y", "curl"]

# Multi-line with line continuation
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        curl \
        git \
        vim && \
    rm -rf /var/lib/apt/lists/*

# Heredoc syntax (BuildKit, Dockerfile 1.4+)
RUN <<EOF
apt-get update
apt-get install -y curl git
rm -rf /var/lib/apt/lists/*
EOF

# With mount options (BuildKit)
RUN --mount=type=cache,target=/root/.npm npm ci
RUN --mount=type=secret,id=token TOKEN=$(cat /run/secrets/token) && use-token
RUN --mount=type=ssh git clone [email protected]:user/repo.git
RUN --mount=type=bind,source=.,target=/src make -C /src build
RUN --mount=type=tmpfs,target=/tmp make build

RUN Mount Types

TypePurposePersistsIn Image
cacheCache package managers✅ Between builds
secretSensitive build data
sshSSH agent forwarding
bindHost files during buildN/A
tmpfsTemporary build storage

RUN --network

dockerfile
# Run with no network access (security)
RUN --network=none pip install --no-deps -r requirements.txt

# Run with default network
RUN --network=default curl -o file.tar.gz https://example.com/file.tar.gz

# Run on host network
RUN --network=host curl http://localhost:8080/api

CMD

Sets the default command that is executed when a container starts. There can be only one CMD instruction per Dockerfile (the last one takes effect).

dockerfile
# Exec form (preferred)
CMD ["node", "server.js"]
CMD ["python", "-u", "app.py"]

# Shell form
CMD node server.js

# As default parameters for ENTRYPOINT
ENTRYPOINT ["python"]
CMD ["app.py"]

# The CMD can be overridden at runtime:
# docker run my-image custom-command

CMD vs ENTRYPOINT Interaction

No ENTRYPOINTENTRYPOINT execENTRYPOINT shell
No CMDError/ep/bin/sh -c /ep
CMD exec/cmd p1/ep /cmd p1/bin/sh -c /ep
CMD shell/bin/sh -c /cmd/ep /bin/sh -c /cmd/bin/sh -c /ep

ENTRYPOINT

Configures the container to run as an executable. Unlike CMD, ENTRYPOINT is not easily overridden.

dockerfile
# Exec form (preferred)
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["postgres"]

# The container always runs docker-entrypoint.sh
# CMD provides default arguments
# docker run my-postgres           → docker-entrypoint.sh postgres
# docker run my-postgres bash      → docker-entrypoint.sh bash

# Shell form (cannot receive CMD arguments)
ENTRYPOINT exec java -jar app.jar
bash
# Override entrypoint at runtime
docker run --entrypoint /bin/sh my-image

COPY

Copies files and directories from the build context (or a build stage) into the image.

dockerfile
# Basic file copy
COPY package.json .
COPY package.json /app/

# Copy multiple files
COPY package.json package-lock.json ./

# Copy directory contents
COPY src/ /app/src/

# With wildcard patterns
COPY *.json /app/
COPY hom?.txt /app/

# With ownership
COPY --chown=user:group files/ /app/

# From another build stage
COPY --from=builder /app/dist /srv/public

# From an external image
COPY --from=nginx:latest /etc/nginx/nginx.conf /etc/nginx/

# With chmod (BuildKit)
COPY --chmod=755 scripts/ /app/scripts/

# With link (BuildKit — creates hard links for better cache)
COPY --link package.json /app/

COPY Options

OptionDescriptionExample
--fromCopy from a named stage or image--from=builder
--chownSet file ownership (Linux only)--chown=1000:1000
--chmodSet file permissions--chmod=755
--linkUse hard link for better caching--link
--parentsPreserve parent directories--parents
--excludeExclude files matching patterns--exclude=*.test.js

ADD

Similar to COPY but with extra features: tar extraction and URL support.

dockerfile
# Copy files (same as COPY)
ADD app.js /app/

# Auto-extract tar archives
ADD archive.tar.gz /app/

# Download from URL
ADD https://example.com/file.txt /app/

# With checksum verification
ADD --checksum=sha256:abc123... https://example.com/file.txt /app/

# With permissions
ADD --chown=user:group --chmod=755 app.tar.gz /app/

WARNING

Prefer COPY over ADD unless you specifically need tar extraction or URL download. COPY is more transparent and predictable.

ENV

Sets environment variables that persist in the built image and running containers.

dockerfile
# Key-value syntax
ENV NODE_ENV=production
ENV DB_HOST=localhost DB_PORT=5432

# Legacy syntax (single variable)
ENV NODE_ENV production

# Use in subsequent instructions
ENV APP_HOME=/app
WORKDIR $APP_HOME
bash
# Override at runtime
docker run -e NODE_ENV=development my-image

ARG

Defines build-time variables that are only available during the image build.

dockerfile
# Define with default value
ARG NODE_VERSION=20
ARG BUILD_DATE

# Use in FROM
ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine

# ARG must be redeclared after FROM to be used in the stage
ARG APP_VERSION=1.0
RUN echo "Building version ${APP_VERSION}"
bash
# Override during build
docker build --build-arg NODE_VERSION=18 --build-arg BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) .

Predefined ARGs

ARGDescription
HTTP_PROXY / http_proxyHTTP proxy
HTTPS_PROXY / https_proxyHTTPS proxy
FTP_PROXY / ftp_proxyFTP proxy
NO_PROXY / no_proxyNo proxy list
BUILDKIT_INLINE_CACHEEnable inline cache
TARGETPLATFORMPlatform of the build target (e.g., linux/amd64)
TARGETOSOS of the target (e.g., linux)
TARGETARCHArchitecture of the target (e.g., amd64)
BUILDPLATFORMPlatform of the build host

WORKDIR

Sets the working directory for subsequent instructions.

dockerfile
# Absolute path
WORKDIR /app

# Relative path (relative to previous WORKDIR)
WORKDIR src
# Now in /app/src

# Using environment variables
ENV APP_HOME=/opt/myapp
WORKDIR $APP_HOME

EXPOSE

Documents the ports that the container listens on at runtime.

dockerfile
# Single port
EXPOSE 80

# Multiple ports
EXPOSE 80 443

# Specific protocol
EXPOSE 80/tcp
EXPOSE 53/udp

INFO

EXPOSE does not actually publish the port. Use -p flag at runtime to publish ports: docker run -p 8080:80 my-image.

VOLUME

Creates a mount point and marks it as holding externally mounted volumes.

dockerfile
# Single volume
VOLUME /data

# Multiple volumes
VOLUME ["/data", "/config"]

USER

Sets the user (and optionally group) for subsequent instructions and the running container.

dockerfile
# By name
USER appuser

# By UID
USER 1000

# By name with group
USER appuser:appgroup

# By UID:GID
USER 1000:1000

# Create user and switch
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

LABEL

Adds metadata to the image as key-value pairs.

dockerfile
LABEL maintainer="[email protected]"
LABEL version="1.0"
LABEL description="My application image"

# OCI standard labels
LABEL org.opencontainers.image.title="My App"
LABEL org.opencontainers.image.version="1.0.0"
LABEL org.opencontainers.image.description="Application description"
LABEL org.opencontainers.image.authors="[email protected]"
LABEL org.opencontainers.image.source="https://github.com/org/repo"
LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.created="2025-01-01T00:00:00Z"

HEALTHCHECK

Tells Docker how to test a container to check that it is still working.

dockerfile
# HTTP check
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD curl -f http://localhost:3000/health || exit 1

# TCP check
HEALTHCHECK CMD nc -z localhost 3000 || exit 1

# Custom script
HEALTHCHECK CMD /app/healthcheck.sh

# Disable health check (from base image)
HEALTHCHECK NONE
ParameterDefaultDescription
--interval30sTime between checks
--timeout30sCheck timeout
--start-period0sGrace period during startup
--start-interval5sInterval during start period
--retries3Failures before unhealthy

SHELL

Overrides the default shell used for shell-form commands.

dockerfile
# Default shell on Linux: ["/bin/sh", "-c"]
# Default shell on Windows: ["cmd", "/S", "/C"]

# Change to bash
SHELL ["/bin/bash", "-c"]
RUN echo "Using bash now"

# Change to PowerShell (Windows)
SHELL ["powershell", "-command"]
RUN Write-Output "Using PowerShell"

STOPSIGNAL

Sets the system call signal that will be sent to the container to stop it.

dockerfile
# Default is SIGTERM
STOPSIGNAL SIGTERM

# Use SIGQUIT for graceful shutdown
STOPSIGNAL SIGQUIT

# Numeric signal
STOPSIGNAL 9

ONBUILD

Adds a trigger instruction that executes when the image is used as a base for another build.

dockerfile
# In base image Dockerfile
FROM node:20-alpine
ONBUILD COPY package.json /app/
ONBUILD RUN npm install
ONBUILD COPY . /app/
WORKDIR /app

# When someone builds FROM this image:
# FROM my-base-image
# (ONBUILD instructions execute automatically)

Complete Production Dockerfile

dockerfile
# syntax=docker/dockerfile:1

# ==================================================
# Build Stage
# ==================================================
FROM node:20-alpine AS builder

ARG APP_VERSION=0.0.0

WORKDIR /app

COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci

COPY . .
RUN npm run build

# ==================================================
# Production Stage
# ==================================================
FROM node:20-alpine

LABEL org.opencontainers.image.title="My Application"
LABEL org.opencontainers.image.version="${APP_VERSION}"
LABEL org.opencontainers.image.source="https://github.com/org/repo"

RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app

COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
COPY --from=builder --chown=appuser:appgroup /app/package-lock.json ./

RUN --mount=type=cache,target=/root/.npm \
    npm ci --only=production && \
    npm cache clean --force

ENV NODE_ENV=production
ENV PORT=3000

USER appuser

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD wget -q --spider http://localhost:${PORT}/health || exit 1

EXPOSE ${PORT}

CMD ["node", "dist/server.js"]

Next Steps

基于 MIT 许可发布