Chapter 26Lesson 04~140 minutes

Rootless Docker, RootlessKit, User Namespaces, Networking, Storage, Limitations, and Threat Reduction: Diagnostics, Failure Modes, Security, and Performance

Diagnose rootless failures by separating context/socket mistakes, subordinate-ID gaps, cgroup delegation, networking, storage, ownership, and outer-host privilege without weakening the host.

DiagnosticsOwnershipDelegationNetworkingEvidence first

Learning objectives

  • Apply an evidence-first sequence to rootless context, subordinate-ID, cgroup, storage, networking, and ownership failures.
  • Diagnose bind-mount ownership and capability limitations without broad permissions or privilege escalation.
  • Interpret current Engine 29.5+ RootlessKit networking behavior when older guidance no longer matches.
  • Preserve first-failure evidence and correct only the failing layer.
Diagnostic principle. Context, user-namespace, cgroup, storage, and RootlessKit failures have different evidence. Preserve the first error and fix the smallest layer rather than escalating privileges.

1. Evidence-first sequence for rootless incidents

Preserve the first error before changing contexts, reinstalling packages, or switching daemons. Then walk the layers in order:

  1. Host/kernel and Linux distribution.
  2. Docker client version and selected context.
  3. Rootless socket and daemon security options.
  4. Subordinate UID/GID ranges and user namespace mapping.
  5. cgroup v2/systemd delegation.
  6. Storage driver/backing filesystem.
  7. RootlessKit network/port behavior.
  8. Container image, process, mounts, and ownership.
  9. External dependency/registry/application evidence.

2. Failure: “rootless” context is actually an ordinary daemon

docker context show
docker context inspect "$(docker context show)"
docker info --format '{{json .SecurityOptions}}'
docker info --format 'Root={{.DockerRootDir}}' 

If rootless is absent from Security Options, a context name alone is not proof of rootless execution. Fix the client target or daemon setup; do not troubleshoot UID mappings until the daemon identity is established.

3. Failure: missing or undersized subuid/subgid ranges

Typical symptoms appear during setup or when creating user mappings. Preserve setup-tool output, then inspect the files:

command -v newuidmap
command -v newgidmap
grep "^$(whoami):" /etc/subuid
grep "^$(whoami):" /etc/subgid

The safe correction is an administrator-approved subordinate-ID allocation. Do not invent overlapping ranges or make newuidmap/newgidmap broadly writable.

4. Failure: cgroup controls unavailable even though containers run

Rootless networking and process execution can work while cgroup resource flags do not. Confirm cgroup v2 and user-service delegation rather than interpreting the failure as an application bug.

stat -fc %T /sys/fs/cgroup
systemctl --user status docker --no-pager 2>/dev/null || true
docker info --format 'CgroupVersion={{.CgroupVersion}} CgroupDriver={{.CgroupDriver}}' 

Do not compensate by running the workload privileged. If required controllers cannot be delegated on that host, record the platform limitation or choose a different host/boundary.

5. Failure: bind-mounted files have surprising ownership

Rootless UID/GID mapping and host bind mounts meet at a real filesystem. A file written as “root” inside the container may map to a subordinate host UID rather than the login user. Preserve stat evidence on both sides:

docker exec <container> sh -c 'id; stat -c "%u:%g %n" /work/example'
stat -c '%u:%g %n' ./example

Correct by designing the runtime user, directory ownership, ACLs, or volume strategy deliberately. Do not use chmod 777 or recursively chown an unrelated host tree.

6. Failure: rootless networking is diagnosed as ordinary bridge networking

RootlessKit inserts an outer networking/port-forwarding layer. Container IPAddress may be meaningful only inside that namespace, and published-port source-IP behavior depends on RootlessKit/network-driver configuration. Since Engine 29.5, --net=host behavior also changed materially.

docker version
docker info --format '{{json .SecurityOptions}}'
docker inspect <container> --format '{{json .NetworkSettings.Networks}}'
docker port <container>
ps -ef | grep -E '[r]ootlesskit|[s]lirp4netns|[g]visor|[p]asta' || true

Do not disable host firewalls or switch to rootful Docker before proving which rootless network/port path is failing.

7. Failure: storage driver or backing filesystem assumption is wrong

docker info --format 'DockerRootDir={{.DockerRootDir}} Driver={{.Driver}}'
findmnt -T "$HOME/.local/share/docker" 2>/dev/null || true
uname -r

Rootless overlay2 depends on a sufficiently new kernel; other drivers have documented prerequisites. NFS is not a supported Docker data-root. A storage mismatch is not repaired by deleting the data root blindly.

8. Failure: “rootless-in-rootful DinD” is treated as non-privileged

Docker’s documented rootless DinD pattern still uses an outer privileged rootful container. The inner daemon runs as a non-root user, but the outer container’s privilege is the controlling host boundary. Treat that as a separate trust decision and record it explicitly.

Never use --privileged as a troubleshooting shortcut. If a CI architecture requires privileged DinD, document why, isolate the runner, and compare safer alternatives such as a dedicated rootless daemon/builder or an isolated VM.

9. Intentionally broken example: wrong context, not broken container

Create no destructive state. The “failure” is a client pointing at a nonexistent rootless-style Unix socket:

docker context create da-ch26-broken --docker "host=unix:///tmp/da-ch26-no-such.sock"
docker --context da-ch26-broken info || true
docker context inspect da-ch26-broken
docker context rm da-ch26-broken

The connection error proves a client/context/endpoint failure. It says nothing about image correctness, container runtime state, RootlessKit, cgroups, or storage. The repair is to select the correct known context, not restart daemons or delete runtime files.

Knowledge check

A context named “rootless” points to a normal rootful daemon. What is the first correction?

Why is chmod 777 the wrong fix for a bind-mount ownership mismatch?

Why can a rootless container IP be unreachable directly from the real host namespace?

A rootless workload needs an operation requiring a capability in the initial host user namespace. Will --cap-add necessarily solve it?

What does the intentionally broken context demonstrate?

Next lesson

Next: Checkpoint Lab — Rootless Docker, RootlessKit, User Namespaces, Networking, Storage, Limitations, and Threat Reduction

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

Official references and version notes

Version/platform baseline, verified 2026-09-22.

Docker Engine 29.8.1 is the current Engine release. Engine 29.5 changed packaged rootless networking so gvisor-tap-vsock is the preferred/default path when slirp4netns is not separately installed, and rootless host networking now reaches the real host network namespace. Engine 29.8 updates RootlessKit to 3.1.0 and adds the optional pesto port driver when paired with pasta (IPv4 only). Rootless resource limits require cgroup v2 plus systemd delegation; rootless storage support is host/kernel dependent. Docker Desktop uses an Engine inside a managed Linux VM and must not be described as ordinary Rootless Docker. Every lab therefore records actual docker version, context, security options, cgroup/storage/network state rather than assuming upstream defaults.

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.