Multi-stage builds for smaller images in MLOps - Time & Space Complexity
Start learning this pattern below
Jump into concepts and practice - no test required
We want to understand how the time to build a Docker image changes when using multi-stage builds.
How does adding stages affect the build steps as the project grows?
Analyze the time complexity of this multi-stage Dockerfile snippet.
FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
FROM alpine:latest
COPY --from=builder /app/myapp /myapp
CMD ["/myapp"]
This builds the app in one stage, then copies only the final binary to a smaller image in the second stage.
Look at the build steps that repeat or grow with input size.
- Primary operation: The
RUN go buildcommand compiles the source code. - How many times: This compile step runs once per build, processing all source files.
As the source code size grows, the compile step takes longer.
| Input Size (source files) | Approx. Operations (compile time) |
|---|---|
| 10 | Short compile time |
| 100 | Longer compile time |
| 1000 | Much longer compile time |
Pattern observation: Compile time grows roughly with the amount of source code.
Time Complexity: O(n)
This means the build time grows linearly with the size of the source code.
[X] Wrong: "Multi-stage builds always make the build faster."
[OK] Correct: Multi-stage builds reduce final image size but the compile step still processes all source code once, so build time depends on code size.
Understanding how build steps scale helps you explain trade-offs in build speed and image size clearly.
What if we added caching for the build stage? How would the time complexity change?
Practice
Solution
Step 1: Understand multi-stage build concept
Multi-stage builds separate the build environment from the runtime environment in Dockerfiles.Step 2: Identify the benefit of separation
This separation removes unnecessary build tools from the final image, making it smaller and cleaner.Final Answer:
They create smaller and cleaner Docker images by separating build and runtime stages. -> Option BQuick Check:
Multi-stage builds = smaller images [OK]
- Confusing multi-stage builds with running multiple containers
- Thinking multi-stage builds update base images automatically
- Assuming multi-stage builds change OS compatibility
Solution
Step 1: Recall Dockerfile multi-stage syntax
To start a new build stage, Dockerfile uses 'FROM <image> AS <name>'.Step 2: Match correct syntax
Only 'FROM ubuntu AS builder' matches the correct syntax for naming a stage.Final Answer:
FROM ubuntu AS builder -> Option AQuick Check:
Stage naming uses 'FROM ... AS ...' [OK]
- Using 'STAGE' keyword which does not exist
- Writing 'NEW STAGE' instead of 'FROM ... AS ...'
- Confusing 'BUILD STAGE' with Dockerfile syntax
FROM golang:1.20 AS builder WORKDIR /app COPY . . RUN go build -o myapp FROM alpine:latest COPY --from=builder /app/myapp /usr/local/bin/myapp CMD ["myapp"]
Solution
Step 1: Analyze multi-stage build steps
The first stage builds the Go binary using the full Go environment. The second stage uses a minimal Alpine image.Step 2: Understand what is copied to final image
Only the compiled binary '/app/myapp' is copied from the builder stage to the final image, excluding build tools.Final Answer:
The final image will be small because it only copies the built binary from the builder stage. -> Option CQuick Check:
Copying only binary = smaller final image [OK]
- Assuming the entire build environment is included in final image
- Thinking the build fails due to missing compiler in second stage
- Believing base images merge into one large image
FROM node:18 AS builder WORKDIR /app COPY package.json . RUN npm install COPY . . RUN npm run build FROM node:18 COPY --from=builder /app/dist ./dist CMD ["node", "./dist/server.js"]
Solution
Step 1: Review base images used in both stages
Both stages use 'node:18', which is a full Node image including build tools.Step 2: Suggest optimization for smaller final image
Using a smaller base like 'node:18-alpine' in the second stage reduces image size by excluding unnecessary tools.Final Answer:
The second stage should use a smaller base image like 'node:18-alpine' to reduce size. -> Option DQuick Check:
Use lightweight base images in final stage [OK]
- Thinking COPY syntax is incorrect when it is valid
- Believing CMD needs different syntax here
- Assuming WORKDIR is missing in first stage
Solution
Step 1: Understand requirement for minimal final image
Dependencies should be installed in a build stage, not in the final image, to keep it small.Step 2: Analyze options for multi-stage usage
FROM python:3.12 AS builder WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . FROM python:3.12-slim COPY --from=builder /app /app CMD ["python", "/app/app.py"]
uses a builder stage to install dependencies and copies only the app to a slim final image, achieving minimal size.Final Answer:
Option A correctly uses multi-stage build to keep final image minimal. -> Option AQuick Check:
Install dependencies in builder, copy to slim final image [OK]
- Installing dependencies directly in final image increasing size
- Not using multi-stage build at all
- Running app in builder stage instead of final stage
