Skip to content
BotServBotServ
DockerDockerfileBest PracticesLayerCache

Write and Optimize Dockerfiles

Dockerfile guide for beginners and advanced users. Best practices, layers, caching, and security.

S

schutzgeist

3 min read
Write and Optimize Dockerfiles

Writing and Optimizing Dockerfiles

What this article covers

  • Structure of a Dockerfile.
  • Key instructions and their order.
  • Layers, caching, and image size.
  • Security and clean builds.
  • Common pitfalls and solutions.

Introduction: Writing and Optimizing Dockerfiles

A Dockerfile is the recipe for a Docker image. It specifies which base image to use, which files to copy, which commands to run, and how the container starts. A well-written Dockerfile produces small, secure images that build quickly. A poorly written one leads to long build times, bloated images, and security vulnerabilities.

This article covers the fundamentals, key instructions, and best practices for clean Dockerfiles.

Key Terms

  • FROM: Base image.
  • RUN: Execute a command.
  • COPY: Copy files.
  • ADD: Copy and extract files.
  • CMD: Default command at startup.
  • ENTRYPOINT: Fixed startup command.
  • WORKDIR: Working directory.
  • ENV: Environment variable.
  • EXPOSE: Declare a port.
  • USER: Switch user.
  • Layer: A layer in the image.
  • Cache: Build cache.

Basic Structure

FROM node:20-slim

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

USER node

EXPOSE 3000

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

Choosing FROM

ImageSizeUse Case
ubuntulargeCompatibility
debian:slimmediumVersatile
alpinesmallMinimal, but musl-based
distrolessvery smallMinimal, no shell

Recommendation: Use official slim images or distroless for production containers.

Mind the Order

Docker caches layers. Copy files that change infrequently first:

  1. Base image.
  2. Dependency files.
  3. Install dependencies.
  4. Copy source code.
  5. Build steps.
  6. Runtime command.

Wrong:

COPY . .
RUN npm ci

Right:

COPY package*.json ./
RUN npm ci
COPY . .

COPY vs ADD

  • COPY simply copies files.
  • ADD can handle URLs and tar archives.
  • In most cases, COPY is safer and more predictable.

Minimize Layers

Each RUN, COPY, and ADD instruction creates a layer. Fewer layers mean smaller images:

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

Reduce Image Size

  • Use .dockerignore.
  • Install only production dependencies.
  • Remove build tools.
  • Use multistage builds.
  • Don’t copy unnecessary files.

Example .dockerignore:

node_modules
.git
.env
Dockerfile
README.md
tests

Security

  • Run as a non-root user:
RUN useradd -m appuser
USER appuser
  • Never embed secrets in the Dockerfile.
  • Don’t store passwords in environment variables.
  • Keep permissions minimal.
  • Use read-only filesystems when possible.

CMD and ENTRYPOINT

CMD is the default command; ENTRYPOINT is the fixed command. Combined:

ENTRYPOINT ["node"]
CMD ["server.js"]

Healthchecks

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

Build Command

docker build -t mein-image:1.0 .

Force Rebuild Without Cache

docker build --no-cache -t mein-image:1.0 .

Logs and Configuration

  • Output logs to stdout/stderr.
  • Pass configuration via environment variables.
  • Don’t hardcode paths in images.

Common Pitfalls

  • Everything in one layer: creates bloated images.
  • Build tools in the runtime image: security risks.
  • Secrets in environment variables: visible in images or logs.
  • Wrong FROM version: using latest instead of fixed tags.
  • Missing .dockerignore: unnecessary files end up in the image.
  • Wrong permissions: container runs as root.
  • CMD in shell form: signals don’t propagate correctly.

Further Reading and Resources

FAQ: Dockerfile

What is a Dockerfile? A text file containing instructions to build a Docker image.

Should I use COPY . .? Only with a .dockerignore in place, otherwise unnecessary files end up in the image.

What’s better: Alpine or Debian Slim? Debian Slim is simpler and more compatible; Alpine is smaller but musl-based.

How do I speed up the build? Pay attention to layer order, leverage caching, and set up .dockerignore.

Why use a non-root user? It reduces risk if a container is compromised.

Sources and Further Reading

Summary: Writing and Optimizing Dockerfiles

A good Dockerfile is key to fast builds, small images, and secure containers. The right order of instructions, effective caching, multistage builds, .dockerignore, non-root users, and fixed image tags are essential. Following these principles helps you avoid common mistakes and build Docker images that work well in homelabs and production alike.

Back to Blog
Share:

Related Posts