0
0
Dockerdevops~15 mins

Multiple FROM statements in Docker - Deep Dive

Choose your learning style9 modes available
Overview - Multiple FROM statements
What is it?
Multiple FROM statements in Dockerfiles allow you to use more than one base image in a single Dockerfile. Each FROM starts a new build stage, letting you create multi-stage builds. This helps you separate build environments from final runtime environments. It makes your Docker images smaller and more efficient.
Why it matters
Without multiple FROM statements, Docker images often include unnecessary build tools and files, making them large and slow to transfer. Multi-stage builds solve this by letting you build in one stage and copy only what you need to the final image. This saves storage, speeds up deployment, and improves security by reducing attack surface.
Where it fits
You should know basic Dockerfile syntax and how single-stage builds work before learning this. After mastering multi-stage builds, you can explore advanced Docker optimizations, CI/CD pipelines, and container security best practices.
Mental Model
Core Idea
Multiple FROM statements let you chain separate build steps in one Dockerfile, each with its own base image, to produce a clean final image.
Think of it like...
It's like cooking a meal in stages: you prepare ingredients in one kitchen, then move only the finished parts to another kitchen for plating, keeping the final dish clean and simple.
┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│  Stage 1:     │       │  Stage 2:     │       │  Final Image  │
│  Build base   │──────▶│  Build tools  │──────▶│  Runtime only │
│  (e.g. builder)│       │  (e.g. compiler)│      │  (minimal)    │
└───────────────┘       └───────────────┘       └───────────────┘
Build-Up - 7 Steps
1
FoundationSingle FROM statement basics
🤔
Concept: Learn how a Dockerfile starts with one FROM statement to set the base image.
A Dockerfile begins with FROM followed by a base image name, like 'FROM ubuntu:22.04'. This sets the starting point for your image. All commands after this build on top of that base image.
Result
Docker builds an image starting from the specified base image.
Understanding the single FROM statement is essential because it defines the environment your container will run in.
2
FoundationWhy image size matters
🤔
Concept: Recognize that large images slow down deployment and waste resources.
Images that include build tools and source code are bigger. This means slower downloads, more storage use, and longer startup times. Smaller images are faster and more secure.
Result
You see that including unnecessary files makes images bulky and inefficient.
Knowing why image size matters motivates the need for multi-stage builds.
3
IntermediateIntroducing multiple FROM statements
🤔Before reading on: do you think multiple FROM statements create one combined image or separate images? Commit to your answer.
Concept: Multiple FROM statements start new build stages in one Dockerfile.
Each FROM starts a new stage with its own base image. You can name stages with 'AS' to refer to them later. For example: FROM golang:1.20 AS builder RUN go build -o app . FROM alpine:3.18 COPY --from=builder /app /app CMD ["/app"]
Result
Docker builds the first stage, then the second stage, copying only the needed files from the first to the second.
Understanding that each FROM creates a separate stage helps you organize builds and keep final images small.
4
IntermediateUsing stage names for clarity
🤔Before reading on: do you think naming stages is optional or required? Commit to your answer.
Concept: Naming stages with AS lets you copy files between stages clearly.
You can name a stage like 'FROM node:18 AS build'. Later, use 'COPY --from=build' to copy files from that stage. This avoids confusion and errors when you have multiple stages.
Result
Your Dockerfile is easier to read and maintain, and Docker knows exactly where to copy files from.
Knowing how to name and reference stages prevents mistakes and improves collaboration.
5
IntermediateCopying artifacts between stages
🤔
Concept: Learn how to transfer only needed files from build stages to the final image.
Use 'COPY --from=stage_name /path/in/stage /path/in/final' to copy build outputs. This excludes build tools and source code from the final image, making it smaller.
Result
Final image contains only runtime files, not build dependencies.
Understanding selective copying is key to creating efficient, secure images.
6
AdvancedOptimizing multi-stage builds
🤔Before reading on: do you think adding more stages always makes images smaller? Commit to your answer.
Concept: Learn strategies to minimize image size and build time using multiple stages.
You can add intermediate stages for testing or linting, then discard them. Also, order stages to maximize Docker cache reuse. For example, separate dependencies installation from source code copying.
Result
Builds are faster and final images are minimal.
Knowing how to structure stages affects build efficiency and image size significantly.
7
ExpertSurprising behavior with ARG and FROM
🤔Before reading on: do you think ARG variables can be used before the first FROM? Commit to your answer.
Concept: ARG variables can be declared before FROM but have special scope rules affecting multi-stage builds.
You can declare ARG before the first FROM to parameterize base images. However, ARGs declared after FROM are scoped to that stage only. This subtlety affects build reproducibility and flexibility. Example: ARG BASE=alpine:3.18 FROM ${BASE} AS base This lets you change base images at build time.
Result
You can customize base images dynamically, but must understand ARG scope to avoid errors.
Understanding ARG scope with multiple FROM statements prevents confusing build failures and enables flexible builds.
Under the Hood
Docker processes a Dockerfile top to bottom. Each FROM starts a new build stage with its own filesystem and environment. Docker builds each stage independently, caching layers. When a later stage uses COPY --from, Docker copies files from the finished stage's filesystem into the new stage. Only the final stage's filesystem becomes the final image.
Why designed this way?
Multi-stage builds were introduced to solve the problem of large images containing build tools. Previously, developers had to use multiple Dockerfiles or manual cleanup. Multi-stage builds simplify this by allowing multiple isolated build environments in one file, improving maintainability and efficiency.
Dockerfile
  │
  ├─ FROM base-image AS stage1
  │     └─ Build environment 1
  │
  ├─ FROM base-image AS stage2
  │     └─ Build environment 2
  │
  └─ FROM base-image
        ├─ COPY --from=stage1 /app /app
        └─ Final runtime image
