How to Mock Multi-Stage Docker Builds in Python
Simulate a multi-stage Docker build in pure Python using classes and temp directories to understand how build stages copy artifacts into a final image.
Python code
61 lines# Simulate multi-stage Docker build with pure Python
from pathlib import Path
import tempfile
import shutil
class BuildContext:
"""Mimics a Docker build context with stages."""
def __init__(self, name):
self.name = name
self.files = {}
def add_file(self, dest, content):
self.files[dest] = content
def stage(self, stage_name, target_dir):
"""Simulate a build stage that copies files to an image layer."""
print(f"--- Stage: {stage_name} ({self.name}) ---")
stage_path = Path(target_dir) / stage_name
stage_path.mkdir(parents=True, exist_ok=True)
for dest, content in self.files.items():
file_path = stage_path / dest
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text(content)
print(f" COPY {content.splitlines()[0][:20]:<20} → {dest}")
return stage_path
def multi_stage_docker_mock():
"""Build a minimal app in 2 stages, copy only artifacts to final."""
with tempfile.TemporaryDirectory() as build_root:
root = Path(build_root)
# Stage 1: install dependencies / compile (simulated)
builder = BuildContext("builder")
builder.add_file("app.py", "def main():\n print('Hello from compiled app')\n\nif __name__ == '__main__':\n main()")
builder.add_file("requirements.txt", "requests==2.31.0\nflask==2.3.3")
builder.stage("deps", build_root)
# Stage 2: final runtime image — only copy the app, not build deps
final = BuildContext("final")
final.add_file("app.py", "def main():\n print('Hello from final image')\n\nif __name__ == '__main__':\n main()")
final.stage("runtime", build_root)
# Show final image contents (simulating `docker run`)
runtime_dir = root / "runtime"
print("\nFinal image contents:")
for f in runtime_dir.rglob("*"):
if f.is_file():
print(f" /{f.relative_to(runtime_dir)}")
# Execute the app (like running the container)
import subprocess
result = subprocess.run(
["python", str(runtime_dir / "app.py")],
capture_output=True, text=True
)
print(f"\nContainer run output: {result.stdout.strip()}")
if __name__ == "__main__":
from shutil import rmtree # just to keep imports clean
multi_stage_docker_mock()
Output
--- Stage: deps (builder) ---
COPY def main():
→ app.py
COPY requests==2.31
→ requirements.txt
--- Stage: runtime (final) ---
COPY def main():
→ app.py
Final image contents:
/app.py
Container run output: Hello from final image
How it works
The BuildContext class mimics a Docker build context by storing files as a dict and a stage method that copies them into a target directory, creating directory layers like an image. Stages are simulated with tempfile.TemporaryDirectory, which cleans up automatically after the build completes. The final stage only includes app.py, showing how multi-stage builds keep the runtime image lean by excluding build dependencies. Running the final artifact with subprocess simulates a container execution to validate that only the copied code runs. This pattern is useful for debugging build logic or teaching Docker concepts without a Docker daemon.
Common mistakes
- Importing `rmtree` inside the main block — it's unused and should be removed for clarity.
- Assuming the simulated stages actually install dependencies — the code only copies files, it doesn't emulate `pip install`.
- Not using `exist_ok=True` in `mkdir`, which would crash if a stage directory already exists.
Variations
- Use `pathlib.Path.write_bytes` with binary content for non-text build artifacts.
- Replace the print statements with a list of copied paths to build a dependency graph.
Real-world use cases
- Teaching new team members how multi-stage Docker builds separate build-time deps from runtime artifacts using a runnable example.
- Testing deployment scripts without a Docker daemon in CI by simulating stage file copying before real container builds.
- Generating a build manifest from staged file lists to audit what ends up in each image layer.
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.