May 14, 2026·6 min read·engineeringdockerrootlessnamespaces

Docker Engine 29.5 changes rootless network boundaries

Engine 29.5 embeds a new rootless networking default and moves the rootless daemon into the host network namespace. Private time namespaces add a separate compatibility consideration.

Docker Engine 29.5.0 changes the default rootless network driver to gvisor-tap-vsock and enables private time namespaces on supported kernels. The May 14 release notes make the packaging consequence explicit. Docker no longer installs slirp4netns through its packages, and users should prefer the new driver. An upgrade assessment needs to consider both the selected driver and the network namespace in which the daemon runs.

I value Docker for making a built environment portable between machines. My preferred service image contains a static Go binary in a scratch final stage. That keeps the runtime filesystem small, but it does not explain the host's networking configuration. This release is a useful reminder to document the runtime environment alongside the image. An unchanged application artifact can encounter a different networking arrangement after an Engine upgrade.

RootlessKit now embeds the default driver

The RootlessKit integration change updates Docker to RootlessKit 3.0.0. It explains that gvisor-tap-vsock is embedded, so the setup no longer requires installing slirp4netns, vpnkit, or pasta separately. The change also removes vpnkit from Docker's integration. An embedded default reduces one external installation dependency, which I consider a useful improvement for reproducible host setup.

That change does not establish that every existing installation immediately uses the same driver. The implementation description says the other drivers remain in use when installed. I would inspect the effective configuration on an upgraded host before attributing a behavioral difference to gvisor-tap-vsock. A fresh installation and an existing installation may have different external binaries available.

This distinction affects how I would validate an upgrade. The test record should identify the selected network driver, the RootlessKit version, and any explicit overrides. Otherwise, a comparison between two hosts could accidentally compare different configurations. I would want a failure report to make that possibility easy to eliminate before examining application code.

The same change addresses client source addresses for the builtin port driver. It states that correct source-IP propagation requires disabling userland-proxy. I would treat that condition as part of an application's operational configuration if request handling or access policy depends on the observed client address. An improvement in a driver does not by itself establish that the whole request path preserves the address.

The pull request demonstrates the setting in the rootless daemon configuration:

{
  "userland-proxy": false
}

Its verification instructions also load br_netfilter and restart the user service. I would check the host prerequisites before adopting the example. Copying the JSON setting into a machine's configuration should be accompanied by a test that reaches the actual published application port and records what the application observes.

The daemon and container networks have different placement

A separate rootless networking change changes where the daemon runs. Previously, RootlessKit placed the daemon in a network namespace it created. The updated launcher uses RootlessKit's --detach-netns option so dockerd runs in the host network namespace. Docker's container-network namespaces remain inside the detached namespace associated with rootless networking.

The implementation explains why that arrangement is necessary. The rootless daemon does not have CAP_NET_ADMIN in the host network namespace. Placing the daemon there does not give it the authority to configure the host network as a privileged daemon would. Container-network allocation therefore uses the detached namespace.

This placement changes the meaning of a localhost registry reference for the daemon. The pull request explicitly addresses pulls from 127.0.0.1 and proper support for --net=host. It also identifies pulls, pushes, and builds as beneficiaries of moving daemon traffic into the host network namespace. I would avoid assigning a performance number to that change without measuring a particular workload.

The operational implication I would investigate first is whether an existing workaround is still needed. If a local registry setup contains an extra address solely to make the old namespace arrangement reachable, the upgrade may change that requirement. I would test the ordinary reference before deleting the workaround. Removing configuration should be based on the observed behavior of the upgraded installation.

Host networking also deserves an explicit test because its name can hide assumptions about which host is meant. I would document the namespace expected by the application and confirm the listeners it can reach. A test that succeeds against one selected endpoint should not become a general claim about access to every host service. The release changes a particular arrangement, and the validation should describe that arrangement.

Private time namespaces are a separate change

The time namespace implementation updates the default OCI configuration to request a private time namespace when the host supports it. Its history points to Linux 5.6 and OCI runtime specification 1.1.0 support. Docker detects host support before adding the namespace. This is a runtime default, independent of which rootless network driver the installation selects.

The initial implementation does not provide per-container options to select the host namespace, join another container's namespace, or choose a private namespace explicitly. Those choices require additional API work according to the change description. I would therefore avoid describing this release as a general-purpose container clock configuration interface.

An operator who needs the previous behavior has a daemon-wide feature override. The follow-up change documents this command:

dockerd --feature time-namespaces=false

The override restores the earlier default of using the host time namespace. Its scope matters. A daemon-level switch belongs in the host configuration record, and its presence should be visible during an upgrade review. I would not introduce it preemptively. I would use it only after identifying a compatibility reason and recording the evidence.

For applications with time-sensitive checks, I would compare behavior on the kernels actually used for deployment. Support detection makes the host kernel part of the condition under which the new default applies. An acceptance result from a host that does not support the namespace would not validate the same configuration as a result from one that does.

I would also keep the test's assertion specific. Seeing an extra namespace in a runtime configuration proves that the configuration contains it. That observation alone does not establish every property an application might expect from clocks. An application test should exercise its own requirement, and the runtime inspection should explain the environment in which that test ran.

I would include namespace support in the host inventory used by the release process. That would let an operator explain why two machines running the same Engine version receive different defaults. It would also make a kernel upgrade review ask whether the newly available namespace changes the environment accepted by the application tests. The relevant evidence should come from each supported host configuration.

An upgrade record should identify effective behavior

My first validation would use a small service whose published endpoint is easy to inspect. The RootlessKit change itself demonstrates publishing an nginx endpoint. I would extend that sort of check with the requirements of the actual application, especially any dependence on client addresses. This would remain a bounded compatibility check, with no assumption that a generic example proves production behavior.

I would then test registry access from the daemon using the addresses present in the deployment configuration. The useful question is whether the upgraded daemon reaches the intended registry with the intended reference. If a test fails, the namespace change gives a concrete mechanism to investigate. I would inspect daemon placement and configuration before changing credentials or rebuilding the application image.

The time-namespace check would have its own result. I would record whether the kernel supports the feature and whether a feature override disables it. Keeping that evidence distinct would help explain an application failure without conflating two changes delivered in the same Engine release.

For an existing installation, I would preserve the previous accepted host configuration as well as the previous application artifact. My image-building preferences already make the application artifact relatively easy to account for. These changes show why the host configuration deserves the same attention. A rollback assessment needs to identify which networking and namespace defaults it would restore.

The release gives operators useful improvements, including fewer external networking dependencies and more accurate host-network behavior for rootless Docker. I would adopt them with an acceptance record tied to the actual driver and host kernel. That record should also explain any retained overrides, so a later maintainer can distinguish a required compatibility setting from configuration left over from an earlier Engine.