Chapter 37Lesson 04~195 minutes

Developer Workflows, Dev Containers, Inner Loop Optimization, Compose-Based Labs, and Local Parity: Diagnostics, Failure Modes, Security, and Performance

Diagnose ownership, socket exposure, secret leakage, slow file sharing, mutable tooling, and false production parity without weakening isolation or hiding the first failure.

DiagnosticsOwnershipSecretsDesktop performanceEvidence

Learning objectives

  • Diagnose development-environment failures from preserved source, mount, user, runtime, and tool evidence.
  • Repair root-owned workspace files without weakening permissions globally.
  • Recognize Docker-socket mounting as infrastructure authority rather than ordinary developer convenience.
  • Separate Desktop file-sharing performance from application performance and image-build performance.
  • Detect false parity caused by mutable tools, dev-only configuration, or production-kernel differences.

1. Evidence-first diagnostic sequence

  1. Preserve the first error, source revision, and local edits.
  2. Confirm Docker context, Engine/Compose versions, and platform.
  3. Render the Compose model and inspect the exact service/container.
  4. Inspect image identity, runtime user, mounts, named volumes, and port bindings.
  5. Determine whether source reaches the container by bind, Watch, COPY, or volume.
  6. Inspect tool versions and generated-file ownership.
  7. Check external dependencies only after local state is understood.
  8. Apply the smallest correction and rerun the smallest failed scope.

2. Failure: root-owned source files

# Preserve evidence before changing ownership.
id
ls -ln dca37-lab/src | tee dca37-lab/evidence/host-owners-before.txt
docker compose -p dca37-bind -f dca37-lab/compose.bind.yaml exec dev id
docker inspect dca37-bind-dev-1 --format '{{json .Mounts}}'

Cause: the process writing the bind mount used a numeric UID/GID the host developer does not own. Repair the intended user mapping or chown only the lab-owned files to the intended owner. Do not make the workspace world-writable.

3. Failure: mounting Docker socket into every dev container

The Docker socket is not “just a CLI integration.” Access to a rootful daemon can create privileged containers, mount host paths, alter networks, and manipulate other projects. Chapter 35 already established that daemon access is infrastructure authority. For ordinary development, keep Docker commands on the host or use an explicitly isolated/rootless/remote builder design with a documented trust boundary. This chapter contains no runnable socket-mount recipe.

4. Failure: committed local secrets

Preserve the commit/file evidence, rotate any real credential, then remove the secret from source history according to your repository incident process. Replace it with fake development configuration or a narrow runtime secret/provider path. Do not merely add the already-committed file to .gitignore and call the incident resolved.

5. Failure: slow cross-OS bind mounts

First separate CPU/network latency from filesystem latency. Record whether Docker Desktop is in the path, what directory is shared, and whether the workload scans thousands of dependency/cache files. Move non-source caches/databases to named volumes, reduce the shared tree, or use Watch/sync for selected source. Optional Desktop Synchronized File Shares are an acceleration choice, not a correctness requirement.

6. Failure: “works in dev container” but production fails

Evidence Potential mismatch
same app source; different base digest runtime libraries/CA certs/OS packages
same image; different behavior kernel, CPU architecture, filesystem, runtime config, network or external service
dev uses source bind; prod copies files generated/uncommitted source was never in image
dev has debugger/compiler runtime accidentally depends on dev-only tool
dev forwards/publishes loopback port production ingress/service discovery differs

7. Failure: mutable tool versions

If onboarding runs “install latest,” two developers can have different compilers, formatters, or CLIs while claiming the same dev-container configuration. Preserve --version output, pin/update the declared image/Feature/package version, and keep a resolved lock where supported. Rebuild only the development environment whose inputs changed.

8. Intentionally broken example: unwritable Watch target

# BROKEN LAB EXAMPLE — target is intentionally read-only for the dev user.
services:
  dev:
    image: python:3.13-alpine
    user: "10001:10001"
    develop:
      watch:
        - action: sync
          path: ./src
          target: /root/src

The failure is not evidence that Watch is unreliable. The configured non-root user cannot write under /root. Preserve the Watch error, inspect the container user and target permissions, then repair the target to a directory owned by the intended developer user, such as /workspace/src.

9. Failure: generated files pollute source

Build outputs, language package caches, bytecode, and databases should not appear in source merely because a tool runs in a container. Decide which generated files are source artifacts, which belong in a named volume, and which belong in an image build stage. Use exact cleanup of known generated paths only after confirming they are not reviewed source.

10. Failure: dev container is treated as a security sandbox

A development container still shares a kernel with its Docker host/VM and often consumes highly trusted source code, credentials, SSH agents, and editor integrations. Do not add broad capabilities, host namespaces, devices, or privileged mode to “make tools work.” Identify the one needed operation and redesign or isolate it.

11. Minimal correction matrix

Symptom Layer Smallest safe correction
permission denied on bind source identity/storage align intended numeric owner or writable path
edit not reflected mount/Watch config fix source path/target/ignore rule
slow dependency install on Desktop file-sharing/storage move cache to named volume; reduce shared tree
service not reachable runtime/network confirm listen address and exact loopback publish/forward
prod missing local edit source/build commit/include intended input; rebuild production image
tool drift development supply chain pin and rebuild dev environment only

12. Preserve first-failure evidence

A failed Watch sync, permission error, missing file in the production image, or unexpected tool version is valuable evidence. Capture it before recreating containers. “Fixed by reopening the dev container” may erase the exact state difference you needed to understand.

Knowledge check

A bind-mounted file is root-owned. What should you inspect before changing permissions?

Why is the Docker socket not an acceptable universal dev-container convenience?

A Watch sync fails writing /root/src under UID 10001. What layer failed?

Why might production fail even if it runs the same application image?

What is the correct response to a committed real secret?

Next lesson

Next: Checkpoint Lab — Developer Workflows, Dev Containers, Inner Loop Optimization, Compose-Based Labs, and Local Parity

Continue with the next lesson in the course sequence and carry forward the evidence-first Docker operating model.

Official references and version notes

Diagnostic baseline: 2026-09-22. Docker Desktop file-sharing behavior is platform/VM dependent. Compose Watch errors should be diagnosed from target ownership, paths, ignored files, and the active Compose model before any broad rebuild/cleanup.

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.