Myth Busters - 4 Common Misconceptions
Quick: Does each FROM statement create a separate image or combine into one? Commit to your answer.
Common Belief:Each FROM statement creates a separate image that runs independently.
Tap to reveal reality
Reality:Multiple FROM statements create separate build stages, but only the last stage produces the final image.
Why it matters:Believing each FROM creates a separate image can lead to confusion about what is included in the final container, causing deployment errors.
Quick: Can you use files from a previous stage without naming it? Commit to your answer.
Common Belief:You can copy files from any previous stage without naming them.
Tap to reveal reality
Reality:You must name stages with AS to copy files from them using COPY --from; unnamed stages can also be referenced by their numeric index.
Why it matters:Not naming stages or misunderstanding referencing leads to build failures or copying wrong files.
Quick: Does ARG declared after FROM affect all stages? Commit to your answer.
Common Belief:ARG variables declared after FROM are global and affect all stages.
Tap to reveal reality
Reality:ARG variables declared after FROM are scoped only to that stage; only ARG before the first FROM is global.
Why it matters:Misusing ARG scope causes unexpected build behavior and hard-to-debug errors.
Quick: Does adding more stages always reduce image size? Commit to your answer.
Common Belief:More stages always make the final image smaller.
Tap to reveal reality
Reality:Adding unnecessary stages or copying extra files can increase image size; careful design is needed.
Why it matters:Assuming more stages always help can lead to bloated images and slower builds.
Expert Zone
1
Stages can share cache layers if their base images and commands match, speeding up builds.
2
Using named stages improves readability and reduces errors in complex Dockerfiles with many stages.
3
ARG variables before FROM enable dynamic base images, but require careful management to avoid build inconsistencies.
When NOT to use
Multi-stage builds are not ideal when your build process is extremely simple or when you need to debug intermediate stages interactively. In such cases, separate Dockerfiles or single-stage builds might be easier. Also, for very large monolithic builds, specialized build tools outside Docker may be better.
Production Patterns
In production, multi-stage builds are used to compile code in a heavy builder image, then copy only the compiled binaries into a minimal runtime image like Alpine. This pattern reduces attack surface and speeds up deployment. CI/CD pipelines often build and push multi-stage images automatically.
Connections
Continuous Integration/Continuous Deployment (CI/CD)
Multi-stage builds integrate with CI/CD pipelines to produce optimized images automatically.
Understanding multi-stage builds helps you design pipelines that build, test, and deploy containers efficiently.
Software Build Systems
Multi-stage builds mimic traditional build systems by separating compile and runtime environments.
Knowing build systems clarifies why separating build and runtime stages reduces complexity and errors.
Manufacturing Assembly Lines
Multi-stage builds are like assembly lines where parts are prepared separately before final assembly.
Seeing multi-stage builds as assembly lines helps grasp the efficiency gained by isolating steps.
Common Pitfalls
#1Copying build tools into the final image accidentally
Wrong approach:FROM golang:1.20 RUN go build -o app . COPY . /app CMD ["/app"]
Correct approach:FROM golang:1.20 AS builder RUN go build -o app . FROM alpine:3.18 COPY --from=builder /app /app CMD ["/app"]
Root cause:Not using multi-stage builds causes build tools and source files to be included in the final image.
#2Referencing unnamed stages incorrectly
Wrong approach:FROM node:18 RUN npm build FROM nginx COPY --from=build /app /usr/share/nginx/html
Correct approach:FROM node:18 AS build RUN npm build FROM nginx COPY --from=build /app /usr/share/nginx/html
Root cause:Forgetting to name the build stage prevents COPY --from from finding the correct source.
#3Declaring ARG after FROM expecting global scope
Wrong approach:FROM alpine ARG VERSION=1.0 RUN echo $VERSION
Correct approach:ARG VERSION=1.0 FROM alpine RUN echo $VERSION
Root cause:ARG declared after FROM is scoped only to that stage, so variables may be undefined if expected globally.
Key Takeaways
Multiple FROM statements enable multi-stage builds that separate build and runtime environments in one Dockerfile.
Using named stages with AS allows precise copying of build artifacts, keeping final images small and secure.
ARG variables before the first FROM let you customize base images dynamically, but ARG scope is stage-specific.
Properly structured multi-stage builds improve build speed, reduce image size, and enhance deployment security.
Misunderstanding stage referencing or ARG scope causes common build errors; naming stages and careful ARG placement prevent these.