Saving a container inside a container
Chrome and VS Code build small containers of their own. Until this week, our checkpoint tool could not save them.
October 29, 2026
Drums saves a running desktop and brings it back in about a second, so a training run can retry or branch from any point. We do this with our own build of CRIU, the open-source tool that freezes running programs and restores them later. In our first benchmark, 11 of the 12 tasks we could not save involved Chrome or VS Code. The reason was the same every time.
The problem
Linux isolates programs with namespaces: separate views of process IDs, users, files, network and so on. Containers are built from them. Modern browsers and editors also use them for their own safety features, so a desktop running Chrome holds a small container inside a bigger one. CRIU could save the outer layer but refused anything nested. The easy way around that is to switch those safety features off. We did not want to ask anyone to weaken their apps to fit Drums, so we built the missing support instead.
What we built
It came in four steps, each with its own tests before the next began.
- Process IDs at every level. A program inside nested namespaces has a different ID at each level. Every one now comes back exactly.
- Users and permissions. Nested user namespaces, with their ID maps and owners, are recorded and recreated in the right order.
- Everything else a container holds. Files and mounts, host names, shared memory, network sockets, finished processes waiting to be collected, and system-call filters.
- The same protections as before. Mounts a container inherited come back locked, as they were, so a restored container cannot remove them and look underneath.
How we checked it
Each new test builds a tree of processes, saves it, restores it, and compares dozens of details before and after: IDs at every level, users, permissions, namespace owners, mounts, sockets and filters. The processes then check themselves too. They collect their finished children, use their sockets and try to remove a locked mount, which must still fail.
| What | Result |
|---|---|
| New tests in the last step, including a container inside a container with every namespace type | 240 of 240 runs pass |
| Tests from the earlier steps, rerun on the final build | 320 of 320 pass |
| Existing CRIU tests, before and after our changes | identical results |
| Builds with one new piece switched off | the matching test fails every time |
The last row matters. A test that passes even when the feature is missing proves nothing, so we broke each piece on purpose and made sure its test noticed. Along the way we found and fixed four bugs, including two where shared memory from different namespaces overwrote each other.
What it does not cover yet
- Containers made by full container tools such as runc or podman. They set up their files in a way our restore does not rebuild yet.
- Two namespace types, for control groups and clocks, when they sit inside a nested user namespace.
- An open network connection inside a nested network namespace in one of our two test setups.
- So far everything ran on one machine with one Linux version (7.0).
What is next
Passing tests are the first checkpoint, not the finish line. We are now running Chrome and VS Code tasks with their safety features on, saving them, branching each into eight copies and checking every copy. We will publish a compatibility table of which apps and states pass, how often, and under how much load, including the ones that fail.
Measured on AWS (c8i.4xlarge, Linux 7.0) with our CRIU build based on version 4.3. Details and raw data are on bench.drums.run.