Container Filesystems, Writable Layers, docker cp, exec Workflows, Processes, Signals, and PID 1: Configuration, Design Choices, and Tradeoffs
Runtime filesystem and process choices trade convenience against reproducibility. This lesson compares baked image content, mounts, docker cp, and exec; shell-form versus exec-form launch; application PID 1 versus an init helper; and temporary diagnosis versus immutable rebuild using explicit evidence and trust boundaries.
Learning objectives
- Choose whether content belongs in an image, volume/bind/tmpfs mount, or short-lived runtime diagnostic path based on lifecycle and ownership.
- Choose exec-form or shell-form startup deliberately and predict which process becomes PID 1 and receives Docker stop signals.
- Decide when an application can safely be PID 1 and when a small init helper is justified for child reaping and signal forwarding.
- Distinguish a temporary debugging action from a deployable change and define the evidence required before rebuilding.
- Evaluate portability, security, performance, rollback, and host-coupling trade-offs without reaching ahead into later storage chapters unnecessarily.
1. Design frame: decide ownership before choosing a command
The fastest command is not always the safest design. Before choosing
COPY, a volume, bind mount, docker cp,
docker exec, shell-form startup, exec-form startup, or
--init, ask four questions: who owns the state, how
long must it live, who must reproduce it, and which process must
receive lifecycle signals?
These decisions affect portability, rollback, incident evidence, host coupling, security exposure, and performance. The chapter keeps the choices bounded; persistent-storage engineering is covered later in Chapters 20–21.
2. Bake into the image, mount, or copy at runtime?
| Need | Best default | Why | Main risk |
|---|---|---|---|
| Application binary and static release files | Image | Versioned with the artifact; reproducible by digest. | Rebuild needed for change, which is usually desirable. |
| Durable application data | Explicit persistent mount | Lifecycle independent of container writable layer. | Backup, ownership, host/provider coupling must be designed. |
| Host-managed development source/config | Bind mount when appropriate | Fast iteration and explicit host ownership. | Host coupling and potential write access to host files. |
| Ephemeral high-churn scratch data | tmpfs or writable layer depending need | Avoids pretending temporary state is durable. | Memory/swap or writable-layer performance/lifecycle. |
| One-time non-secret diagnostic evidence | docker cp | Bounded transfer without redesigning the image. | Can create undocumented drift if used as deployment. |
A manual copy that fixes production behavior is a clue that declared
state is incomplete, not proof that docker cp should
become the deployment mechanism.
3. Writable-layer convenience has lifecycle and performance costs
Docker's storage guidance recommends keeping write-heavy or durable data outside the container writable layer. Copy-on-write can add overhead when a lower-layer file must be copied up before modification, and deleting the container deletes its writable layer. The exact implementation depends on the daemon's storage backend; Engine 29 fresh installs default to the containerd image store, while upgraded hosts may still expose classic storage-driver behavior.
Therefore performance advice should be evidence-based: inspect
actual storage mode, measure the workload, and use a volume for
durable/write-heavy data rather than assuming every filesystem issue
is an overlay2 issue.
4. Mount precedence: visible does not mean stored there
If a mount targets a non-empty directory, its contents obscure what the image or writable layer had at that path. This is useful for configuration/data injection, but it complicates diagnosis. A missing visible file may still exist underneath the mount.
- Inspect
.Mounts. - Identify source, destination, read/write mode, and mount type.
- Determine whether the expected file should be image-owned or mount-owned.
- Reproduce in a disposable container without the mount if you need to reveal underlying image content.
Do not copy a file “into” a mounted path until you know which storage object will actually receive the write.
5. Exec form versus shell form: convenience changes signal ownership
Shell form is convenient when you need shell expansion or pipelines,
but it inserts an implicit shell. Docker's current build check warns
that shell-form CMD/ENTRYPOINT can prevent
the intended application from receiving OS signals. Exec form
launches the executable directly and makes process identity clearer.
| Choice | PID 1 tendency | Signal behavior | Use deliberately when |
|---|---|---|---|
CMD my-app --serve |
Implicit shell | Application may not receive forwarded TERM/INT | Shell semantics are truly required and forwarding is handled explicitly. |
CMD ["my-app","--serve"] |
Application | Docker signal targets application directly | Normal service process with correct signal handling. |
Wrapper script + exec "$@" |
Final application | Wrapper performs setup, then hands PID 1 to app | Startup preparation is required before launching the service. |
6. Application PID 1 versus an init helper
A well-designed application can be PID 1 if it handles its signals
and child processes. Adding a tiny init is valuable when the
workload spawns children that can become orphaned/zombie processes
or when signal forwarding needs an init boundary. Docker's
--init option uses the daemon's Tini-backed
docker-init by default.
Do not use a full systemd-style init merely because the container concept resembles a VM. A container usually has one main service concern. Add the smallest process-management mechanism justified by measured behavior.
7. Runtime debugging versus immutable rebuild
docker exec is strong for inspection, health probes
during an incident, or a narrowly authorized administrative command.
It is weak as a deployment mechanism because the action is not
encoded in the image source and may be lost on replacement.
A robust workflow is:
- Preserve the first-failure evidence.
- Use a disposable reproduction or bounded exec/copy action to test a hypothesis.
- Record exactly what was changed and why.
- Express the intended fix in Dockerfile/source/configuration.
- Build a new image from reviewed inputs.
- Verify the new image identity and behavior.
- Replace the old container; do not “promote” the hot-fixed writable layer.
8. Secret boundary: neither writable layer nor docker cp is a secret store
Copying a credential into a container creates sensitive data in runtime filesystem state and may leave it inspectable or recoverable longer than intended. Embedding the same credential in an image is worse because it can persist in image layers and caches. Later chapters cover Docker secrets/configuration patterns in depth.
For this chapter, the rule is simple: labs use fake values only, and
docker cp examples transfer harmless text. In
production design, use an explicit secret-management mechanism with
narrow access and lifecycle rather than ad hoc file copying.
9. Worked decision: a service needs config, scratch space, and graceful shutdown
Suppose a service ships a default policy, receives environment-specific configuration, writes transient render output, and spawns helper processes. A defensible design might be:
- Bake the default policy and binary into the image.
- Inject environment-specific non-secret config through a read-only configuration mount or platform mechanism.
- Use tmpfs or a bounded writable path for non-durable scratch output.
- Launch the application in exec form.
-
Add
--initonly if child reaping is genuinely needed. - Set and test a stop timeout that exceeds measured drain time.
- Use exec/cp for diagnosis only, then rebuild any intended release change.
Evidence should include image digest, mount ownership,
writable-delta expectations, docker diff output where
relevant, PID 1 command, child-process behavior, stop
signal/timeout, shutdown logs, and replacement test.
10. Platform and version prerequisites
Linux containers expose the PID 1 and Unix-signal model discussed here. Windows containers have different process and signal semantics. Docker Desktop adds a managed VM boundary for Linux containers on macOS/Windows, so host PID/filesystem assumptions should not be transferred blindly.
docker cp behavior and security have also changed
across Engine releases. Engine 29.5.1 fixed multiple high-severity
copy-path issues; 29.7.x fixed additional symlink/kernel
compatibility regressions. Record the actual Engine patch level in
runbooks and do not rely on an old copy workaround as current
guidance.
11. Design challenge
You inherit a container that starts with shell-form
CMD, writes 2 GB/day into /var/lib/widget,
receives config by docker cp, and is routinely “fixed”
with docker exec vi .... Propose a migration that
separates release files, durable data, configuration, runtime
scratch, process launch, and diagnostic actions. For every change,
state the evidence proving the new behavior and the rollback
boundary.
Knowledge check
Where should a release binary normally live: container writable layer or image?
In the image, so the release is versioned and reproducible by image identity rather than tied to one mutable container.
Why can a bind mount make an image file appear missing?
The mount can obscure the existing path. The file may still exist in the image underneath the mounted filesystem.
What is the main runtime advantage of exec-form startup?
It avoids an unintended shell parent so the intended executable can become PID 1 and receive Docker signals directly.
Should every container use --init?
No. Use it when child reaping/signal-forwarding responsibilities justify it; a correctly designed application may handle PID 1 responsibilities itself.
Official references and version notes
- Docker storage overview — explains the ephemeral per-container writable layer and why persistent data belongs in explicit mounts rather than the container layer.
- Storage drivers and writable layers — copy-on-write concepts, writable-layer behavior, and the Engine 29 distinction between the containerd image store and classic storage-driver examples.
- docker container diff — reports added, changed, and deleted paths in the container filesystem relative to its initial image-backed state.
- docker container cp — current copy semantics, stopped-container support, destination ownership, archive mode, symlink handling, and path rules.
- docker container exec — starts a new command only while the container's primary PID 1 is running and does not make image changes durable.
-
docker container run
— current runtime options including
--init, stop signals/timeouts, mounts, TTY behavior, and security controls. - docker container stop — graceful signal delivery and timeout-to-SIGKILL escalation.
- docker container attach — documents special PID 1 signal behavior and terminal signal-proxy implications.
-
JSONArgsRecommended build check
— why exec-form
CMD/ENTRYPOINTavoids an unintended shell parent and improves signal handling. -
Docker build best practices
— entrypoint scripts should normally
execthe final application so it becomes PID 1 and receives signals directly. - Bind mounts — mounting over an existing container path obscures image/writable-layer content until the container is recreated without that mount.
-
Docker Engine 29 release notes
— Engine 29.8.1 is the current patch baseline at verification
time; recent 29.x releases also include multiple
docker cpsecurity and compatibility fixes.
Verified 2026-09-21: Docker Engine
29.8.1 is the current Engine 29 patch release.
Current Docker documentation states that each container gets a
unique writable layer above immutable image layers and that
deleting the container deletes that layer;
docker cp can copy to or from running or stopped
containers; docker exec starts an additional process
only while the primary process is running; and
--init uses Docker's Tini-backed init to perform
normal init duties such as reaping child processes. Because Engine
29.5.x–29.7.x contained important docker cp security
and compatibility fixes, learners should record their actual
Engine/CLI versions and current security status rather than
treating file-copy behavior as version-independent.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.