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.
Python code
58 linesfrom 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
=== 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
- Use a dict-based config instead of dataclasses for a lighter-weight mock
- 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
More from Production deployment patterns
- Auto Rollback on Error Rate Exceeded in Python medium
- Automate Semantic Versioning with Conventional Commits in Python medium
- Design a Data Helper for Beginners in Python easy
- Docker healthcheck CMD mock in Python easy
- Generate a Mock Artifact Version Tag in Python easy
- Generate a docker-compose.yml with mock services in Python easy
Keep learning
Related tutorials and quizzes for this topic.