DEV Community

Abhay Singh Kathayat
Abhay Singh Kathayat

Posted on

Streamline Your Docker Images with Multi-Stage Builds

Multi-Stage Builds in Docker: Optimizing Your Docker Images

Multi-stage builds in Docker allow you to create lean and optimized images by using multiple FROM statements in a single Dockerfile. This approach is particularly useful for building applications where you need tools or dependencies during the build process but donโ€™t want them included in the final image.


Why Use Multi-Stage Builds?

  1. Smaller Image Size:

    By separating the build environment from the runtime environment, you only include the necessary artifacts in the final image.

  2. Improved Security:

    Excluding build-time dependencies reduces attack surfaces in your image.

  3. Cleaner Workflow:

    Consolidates multiple build steps into a single Dockerfile, reducing complexity.


How Multi-Stage Builds Work

A multi-stage build uses multiple stages, each defined by a FROM statement. Intermediate stages can compile code, install dependencies, or run tests, while the final stage packages the application.


Example: Node.js Application

Hereโ€™s a Dockerfile for a Node.js application using multi-stage builds:

# Stage 1: Build
FROM node:16 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Stage 2: Production
FROM node:16-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
COPY package*.json ./
RUN npm install --only=production
EXPOSE 3000
CMD ["node", "dist/index.js"]
Enter fullscreen mode Exit fullscreen mode

Breaking Down the Example

  1. Build Stage (FROM node:16 AS build):

    • Installs all dependencies.
    • Builds the application using npm run build.
    • Produces the compiled artifacts in the dist folder.
  2. Production Stage (FROM node:16-alpine):

    • Copies the compiled files from the build stage.
    • Installs only production dependencies using --only=production.
    • Creates a lightweight production image.

Another Example: Go Application

For a Go application, you might have:

# Stage 1: Build
FROM golang:1.18 AS build
WORKDIR /app
COPY . .
RUN go build -o myapp

# Stage 2: Production
FROM alpine:latest
WORKDIR /app
COPY --from=build /app/myapp .
EXPOSE 8080
CMD ["./myapp"]
Enter fullscreen mode Exit fullscreen mode

Advantages of Multi-Stage Builds

  1. Reduced Image Size:

    • Intermediate layers (like build tools) are excluded from the final image.
  2. Simplified CI/CD Pipelines:

    • Combine build and deployment steps in a single file.
  3. Improved Performance:

    • Smaller images lead to faster pull and deploy times.
  4. Cleaner Development:

    • Developers can include debugging tools in build stages without affecting production.

Best Practices

  1. Minimize Build Tools in Final Images:

    Use lightweight base images like alpine for production stages.

  2. Use AS for Naming Stages:

    Name each stage to make your Dockerfile more readable and maintainable.

  3. Leverage Caching:

    Reorder commands to optimize Docker layer caching.

  4. Copy Only Needed Artifacts:

    Avoid copying unnecessary files to the final image.


Use Cases for Multi-Stage Builds

  1. Compiling Code:

    Ideal for languages like Go, Java, or C++ where you need a build environment.

  2. Frontend Applications:

    Build React, Angular, or Vue applications in one stage and serve them using Nginx in the final stage.

  3. Testing:

    Run unit tests in one stage and build the final image only if tests pass.


Stay Connected

Follow me for more Docker tips and insights:

Feel free to connect and share your Docker experiences!

Top comments (0)