This guide provides setup instructions for running Nested Execution (running cderun recursively inside a container managed by cderun) on macOS environments.
Nested Execution relies on mounting the cderun binary and the container runtime socket (docker.sock or podman.sock) from the host into the container.
On macOS, this introduces two specific challenges:
- OS/Architecture Mismatch: The host
cderunbinary on macOS is compiled for Darwin (GOOS=darwin). However, the container runs Linux. A macOS binary cannot be executed inside a Linux container. - Socket GIDs: The host's
staton/var/run/docker.sockmight report a different Group ID (GID) than what is present inside the VM/container context, preventing automatic GID assignment from granting appropriate permissions.
To run Nested Execution successfully on macOS, you must configure a Linux-compatible cderun binary and ensure the container user has permission to access the container runtime socket.
The inner cderun executing inside the container must be a Linux binary matching the target container's architecture (e.g., linux/arm64 for Apple Silicon, or linux/amd64 for Intel).
You can cross-compile the Linux binary on your macOS host:
# For Apple Silicon Macs (M1/M2/M3/M4)
GOOS=linux GOARCH=arm64 go build -o cderun_linux_arm64 main.go
# For Intel-based Macs
GOOS=linux GOARCH=amd64 go build -o cderun_linux_amd64 main.goSpecify the pre-built Linux binary path using --mount-cderun-path on the CLI or in your global configuration file (.cderun.yaml):
# .cderun.yaml
defaults:
mountCderun: true
mountCderunPath: "./cderun_linux_arm64"To execute container commands recursively, the inner cderun needs access to the mapped socket file (e.g. /var/run/docker.sock). If you are running the container as a non-root user, you will face permission denied errors unless the container user belongs to the socket's owner group.
On macOS, since the socket is managed by a lightweight Linux VM (such as Docker Desktop or Podman), the automatic GID lookup on the host may not resolve correctly or match the VM's permissions.
To grant the necessary permissions, you must add the correct socket GID explicitly to the supplementary groups via the groupAdd configuration or the --cderun-group-add CLI flag.
⚠️ Security Warning on Socket Sharing: Sharing the container runtime socket (e.g.,/var/run/docker.sock) and granting access via supplementary numeric GID is a highly privileged operation. It allows any process within the container to control the container daemon, which is equivalent to granting full root-level access on the host system. Consequently, this setup must only be used in trusted, secure environments and should be explicitly flagged/warned in production designs.When considering alternatives, rootless Podman configurations reduce the blast radius compared with a rootful daemon because processes run as a non-root user on the host. However, please note that shared socket access still grants the owning user broad Podman control, including the ability to create containers and mount host volumes, which could still lead to host-level impact if abused.
Important: The value
102shown below is merely an example. The actual GID depends on your specific container runtime installation and environment on your machine. You must determine and configure the correct GID for your system.
To find the numeric GID of the socket as seen inside the container environment, run cderun with root user privileges to list the socket's file details:
cderun --mount-socket --user root alpine ls -ln /var/run/docker.sockThe output will look similar to this:
srw-rw---- 1 0 102 0 Jun 15 10:00 /var/run/docker.sock
In this output, the third column (0) is the owner UID (root), and the fourth column (102) is the owner GID. This GID (102 in this example) is the value you must use.
You must ensure that the value passed to groupAdd or --cderun-group-add is numeric (e.g. "102"), not a group name (e.g. "docker"). Numeric values are required because container runtime adapters (such as containerd) resolve permissions directly inside the container using GIDs and do not perform group name lookups.
Add the determined numeric GID to your configuration:
# .cderun.yaml
defaults:
groupAdd:
- "102" # Replace with your actual socket GID determined in Step 2.1Or pass it as a CLI option when running the command:
cderun node app.js --cderun-group-add 102To verify that socket access has been successfully configured, execute a command as a non-root user inside a container and verify that cderun can communicate with the runtime socket without permission errors:
cderun --mount-socket --user 1000 alpine sh -c "cderun --diagnosis"If the configuration is correct, the nested diagnosis will complete successfully and display the container runtime status instead of returning a permission denied error.
To achieve seamless nested execution on macOS, create a global configuration file (e.g., .cderun.yaml in your project root or ~/.config/cderun/.cderun.yaml):
runtime: docker # Configured for Docker Desktop; change to "podman" if using Podman on macOS
defaults:
mountCderun: true
mountCderunPath: "./cderun_linux_arm64" # Use the binary built for your host CPU architecture (use "./cderun_linux_amd64" for Intel-based Macs)
mountSocket: true
groupAdd:
- "102" # Replace with your actual socket GID determined in Step 2.1Usage Notes on Complete Configuration:
- Engine Selection: The
runtimeparameter is configured asdockerspecifically for Docker Desktop on macOS. If you are running Podman or another engine on your Mac, update this topodmanor your appropriate engine runtime.- CPU Architecture: Replace
mountCderunPathwith the path to thecderunbinary matching your Mac's host CPU architecture:
- For Apple Silicon Macs (M1/M2/M3/M4): Use
./cderun_linux_arm64- For Intel-based Macs: Use
./cderun_linux_amd64
Once configured, any recursive invocation of cderun (such as mounting tools defined in .tools.yaml) will run reliably inside your ephemeral containers on macOS.