Best Practices for Writing Efficient Dockerfiles
This article presents a concise Dockerfile template, explains how to build efficient images by minimizing layers, leveraging caches, using multi‑stage builds, and addresses common pitfalls such as over‑caching, proper use of ARG/ENV, COPY vs ADD, and CMD/ENTRYPOINT configurations.
In the container ecosystem, Docker's image format has become the de‑facto standard, and writing a clean Dockerfile is essential for fast, reliable builds. This article adapts Docker's official "Best practices for writing Dockerfiles" and provides a streamlined version.
Simple Dockerfile Reference Template
The official Dockerfile reference contains about 20 instructions, but most projects use fewer than 10. Below is a concise template that covers the majority of use cases.
FROM base_image:tag # reference base image *required*
ARG arg_key[=default_value1] # declare variable
ENV env_key=value2 # declare environment variable
# Build almost immutable parts (directory structure, build‑time dependencies)
COPY src dst
RUN command1 && command2 ...
WORKDIR /path/to/work/dir # set work directory
# Build less‑changing parts (application dependencies)
COPY src dst
RUN command3 && command4 ...
# Build frequently changing parts (application compilation)
COPY src dst
RUN command5 && command6 ...
# Container entry point *required*
ENTRYPOINT ["/entry.app"] # default executable
CMD ["--options"] # default argumentsEfficient Image Lifecycle
Containers are designed for rapid iteration, so each stage of image handling should be as simple and efficient as possible.
1. Image Build
Trim context : Exclude unnecessary files from the build context.
Multi‑stage images : Separate stable base layers from application‑specific layers.
Leverage build cache : Organize instructions by change frequency to maximize cache hits.
Reduce layers : Combine multiple RUN commands with && to limit layer creation.
Use multi‑stage builds : Detailed later.
2. Image Pull
Docker documents storage drivers; understanding layers helps accelerate pulls:
Image layers are read‑only and shared across containers.
Container layers are writable and use copy‑on‑write.
Speed‑up strategies include reusing existing base layers, pulling only changed layers, and pre‑warming images during idle periods.
Common Issues
1. Instruction Independence
# Incorrect: separate RUN commands lose the working directory
RUN cd /some/dir
RUN bash script.sh
# Correct alternatives
RUN cd /some/dir && bash script.sh
RUN bash /some/dir/script.sh2. Over‑caching
Each instruction creates a cacheable layer; modifying a later line may not trigger re‑execution of earlier cached steps, leading to outdated packages.
# Recommended apt‑get usage
RUN apt-get update && apt-get install -y \
curl \
nginx=1.16.* && \
rm -rf /var/lib/apt/lists/*3. ARG vs ENV
ARG before FROM can only be used in that FROM line; later usage requires redeclaration.
ARG is build‑time only; ENV persists in the final image.
CMD and ENTRYPOINT cannot reference ARG or ENV.
If ARG and ENV share a name, ENV overrides ARG.
ENV creates a layer; unsetting it does not remove the layer.
# Example showing ENV layer persistence
FROM alpine
ENV ADMIN_USER="mark" # creates a layer
RUN echo $ADMIN_USER > ./mark
RUN unset ADMIN_USER # only removes build‑time variable, layer remains4. COPY vs ADD
Prefer COPY for straightforward file copying. Use ADD only when you need automatic tar extraction or remote URL fetching.
Specify trailing slashes to control whether the source directory itself or its contents are copied.
Source must reside within the build context; ../ is disallowed.
5. CMD and ENTRYPOINT
CMDsets the default command when the container starts. ENTRYPOINT can replace CMD entirely.
When both are present, CMD provides default arguments to ENTRYPOINT.
Prefer the exec form (JSON array) to avoid an extra shell process.
Example combinations are illustrated in the accompanying diagram.
6. Multi‑Stage Builds
Docker 17.05+ supports multi‑stage builds, allowing separate stages for building and runtime, dramatically reducing final image size.
# Multi‑stage example
FROM base_image:tag AS builder
ARG arg_key[=default_value1]
ENV env_key=value2
COPY src dst
RUN command1 && command2 ...
WORKDIR /path/to/work/dir
COPY src dst
RUN command3 && command4 ...
COPY src dst
RUN compile_entry_app
FROM base_image:tag
COPY --from=builder /path/to/work/dir/entry.app .
ENTRYPOINT ["/entry.app"]
CMD ["--options"]By copying only the compiled binary and its runtime dependencies from the builder stage, the final image remains lean and secure.
NetEase Game Operations Platform
The NetEase Game Automated Operations Platform delivers stable services for thousands of NetEase titles, focusing on efficient ops workflows, intelligent monitoring, and virtualization.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
