Rootless Docker and gVisor’s runsc runtime tighten different parts of the boundary around untrusted code, and you can use them together. Rootless Docker runs the daemon and its containers as a non-root user inside a user namespace, so the daemon is not running as host root. gVisor places a userspace application kernel between the workload and the host kernel. Neither control makes a workload safe on its own. The outcome depends on the exact Docker and gVisor versions, how the runtime is configured, which host paths and credentials the container can reach, what network access it has, and whether the program runs correctly under the chosen configuration.
There is no single Docker flag that makes running untrusted code safe. What follows explains what each layer covers, where it stops, and what to check before you run someone else’s code in this setup.
As an Amazon Associate I earn from qualifying purchases.
What each layer isolates
Rootless Docker: the daemon stops running as host root
In Rootless mode, both dockerd and the containers it starts run without host-root privileges. Docker’s Rootless mode documentation states the purpose in one sentence:
“Rootless mode lets you run the Docker daemon and containers as a non-root user to mitigate potential vulnerabilities in the daemon and the container runtime.”
The word “mitigate” is deliberate. Rootless mode limits the damage a daemon or runtime flaw can do on the host. It does not decide what the container is allowed to reach. That is a question of mounts, credentials and network access, covered below.
Rootless mode has host prerequisites: the newuidmap and newgidmap utilities, and subordinate UID and GID ranges assigned to your user, as listed in the same documentation.
Rank #2
Do not confuse Rootless mode with userns-remap. With userns-remap, container processes get remapped user IDs, but the daemon itself remains rootful. Anyone who can reach that daemon’s API can still ask it to create containers with access to host filesystems, which is why Docker’s guidance limits control of a rootful daemon to trusted users. If an untrusted process or a service account can reach a rootful daemon socket, remapping IDs does not change who controls that daemon.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
gVisor: a userspace kernel between the workload and the host
runsc is gVisor’s OCI runtime. Its sandbox includes an application kernel written in userspace, which handles the workload’s system calls instead of passing them straight to the host kernel. That reduces how much of the host kernel a workload touches directly. It is a separate runtime rather than a syscall filter added to an ordinary container, and it has its own compatibility profile.
Rank #3
Docker integrates it as an alternative runtime. You register the gVisor containerd shim in the Docker daemon configuration under a name you choose, then individual containers select it at run time. Read gVisor’s security introduction for its threat model. The practical summary is that the sandbox reduces direct exposure to the host kernel and does not eliminate risk. gVisor’s guidance is to decide deliberately what data containers can see, scope filesystem mappings tightly, and keep separate customers’ workloads in separate sandboxes.
How the two controls compare
The two controls answer different questions, so compare them along the axes that matter for your workload rather than looking for a winner.
| Question | Rootless Docker | gVisor (runsc as a Docker runtime) |
|---|---|---|
| Who holds privilege | The daemon and containers run as a non-root user in a user namespace. | Not a daemon-privilege control. It is a per-container runtime choice, and its support depends on the Docker version and configuration. |
| What a compromised daemon or runtime can do on the host | Limited, because the daemon does not hold host-root privileges. | Workload system calls are answered by gVisor’s userspace kernel, which limits direct contact with the host kernel. |
| Host files and credentials | Bind mounts can only expose paths the daemon’s user can already access. Anything mounted stays visible to the workload. | Mounted paths remain visible to the workload. gVisor’s guidance is to scope filesystem mappings deliberately. |
| Networking | Rootless networking uses user-mode drivers, whose TCP/IP stack can be slower than kernel networking, according to Docker’s rootless troubleshooting guide. | Depends on the network mode. Host networking uses the host network stack and gives up some isolation, according to gVisor’s FAQ. |
| Compatibility and resource controls | The --cpus, --memory and --pids-limit flags need cgroup v2 and systemd. |
Behavior differs from conventional containers in cases gVisor documents; kernel interfaces need testing. |
Setting up Rootless Docker
Run these checks on a Linux host, as the non-root user who will own the daemon.
- Check the prerequisites. Run
which newuidmap newgidmap; both must print a path. Then runcat /etc/subuid /etc/subgidand confirm your username has a range in each file. If it does not, add one with your distribution’s tooling. On many systems,usermodwith--add-subuidsand--add-subgids, each given a range argument, does this. - Check cgroup v2 and systemd. Run
stat -fc %T /sys/fs/cgroup/; the output should becgroup2fs. Runps -p 1 -o comm=; it should printsystemd. Docker documents the resource flags listed above as supported in rootless mode only with cgroup v2 and systemd, so without them do not count on those limits being enforced. - Install Rootless mode. Follow the setup steps in Docker’s Rootless mode documentation for your distribution and Docker release. Run the setup as the non-root user, not with
sudo. - Select the rootless CLI context. Run
docker context use rootless, thendocker context ls. The asterisk should sit onrootless. - Confirm the daemon you reach is rootless. Run
docker info --format '{{.SecurityOptions}}'; the output should includename=rootless. If it does not, your CLI is probably still reaching a rootful system daemon, which Docker’s setup documentation warns about. Stop that daemon or point the CLI at the rootless socket before continuing.
Registering gVisor as a Docker runtime
- Install
runscand its containerd shim using gVisor’s installation instructions. Choose the release that matches your Docker version’s row in gVisor’s Docker support table, and treat that table, not an older blog snippet, as the reference. - Register the shim as a runtime. For rootless Docker, the daemon configuration file is
~/.config/docker/daemon.json. Add an entry under theruntimeskey, named for examplerunsc, using the path and options that gVisor’s Docker guide specifies for your release. Docker’s alternative runtimes documentation describes the same mechanism. Older snippets online often use a different layout, so copy the current stanza rather than a remembered one. - Restart the rootless daemon: run
systemctl --user restart docker. - Confirm registration:
docker infoshould listrunscunder Runtimes. - Start a test container under gVisor: run
docker run -d --name runsc-check --runtime=runsc alpine sleep 300, thendocker inspect --format '{{.HostConfig.Runtime}}' runsc-check. It should printrunsc. Remove the test container withdocker rm -f runsc-check.
A correct Runtime value confirms that Docker selected gVisor. It says nothing about whether your workload runs correctly under it, which is the subject of the compatibility checks below.
Best Value
- Docker, Docker Swarm, Docker Compose, Programmer, Developer, Coding, Programming, Software Engineer, Code, DevOps, Deploy, Deployment, Kubernetes, Salt, Puppet, Chef, Terraform, Container, AWS, Azure, Cloud, Geek, Funny, Computer, Software, Tech, IT
- Integration, Scrum, Compile, Compilation, Science, Bug, Debug, Python, Linux, Java, Javascript, Scala, Dotnet, Kotlin
- Lightweight, Classic fit, Double-needle sleeve and bottom hem
Can gVisor run rootless?
Yes, in two forms with different limits. The second is the one relevant to Docker-style container workloads.
The built-in runsc --rootless mode
gVisor’s rootless documentation describes limitations in this built-in mode. It is mainly suitable for runsc do, which runs a command under gVisor without the Docker container interface. If your goal is running untrusted code through Docker containers, do not plan around this path.
Caller-configured user namespaces
This is the approach associated with higher-level tools such as Docker: the caller creates the user namespace and gVisor runs inside it. gVisor’s documentation says this method currently lacks network namespacing, so container networking in this mode does not get the separation you might assume from a sandbox. Enforce outbound limits at the host firewall or at a network boundary you manage outside the container, and test that blocked destinations stay blocked.
Limiting what the workload can reach
Neither layer decides what the workload can see on the host. Mounts, credentials and network configuration do that, and they are where the largest gaps usually appear.
- Bind mounts. Mount only the paths the job needs, and prefer read-only mounts such as
-v /path:/path:ro. Every mounted path stays visible to the workload, including under gVisor. - The Docker API socket. Never mount the daemon socket into an untrusted container. A container holding it can ask the daemon to start containers that mount host paths.
- Credentials. Do not copy host SSH keys, cloud tokens or CI secrets into the container’s filesystem or environment. Inject only short-lived, task-scoped values.
- Tenants. Run different customers’ or users’ workloads in separate sandboxes rather than sharing one sandbox, as gVisor’s guidance advises.
- Egress. Allow only the outbound destinations the task requires, and enforce that policy outside the container when you use the caller-configured user-namespace method.
Version and compatibility checks
Docker with gVisor works only in the pairings gVisor documents. Its Docker support table lists Docker 27, 28 and 29, each with version-specific configuration requirements. Docker 29 adds storage-backend considerations for nested or overlay environments, so a Docker 29 host running inside another VM or container needs checking against that row specifically. Support lists change between releases, so check the table on the day you deploy.
Quick Recap
- Test the real workload, including its file operations (permissions, file locking, directory watches), its network calls, and any less common kernel interfaces it uses, such as device nodes, unusual
/procentries or ioctls. - Read gVisor’s FAQ on behaviors that differ from conventional containers, and check each one against your code.
- Measure network-heavy jobs under the rootless network driver you will run in production, not under a rootful host’s kernel networking.
When to choose a different boundary
Rethink the design if any of these apply:
- The workload needs host networking or broad host access. The isolation gain described above does not cover those paths.
- The workload depends on kernel interfaces that the support table or FAQ does not cover for your versions. Test them, or move that tenant to a separate virtual machine.
- The only daemon available is a rootful one that other administrators control. A rootful daemon remains a root-equivalent control point, whatever runs inside it.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




