Docker Multistage Build is a technique that optimizes Docker images by reducing their size and improving security. It achieves this by splitting the build process into multiple stages, copying only the necessary artifacts to the final image. This prevents unnecessary dependencies from being included in the final application version.
Benefits of Multistage Build
- Smaller image size: Only essential files are included in the final image.
- Improved security: Temporary dependencies and credentials used during the build are not copied to the final image.
- Optimized build time: Docker caching is better utilized, reducing compilation and deployment time.
Now, let’s see practical examples using Golang, Rust and Laravel.
Example for Golang
For Golang, we can use one stage to compile the binary and another to create a minimal final image.
# Stage 1: Build the application
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go mod tidy && go build -o app
# Stage 2: Minimal final image
FROM scratch
COPY --from=builder /app/app .
CMD ["./app"]
- The first stage compiles the source code.
- The second stage creates a minimal final image containing only the compiled binary.
Example For Laravel
Laravel requires an environment with PHP and its dependencies. With multistage Build, we can use one stage to install dependencies and another to create the final image.
# Stage 1: Build the application
FROM composer:latest AS builder
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --prefer-dist
COPY . .
# Stage 2: Final image
FROM php:8.2-fpm-alpine
WORKDIR /var/www/html
COPY --from=builder /app .
RUN chown -R www-data:www-data .
CMD ["php-fpm"]
This Dockerfile creates the image in two stages:
- The first stage installs composer dependencies.
- The second stage copies only the necessary files and sets up PHP-FPM
Example for Rust
Rust produces binary executables, so we can also compile in the first stage and run in a smaller final image.
# Stage 1: Build the application
FROM rust:1.76 AS builder
WORKDIR /usr/src/app
COPY . .
RUN cargo build --release
# Stage 2: Optimized final image
FROM scratch
COPY --from=builder /usr/src/app/target/release/meu-app .
CMD ["./meu-app"]
-
The first stage compiles Rust in release mode.
-
The second stage copies the binary to a scratch image, minimizing the final image size.
Docker Multistage Build is a great technique for optimizing and securing your images. By separating the build process into multiple stages, you can significantly reduce image size, enhance security, and streamline the deployment process. No matter what language you use, keeping build and execution separate ensures lightweight and efficient images.
For further reading on Dockerfile best practices, check out these great articles: