Two-Stage Architecture¶
PeiDocker’s default model splits the build into two images because system setup and day-to-day application setup have different change rates.
This page explains that default model. PeiDocker also supports a stage-1-only workflow and a merged build workflow; see Build Modes for the user-facing choice between them.
Where This Fits¶
| Mode | What changes |
|---|---|
stage-1-only |
You omit stage_2 from user_config.yml, and the generated compose file keeps only the stage-1 service |
two-stage Compose |
You keep both stages and build/run them through the default Compose flow |
merged build |
You keep both stages, but configure --with-merged also writes merged artifacts so the final image can be built and run without the default Compose build path |
Stage-1¶
Stage-1 is the system layer. It is where you usually put:
- Base image selection
- SSH server setup
- APT mirrors and proxy-aware package setup
- Low-level installers and stable dependencies
If you change stage-1, you invalidate everything built on top of it.
Stage-2¶
Stage-2 is the working layer. It is where you usually put:
- App, data, and workspace storage
- Additional ports
- Application-specific environment variables
- Runtime-oriented custom scripts
- Built-in installers you want closer to the final image
If stage_2.image.base is omitted, PeiDocker automatically uses the output image from stage-1.
How They Chain¶
configurewrites compose build arguments for stage-1 and stage-2.- Stage-1 builds a reusable foundation image.
- Stage-2 uses that stage-1 image as its base unless you override it.
- Runtime storage and
/soft/*symlinks are created when the final container starts, not duringdocker build.
If stage_2 is omitted, the chain stops after stage-1 and the generated compose file keeps only the stage-1 service. If you use merged build artifacts, the logical chain is still stage-1 then stage-2; only the build/run workflow changes.
What Belongs Where¶
| Put it in | When |
|---|---|
| Stage-1 | You need OS-level setup, SSH, APT, or something reused across many projects |
| Stage-2 | You need storage, app tooling, ports, or project-specific runtime behavior |
Practical Rule¶
If a script needs /soft/... or mounted volumes, it does not belong in stage_2.custom.on_build. Those paths do not exist until container startup. Use runtime hooks such as on_first_run or target in-image paths like /hard/image/... at build time.