Best Practices for Writing Dockerfile: Clean and Efficient Containers
Use
multi-stage builds to keep images small, specify exact base image versions for consistency, and minimize layers by combining commands. Always use a non-root user and include a .dockerignore file to exclude unnecessary files.Syntax
A Dockerfile is a text file with instructions to build a Docker image. Key instructions include:
FROM: sets the base image.RUN: runs commands inside the image.COPYorADD: copies files into the image.CMDorENTRYPOINT: defines the container start command.USER: switches to a non-root user for security.
Each instruction creates a new layer, so combining commands reduces image size.
dockerfile
FROM ubuntu:22.04 RUN apt-get update && apt-get install -y curl COPY app /app USER appuser CMD ["/app/start.sh"]
Example
This example shows a multi-stage Dockerfile that builds a Go application and creates a small final image with only the binary.
dockerfile
FROM golang:1.20 AS builder WORKDIR /app COPY . . RUN go build -o myapp FROM debian:bullseye-slim RUN useradd -m appuser USER appuser COPY --from=builder /app/myapp /usr/local/bin/myapp CMD ["myapp"]
Common Pitfalls
Common mistakes include:
- Using
latesttag inFROM, causing unpredictable builds. - Running many
RUNcommands separately, increasing image size. - Running containers as root, which is a security risk.
- Not using
.dockerignore, which copies unnecessary files and slows builds.
dockerfile
### Wrong way:
FROM node:latest
RUN npm install
RUN npm run build
### Right way:
FROM node:18.16.0
RUN npm install && npm run build
USER node
# .dockerignore
node_modules
.git
DockerfileQuick Reference
- Always pin base image versions (avoid
latest). - Use multi-stage builds to reduce final image size.
- Combine commands with
&&to minimize layers. - Use a non-root user with
USERfor security. - Include a
.dockerignorefile to exclude unnecessary files. - Keep Dockerfile readable and well-commented.
Key Takeaways
Pin base image versions to ensure consistent builds.
Use multi-stage builds to keep images small and efficient.
Combine commands in one RUN to reduce image layers.
Run containers as a non-root user for better security.
Use a .dockerignore file to speed up builds and reduce image size.