Chapter 21Lesson 04~135 minutes

Bind Mounts, Read-Only Mounts, tmpfs, Mount Propagation, Subpaths, SELinux Labels, and Host Coupling: Diagnostics, Failure Modes, Security, and Performance

Diagnose mount failures and host-side effects without broad permissions, security disablement, or destructive cleanup, preserving first-failure evidence.

DiagnosticsPermissionsRemote daemonSecurityEvidence

Learning objectives

  • Use an evidence-first sequence to separate source-path, context, permission, SELinux, propagation, and application failures.
  • Diagnose a missing bind source without replacing the error with silent directory creation.
  • Explain why mounting broad host paths or Docker control interfaces into untrusted containers is a host-compromise risk.
  • Diagnose root-owned development files and remote-context path confusion using numeric identity and daemon-host evidence.
  • Preserve security controls and apply the least destructive correction.
Diagnostic rule. Preserve the first mount error. Do not “fix” it by broadening permissions, disabling SELinux, changing the daemon, or switching blindly from --mount to -v. Each of those can hide the real layer that failed.

1. Evidence-first diagnostic sequence

Step Question Evidence
1. Context Which daemon is receiving this request? docker context show/inspect
2. Source Does the exact source exist on that daemon host? Host/remote evidence; preserved mount error
3. Mount object What did Docker configure? docker inspect ... .Mounts
4. Identity Which UID/GID needs access? id, numeric ls -ln
5. LSM Is SELinux/AppArmor denying access? Host security status/audit evidence
6. Platform Linux Engine, Desktop VM, or remote daemon? docker info, context endpoint
7. Application Is the app reading/writing the expected target? Logs, in-container ls/stat
8. Correction What is the smallest change? Narrow source, correct owner, scoped label, or config fix

2. Intentionally broken example: preserve the missing-source error

This is the same failure category as the Lesson 2 exercise, now treated diagnostically. The path is intentionally absent and stays inside the lab directory.

mkdir -p da21-diag/evidence
rm -rf da21-diag/not-present

set +e
docker run --rm   --mount type=bind,src="$(pwd)/da21-diag/not-present",dst=/data   busybox:1.36.1 ls /data   >da21-diag/evidence/stdout.txt 2>da21-diag/evidence/stderr.txt
status=$?
set -e

printf 'exit=%s
' "$status" | tee da21-diag/evidence/exit.txt
cat da21-diag/evidence/stderr.txt

docker context show | tee da21-diag/evidence/context.txt
docker context inspect "$(docker context show)" --format '{{json .Endpoints.docker.Host}}'   | tee da21-diag/evidence/endpoint.txt

test ! -e da21-diag/not-present && echo 'source remains absent'

The least-destructive correction is to create the intended source explicitly if it truly belongs on this daemon host, or fix the context/path if it does not. Switching to short syntax merely to suppress the error would erase useful evidence.

3. Remote context: client-local path is not remote-daemon state

A frequent mistake is running Docker from a laptop against a remote daemon and assuming ./config refers to the laptop. It does not. The remote daemon resolves the bind source. The secure alternatives are to place the required data on that host through an authorized deployment process, bake declared immutable data into the image, or use a storage/config mechanism designed for remote delivery.

4. Root-owned developer files

A container process running as UID 0 can create files in a writable bind that appear host-owned by root on native Linux. Preserve numeric ownership first. A common local-development correction is to run the container process as the developer's numeric UID/GID when the image supports it, rather than recursively changing broad host permissions.

# Native Linux diagnostic example; skip numeric ownership conclusions on Desktop if its sharing layer remaps IDs.
id
ls -ln da21-lab/host-rw 2>/dev/null || true

docker run --rm   --user "$(id -u):$(id -g)"   --mount type=bind,src="$(pwd)/da21-lab/host-rw",dst=/work   busybox:1.36.1 sh -c 'echo user-matched > /work/user-matched.txt'   2>da21-diag/evidence/user-write.err || true

ls -ln da21-lab/host-rw 2>/dev/null || true

If the application requires a specific in-image user, solve ownership as a deliberate image/runtime contract rather than falling back to world-writable permissions.

5. SELinux denial: keep the control, fix the label contract

On SELinux hosts, a bind may be blocked even when Unix permissions look correct. Capture getenforce and relevant audit evidence. Then choose the documented shared/private relabel option for the exact application directory if appropriate. Disabling SELinux converts a scoped labeling problem into a host-wide security regression.

6. Broad host mounts and Docker control interfaces

Giving an untrusted container access to host root or the Docker daemon control interface can effectively grant host-level authority. The remedy is architectural: remove that mount and expose only the specific data or API the workload truly needs. This course never uses those mounts as troubleshooting shortcuts.

7. Propagation surprises

If a nested host mount is not visible in a container, first inspect whether propagation is actually required and whether the host mount tree supports it. Do not jump from rprivate to rshared globally. On Docker Desktop, propagation does not work, so a Linux-only recipe is the wrong layer entirely.

8. Docker Desktop: correctness versus file-sharing performance

If a large source bind is slow on Desktop, prove the bottleneck before changing application behavior. Docker advises sharing only needed directories and using named volumes for database/cache data. Optional synchronized file sharing may help very large repositories, but mandatory course workflows remain free and use ordinary file sharing.

9. Unsafe shortcut → evidence-based correction

Unsafe shortcut Why it hides risk Preferred correction
Disable SELinux Removes host-wide enforcement Inspect denial and apply correct scoped labeling
Make directory world-writable Erases least-privilege boundary Match UID/GID or grant narrow intended permissions
Mount a broader host tree Expands read/write authority Mount the smallest required subtree
Switch to -v after missing-source error May silently create the wrong path Correct the intended source or context
Use broader propagation Can expose nested mounts bidirectionally Keep rprivate unless a concrete propagation requirement exists

10. Exact cleanup

docker rm -f da21-ro da21-rw da21-inspect da21-tmpfs da21-prop-inspect 2>/dev/null || true
find da21-diag -maxdepth 2 -type f -print 2>/dev/null || true
# Review evidence, then remove only ./da21-diag and ./da21-lab when intentionally finished.
Next lesson

Next: Checkpoint Lab — Bind Mounts, Read-Only Mounts, tmpfs, Mount Propagation, Subpaths, SELinux Labels, and Host Coupling

Run a checkpoint that measures read-only visibility, writable host side effects, tmpfs lifetime, ownership, mount metadata, and exact cleanup as one evidence packet.

Knowledge check

A bind works locally but fails through a remote context. What should you verify first?

Why is changing to world-writable permissions a poor ownership fix?

What is the safer response to an SELinux denial?

Why is mounting a broader host path not a neutral troubleshooting step?

What should you conclude if propagation guidance works on Linux Engine but not Docker Desktop?

Official references and version notes

Version baseline, verified 2026-09-21.

Docker Engine 29.8.1 and Docker Desktop 4.91.0 are current; Compose 5.5.1, Buildx 0.37.1, and BuildKit 0.33.0 are the upstream baselines used for compatibility discussion. The labs record the learner's actual versions because host kernel, Docker Desktop VM/file-sharing mode, SELinux, and remote-context topology materially affect mount behavior.

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.