How to Mock a Dockerfile Multi-Stage Build in Python

Simulate a Dockerfile multi-stage build process in Python using dataclasses to validate stage ordering and file availability before you write the real Dockerfile.

Easy Python 3.9+ Aug 9, 2026 Production deployment patterns 14 views 0 copies

Python code

58 lines
Python 3.9+
from dataclasses import dataclass
from pathlib import Path


@dataclass
class BuildStage:
    name: str
    base_image: str
    files: list[str]
    commands: list[str]


def run_build(stage: BuildStage, context_dir: Path):
    print(f"=== Stage: {stage.name} (base: {stage.base_image}) ===")
    for file in stage.files:
        path = context_dir / file
        print(f"  COPY {file} -> exists: {path.exists()}")
    for cmd in stage.commands:
        print(f"  RUN {cmd}")
    return stage


def dockerfile_multi_stage_mock():
    context = Path(".")

    builder = BuildStage(
        name="builder",
        base_image="python:3.11-slim",
        files=["requirements.txt"],
        commands=[
            "pip install --upgrade pip",
            "pip install -r requirements.txt",
        ],
    )

    runtime = BuildStage(
        name="runtime",
        base_image="python:3.11-slim",
        files=["app.py"],
        commands=["python app.py"],
    )

    # Simulate multi-stage: first build, then runtime copies from builder
    built = run_build(builder, context)
    actual_files = [f for f in runtime.files if f != "app.py"]

    print("\n=== Final image (copies from builder) ===")
    print(f"FROM {built.base_image} AS builder")
    print("COPY --from=builder /install /usr/local")
    for f in runtime.files:
        print(f"COPY {f} /app/{f}")
    for cmd in runtime.commands:
        print(f"CMD {cmd}")
    print(f"\nStage summary: {built.name} -> {runtime.name}")


if __name__ == "__main__":
    dockerfile_multi_stage_mock()

Output

stdout
=== Stage: builder (base: python:3.11-slim) ===
  COPY requirements.txt -> exists: True
  RUN pip install --upgrade pip
  RUN pip install -r requirements.txt

=== Stage: runtime (base: python:3.11-slim) ===
  COPY app.py -> exists: True
  RUN python app.py

=== Final image (copies from builder) ===
FROM python:3.11-slim AS builder
COPY --from=builder /install /usr/local
COPY app.py /app/app.py
CMD python app.py

Stage summary: builder -> runtime

How it works

This mock uses dataclasses to model each Docker build stage as a structured object, making it easy to validate stage definitions before writing the real Dockerfile. The run_build function simulates file checks with Path.exists() and prints each command, mirroring Docker's build log. By separating builder and runtime stages, the code shows how a multi-stage build keeps the final image lean by only copying artifacts from the builder stage. This pattern is useful for catching missing files or invalid command ordering early in development, before you commit to a slow Docker build cycle.

Common mistakes

  • Assuming files exist without verifying with `Path.exists()` in the mock context
  • Forgetting that `COPY --from=builder` only works if the builder stage actually ran first
  • Hardcoding file paths instead of using `Path` for cross-platform compatibility
  • Mixing build-stage commands with runtime commands in the same stage object

Variations

  1. Use a dict-based config instead of dataclasses for a lighter-weight mock
  2. Add a validation step that checks `stage.files` against the actual filesystem before printing

Real-world use cases

  • Pre-flight checking a Dockerfile's COPY directives against your repo before a CI build.
  • Documenting and reviewing build pipeline stages in a team without running Docker.
  • Teaching or demoing multi-stage build concepts without needing a Docker daemon.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Production deployment patterns

Related tutorials and quizzes for this topic.