Skip to content

Commit 6db3325

Browse files
authored
devenv: Improve nested container support (#99)
The default containers.conf includes net.ipv4.ping_group_range=0 0 which fails in nested containers because /proc/sys is read-only. This causes 'podman build' to fail with: open `/proc/sys/net/ipv4/ping_group_range`: Read-only file system This matches the approach used by the official quay.io/podman/stable image (containers/image_build) which sets default_sysctls = [] in its podman-containers.conf. Assisted-by: OpenCode (claude-opus-4-5@20251101) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent a977825 commit 6db3325

2 files changed

Lines changed: 52 additions & 15 deletions

File tree

devenv/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,37 @@ base, but this helps prove out the general case of "src != target"
1515
that is a philosophy of bootc (and containers in general)
1616
as well as just helping prepare/motivate for bootc-on-Debian.
1717

18+
## Nested container support
19+
20+
This image supports running `podman` and `podman build` inside the container
21+
(podman-in-podman). The `userns-setup` script configures the environment at
22+
container startup.
23+
24+
### Reference: quay.io/podman/stable
25+
26+
Our nested container configuration is based on the official
27+
[quay.io/podman/stable](https://github.com/containers/image_build/tree/main/podman)
28+
image. Key differences:
29+
30+
| Feature | quay.io/podman/stable | bootc-devenv |
31+
|---------|----------------------|--------------|
32+
| **default_sysctls** | `[]` | `[]` |
33+
| **cgroups** | `"disabled"` | `"disabled"` (constrained) / `"no-conmon"` (full) |
34+
| **cgroup_manager** | `"cgroupfs"` | `"cgroupfs"` |
35+
| **netns/userns/ipcns/utsns/cgroupns** | `"host"` for all | `utsns = "host"` (constrained only) |
36+
| **BUILDAH_ISOLATION** | `chroot` (env var) | Not set (uses OCI default) |
37+
| **subuid/subgid** | Hardcoded for `podman` user | Dynamically calculated based on available UID range |
38+
| **storage** | Modified storage.conf for fuse-overlayfs | VOLUME mounts avoid overlay-on-overlay |
39+
40+
### Constrained vs full UID namespace
41+
42+
The `userns-setup` script detects whether we're running in a constrained UID
43+
namespace (typical for rootless podman, GitHub Codespaces, etc.) and adjusts:
44+
45+
- **Full namespace** (>100k UIDs): Uses default subuid/subgid, `cgroups = "no-conmon"`
46+
- **Constrained namespace** (<100k UIDs): Dynamically calculates subuid/subgid
47+
ranges, uses `cgroups = "disabled"` and `utsns = "host"`
48+
1849
## Building locally
1950

2051
See the `Justfile`, but it's just a thin wrapper around a default

devenv/userns-setup

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ This handles:
77
- /dev/kvm permissions
88
- subuid/subgid configuration for constrained UID namespaces
99
- containers.conf configuration for nested operation
10+
11+
Reference: quay.io/podman/stable image configuration
12+
https://github.com/containers/image_build/tree/main/podman
1013
"""
1114

1215
import argparse
@@ -169,28 +172,31 @@ def configure_containers_conf() -> None:
169172

170173
is_constrained, _ = detect_constrained_namespace()
171174

175+
conf_dir = Path("/etc/containers")
176+
conf_dir.mkdir(parents=True, exist_ok=True)
177+
conf_path = conf_dir / "containers.conf"
178+
172179
if not is_constrained:
173-
# Full namespace - just update the shipped config
174-
conf_path = Path("/usr/share/containers/containers.conf")
175-
if conf_path.exists():
176-
content = conf_path.read_text()
177-
content = content.replace("#cgroups =", 'cgroups = "no-conmon" #')
178-
content = content.replace("#cgroup_manager =", 'cgroup_manager = "cgroupfs" #')
179-
conf_path.write_text(content)
180+
header = "# Generated for nested container support"
181+
container_settings = 'cgroups = "no-conmon"'
180182
else:
181-
# Constrained namespace - create full config for nested operation
182-
conf_dir = Path("/etc/containers")
183-
conf_dir.mkdir(parents=True, exist_ok=True)
184-
conf_path = conf_dir / "containers.conf"
185-
conf_path.write_text("""\
186-
# Generated for nested container support in constrained UID namespace
183+
header = "# Generated for nested container support in constrained UID namespace"
184+
container_settings = 'cgroups = "disabled"\nutsns = "host"'
185+
186+
conf_path.write_text(f"""\
187+
{header}
188+
# Reference: https://github.com/containers/image_build/tree/main/podman
187189
[containers]
188-
cgroups = "disabled"
189-
utsns = "host"
190+
# Disable default sysctls - /proc/sys is read-only in nested containers
191+
# (specifically net.ipv4.ping_group_range causes "Read-only file system" errors)
192+
# See: https://github.com/containers/common/blob/main/pkg/config/containers.conf
193+
default_sysctls = []
194+
{container_settings}
190195
191196
[engine]
192197
cgroup_manager = "cgroupfs"
193198
""")
199+
if is_constrained:
194200
print("Configured containers.conf for constrained UID namespace")
195201

196202

0 commit comments

Comments
 (0)