Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
# Editor / OS
.DS_Store
*.swp
.check/
.containerignore
.dockerignore
18 changes: 18 additions & 0 deletions box/check-nerdctl-app/charly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# check-nerdctl-app — the disposable bed image for the layer-nerdctl R10: a Fedora
# base composing the nerdctl stack candy, so the nested-pod posture (cap_add ALL,
# /dev/fuse, /dev/net/tun, unmask /proc/*) is emitted onto a real pod.
check-nerdctl-app:
candy:
version: 2026.266.1730
description: |
Disposable bed image for the layer-nerdctl R10 — a Fedora base composing
layer-nerdctl, so the nested-pod posture is emitted and can be asserted.
base: quay.io/fedora/fedora:43
candy:
- layer-nerdctl
plan:
- check: nerdctl is installed by the composed layer-nerdctl candy
command: command -v nerdctl
exit_status: 0
- check: the nerdctl.toml written by the candy is present
file: /etc/nerdctl/nerdctl.toml
56 changes: 56 additions & 0 deletions candy/layer-nerdctl/charly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ layer-nerdctl:
info, the rootless probe, and the fuse-overlayfs snapshotter.
var:
NERDCTL_FULL_VERSION: "2.1.2"
security:
# The nested-pod posture for the OUTER pod (userns-scoped): the inner
# rootless engine needs the full capability set WITHIN its user namespace,
# /dev/fuse for the fuse-overlayfs snapshotter, /dev/net/tun for the CNI
# bridge, and the /proc/* unmask so the inner runtime can re-mount /proc.
# These are userns-scoped — the inner engine's userns-root is NOT host root.
cap_add:
- ALL
devices:
- /dev/fuse
- /dev/net/tun
security_opt:
- unmask=/proc/*
distro:
arch:
package:
Expand Down Expand Up @@ -107,3 +120,46 @@ layer-nerdctl:
exit_status: 0
- check: the charly CNI network conflist is present
file: /etc/cni/net.d/charly.conflist

# ---- HARNESS SKILL ----
layer-nerdctl-skill:
skill:
name: layer-nerdctl
family: distros
owner: layer-nerdctl
description: "nerdctl (containerd CLI) + the rootless containerd/buildkit/CNI stack — native Arch/Alpine packages, the pinned sha256 nerdctl-full tarball on Fedora/Debian/Ubuntu, nerdctl.toml + the charly CNI conflist + the nested-pod posture. Use when working with the nerdctl engine, the layer-nerdctl candy, or engine: nerdctl deploys."
content: |
# layer-nerdctl

nerdctl (the containerd CLI) plus the rootless containerd + buildkit + CNI
stack, as ONE candy. Composed by a box that wants the opt-in `engine: nerdctl`
engine.

## What it installs

- **Native packages** on Arch/CachyOS/Omarchy and Alpine: `nerdctl`,
`cni-plugins`, `rootlesskit`, `slirp4netns`, `buildkit`, `fuse-overlayfs`,
`crun`, `iptables-nft` (arch) / `iptables` (alpine).
- **Non-native distros** (Fedora/Debian/Ubuntu) install the pinned,
sha256-verified `nerdctl-full` tarball (step `nerdctl-full-tarball`), which
supplies nerdctl + containerd + `containerd-fuse-overlayfs-grpc` + CNI +
buildkit + rootlesskit in one archive.
- `/etc/nerdctl/nerdctl.toml` (charly namespace + rootless buildkit host) and
the `charly` CNI network conflist at `/etc/cni/net.d/charly.conflist`.
- The **nested-pod posture**: userns-scoped `cap_add: ALL`, `/dev/fuse`,
`/dev/net/tun`, `unmask=/proc/*`.

## Engine capability

The `engine: nerdctl` word is served by `opencharly/plugin-nerdctl`
(out-of-process) or compiled in; every engine op delegates to
`container.InvokeEngineOp("nerdctl", …)` in the spec module. nerdctl has no
`--keep-id`, so the start-plan runs the workload as `--user 0:0` (uid 0 == the
host user under rootless), guaranteeing uid-identical sharing; a non-zero uid
needs the subuid caveat.

## Use when

Working with the nerdctl engine, the layer-nerdctl candy, or an
`engine: nerdctl` deploy.

28 changes: 28 additions & 0 deletions charly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,31 @@ defaults:
platform:
- linux/amd64
build: [rpm]

# check-nerdctl-nested — the R10 bed for the layer-nerdctl nested-pod posture: a
# disposable pod composing the nerdctl stack, asserting the emitted devices +
# capability posture on a FRESH deploy. Fails without the security: block.
check-nerdctl-nested:
pod:
image: check-nerdctl-app
disposable: true
lifecycle: test
description: |
The nested-pod R10 bed: deploy a disposable pod composing layer-nerdctl and
assert the outer-pod posture the inner rootless engine needs — /dev/fuse,
/dev/net/tun, and the userns-scoped full capability set (cap_add: ALL).
plan:
- check: the fuse device is present for the fuse-overlayfs snapshotter
file: /dev/fuse
- check: the tun device is present for the CNI bridge
file: /dev/net/tun
- check: the exact full capability mask is retained (cap_add ALL)
command: grep -qE '^CapEff:\s+000001ffffffffff$' /proc/self/status
exit_status: 0
- check: the pod is userns-scoped (uid 0 inside maps to the host user, not host root)
command: grep -qE '^\s+0\s+1000\s+1\s*$' /proc/self/uid_map
exit_status: 0
- check: nerdctl is on PATH in the nested pod
command: command -v nerdctl
exit_status: 0

Loading