0
0
Dockerdevops~5 mins

Builder pattern before multi-stage in Docker - Commands & Configuration

Choose your learning style9 modes available
Introduction
Sometimes, building a Docker image requires compiling code or preparing files before creating the final image. Before Docker had multi-stage builds, developers used the builder pattern to separate the build steps into different images to keep the final image small and clean.
When you need to compile source code before running your app in a Docker container.
When you want to keep your final Docker image small by excluding build tools.
When your Docker version does not support multi-stage builds.
When you want to reuse a build image for multiple final images.
When you want to separate build and runtime environments clearly.
Config File - Dockerfile
Dockerfile
FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

FROM alpine:3.18
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]

The first part uses the official Go image to build the app. It copies the source code and runs the build command.

The second part uses a small Alpine Linux image and copies only the built binary from the builder image. This keeps the final image small and clean.

Commands
This command builds the Docker image using the Dockerfile. It creates the builder image that compiles the app and then the final image with the compiled binary.
Terminal
docker build -t myapp-builder -f Dockerfile .
Expected OutputExpected
[+] Building 10.5s (8/8) FINISHED => [internal] load build definition from Dockerfile 0.1s => => transferring dockerfile: 123B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/golang:1.20 1.2s => [builder 1/4] FROM docker.io/library/golang:1.20 1.2s => [builder 2/4] WORKDIR /app 0.1s => [builder 3/4] COPY . . 0.5s => [builder 4/4] RUN go build -o myapp 8.3s => [final 1/3] FROM docker.io/library/alpine:3.18 0.5s => [final 2/3] WORKDIR /app 0.1s => [final 3/3] COPY --from=builder /app/myapp . 0.1s => exporting to image 0.3s => => exporting layers 0.3s => => writing image sha256:abcdef1234567890 0.0s => => naming to docker.io/library/myapp-builder
-t - Assigns a name and optionally a tag to the image.
-f - Specifies the Dockerfile to use.
Runs the final image to verify the built application works as expected.
Terminal
docker run --rm myapp-builder
Expected OutputExpected
Hello from myapp!
--rm - Automatically removes the container after it exits.
Lists all Docker images to confirm the builder and final images exist.
Terminal
docker images
Expected OutputExpected
REPOSITORY TAG IMAGE ID CREATED SIZE myapp-builder latest abcdef123456 10 seconds ago 25MB
Key Concept

If you remember nothing else from this pattern, remember: use a separate build image to compile your app and copy only the final artifact into a small runtime image.

Common Mistakes
Copying source code directly into the final image instead of the built binary.
This makes the final image large and includes unnecessary build tools and files.
Use the builder pattern to build in one image and copy only the compiled binary to the final image.
Not specifying the correct Dockerfile with -f when building.
Docker might use a different Dockerfile or fail to find the build instructions.
Always use -f Dockerfile to specify the correct file if not named Dockerfile or in a different location.
Summary
Use a builder image to compile or prepare your app with all necessary tools.
Copy only the final built artifact into a small runtime image to keep it lightweight.
Build and run the image to verify your app works as expected.