📖 Scenario: You are working on a Docker project where you want to build a small, efficient image. Before Docker had multi-stage builds, developers used a builder pattern to create the final image in two steps.This project will guide you to create a Dockerfile that uses the builder pattern manually by creating two separate Dockerfiles: one for building the app and one for the final runtime image.
🎯 Goal: Build a Docker setup that first compiles a simple app in a builder image, then copies the compiled app into a smaller runtime image manually, simulating the builder pattern before multi-stage builds.
📋 What You'll Learn
Create a Dockerfile named Dockerfile.builder that builds the app
Create a Dockerfile named Dockerfile.runtime that copies the built app from the builder image
Use exact image names and commands as specified
Show the final image running the app prints the expected output
💡 Why This Matters
🌍 Real World
Before Docker supported multi-stage builds, developers used this pattern to keep final images small by separating build and runtime environments.
💼 Career
Understanding this pattern helps you maintain legacy Docker projects and appreciate modern multi-stage builds in DevOps workflows.
Progress0 / 4 steps
1
Create the builder Dockerfile
Create a file named Dockerfile.builder with these exact contents:
FROM python:3.12-slim
WORKDIR /app
COPY app.py /app/
RUN python -m compileall app.py
This will prepare a builder image that compiles app.py.
Docker
Hint
Use the official Python 3.12 slim image as the base.
Set the working directory to /app.
Copy app.py into the image.
Run python -m compileall app.py to compile the script.
2
Create the runtime Dockerfile
Create a file named Dockerfile.runtime with these exact contents:
This Dockerfile will copy the compiled app from the builder image and run it.
Docker
Hint
Use the same base image and working directory.
Copy the compiled .pyc file from the builder image's /app/__pycache__ folder.
Set the command to run the compiled Python file.
3
Build the builder image
Run this exact command in your terminal to build the builder image: docker build -f Dockerfile.builder -t builder . This creates an image named builder that compiles the app.
Docker
Hint
Use docker build with -f Dockerfile.builder and tag the image as builder.
4
Build and run the runtime image
Run these exact commands in your terminal: docker build -f Dockerfile.runtime -t runtime . Then run: docker run --rm runtime The output should be: Hello from compiled app!
Docker
Hint
Build the runtime image using Dockerfile.runtime and tag it runtime.
Run the container and check the output.
Practice
(1/5)
1. What is the main purpose of the builder pattern in Docker before multi-stage builds were introduced?
easy
A. To run multiple containers simultaneously
B. To separate the build environment from the final runtime environment
C. To automatically update Docker images
D. To manage Docker volumes efficiently
Solution
Step 1: Understand the builder pattern concept
The builder pattern splits the process into two parts: building the app and running it.
Step 2: Identify the benefit of separation
This separation keeps the final image small by excluding build tools and files.
Final Answer:
To separate the build environment from the final runtime environment -> Option B
Quick Check:
Builder pattern = separate build and run [OK]
Hint: Builder pattern means build and run are separate stages [OK]
Common Mistakes:
Confusing builder pattern with running multiple containers
Thinking it manages volumes or updates automatically
Assuming it is about Docker networking
2. Which Dockerfile snippet correctly implements the builder pattern before multi-stage builds?
easy
A. FROM node:14
WORKDIR /app
COPY . .
RUN npm install && npm run build
CMD ["npm", "start"]
B. FROM node:14 AS builder
WORKDIR /app
COPY . .
RUN npm install && npm run build
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
C. FROM node:14
RUN npm install
COPY . .
CMD ["npm", "start"]
D. FROM nginx:alpine
COPY . /usr/share/nginx/html
RUN npm install
Solution
Step 1: Identify builder pattern before multi-stage
Before multi-stage, builder pattern used separate Dockerfiles or manual copying, not the --from syntax.
Step 2: Check each option
FROM node:14 AS builder
WORKDIR /app
COPY . .
RUN npm install && npm run build
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html uses multi-stage syntax (--from=builder), which was not available before multi-stage builds.
Final Answer:
FROM node:14
WORKDIR /app
COPY . .
RUN npm install && npm run build
CMD ["npm", "start"] -> Option A
Quick Check:
Before multi-stage, no --from usage [OK]
Hint: Before multi-stage, no --from in COPY command [OK]
Common Mistakes:
Choosing multi-stage syntax before it existed
Confusing build and runtime commands
Ignoring the CMD instruction
3. Given this Dockerfile before multi-stage builds:
FROM node:14
WORKDIR /app
COPY . .
RUN npm install && npm run build
CMD ["node", "server.js"]
What is the likely size impact on the final image?
medium
A. The image will be large because build tools and source files remain
B. The image will be small because only build output is copied
C. The image size is minimal due to automatic cleanup
D. The image size depends only on the base image
Solution
Step 1: Analyze the Dockerfile steps
The Dockerfile copies all source files and runs build inside the same image.
Step 2: Understand image size impact
Since build tools and source files remain, the image size is larger than needed.
Final Answer:
The image will be large because build tools and source files remain -> Option A
Quick Check:
Single-stage build keeps all files, so image is large [OK]
Hint: Single-stage build keeps all files, making image large [OK]
Common Mistakes:
Assuming build output only is copied
Thinking Docker cleans up build files automatically
Ignoring the COPY . . step
4. You have two Dockerfiles: one for building and one for running. You want to copy build artifacts from the builder image to the runtime build context manually. Which command correctly copies files from a stopped builder container named 'builder' to the runtime build context?
medium
A. docker cp ./build builder:/app/build
B. docker copy builder:/app/build ./build
C. docker cp builder:/app/build ./build
D. docker copy ./build builder:/app/build
Solution
Step 1: Understand docker cp syntax
The correct syntax is 'docker cp <container>:<source_path> <destination_path>'.
Step 2: Match command to copy from container to local
docker cp builder:/app/build ./build correctly copies from container 'builder' path to local './build'.
Final Answer:
docker cp builder:/app/build ./build -> Option C
Quick Check:
docker cp container:path local_path [OK]
Hint: Use 'docker cp container:path local_path' to copy files out [OK]
Common Mistakes:
Using 'docker copy' instead of 'docker cp'
Reversing source and destination paths
Trying to copy from local to container incorrectly
5. You want to manually implement the builder pattern before multi-stage builds by using two Dockerfiles: Dockerfile.build and Dockerfile.run. Which sequence of commands correctly builds and prepares the final image with only the build output copied?