Add README.md
Human-facing overview (what/why/status, build/usage instructions, brief architecture summary) alongside CLAUDE.md, which stays the dense agent-facing reference. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
# slocker-lite
|
||||
|
||||
`slocker-lite` mounts an [OCI Image Layout](https://github.com/opencontainers/image-spec/blob/main/image-layout.md)
|
||||
tar (the format produced by `skopeo`, `podman save --format oci-archive`, or a modern
|
||||
`docker save`) and runs a sandboxed command against it — without `podman`, `docker`,
|
||||
or kernel overlayfs.
|
||||
|
||||
## Why
|
||||
|
||||
The target environment is Android with a stock kernel: `podman`/`docker` don't run
|
||||
there (missing namespace support), and there's no kernel overlayfs. `slocker-lite`
|
||||
works around both: it imports image layers into `containers-storage` and mounts them
|
||||
with `fuse-overlayfs` (userspace, no kernel overlayfs needed), then sandboxes the run
|
||||
with `bwrap` in "degraded mode" — using only whichever `--unshare-xxx` namespaces the
|
||||
running kernel actually supports, instead of requiring the full set.
|
||||
|
||||
## Status
|
||||
|
||||
Early-stage. Mounting, running, and dropping privileges to a specific user/group all
|
||||
work. Volumes and image-declared networking (`Volumes`/`ExposedPorts`/`Env` from the
|
||||
image config) are parsed but not yet applied, and there's no background/daemonized
|
||||
run mode yet.
|
||||
|
||||
## Requirements
|
||||
|
||||
Build-time:
|
||||
- Meson + a C++20 compiler
|
||||
- `fmt`, `libarchive`, `nlohmann_json`, `yaml-0.1` (libyaml)
|
||||
- `spdlog` (uses the system package if found, otherwise fetched automatically via
|
||||
the vendored `subprojects/spdlog.wrap`)
|
||||
- `catch2`, only if the `enable_tests` Meson option is on (default: on)
|
||||
|
||||
Runtime:
|
||||
- `containers-storage`
|
||||
- `fuse-overlayfs`
|
||||
- `bwrap` (bubblewrap)
|
||||
- `nsenter` (only needed for non-root runs — see "How it works" below)
|
||||
|
||||
## Build
|
||||
|
||||
```sh
|
||||
meson setup buildDir
|
||||
meson compile -C buildDir
|
||||
meson test -C buildDir
|
||||
```
|
||||
|
||||
This also builds `buildDir/slocker-lite-priv-drop`, a small statically-linked helper
|
||||
that `-r --user`/`--group` needs at runtime (see "How it works").
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
slocker-lite -m|--mount <image.tar>
|
||||
slocker-lite -r|--run <image.tar> [-- <command> [args...]]
|
||||
slocker-lite -u|--umount <layer-id>
|
||||
slocker-lite -c|--cleanup <layer-id>
|
||||
slocker-lite -l|--list-images <directory>
|
||||
slocker-lite -t|--test
|
||||
slocker-lite -h|--help
|
||||
slocker-lite -V|--version
|
||||
```
|
||||
|
||||
| Flag | Description |
|
||||
| --- | --- |
|
||||
| `-m, --mount <image.tar>` | Validate and mount an OCI Image Layout tar. |
|
||||
| `-r, --run <image.tar>` | Mount, run `bwrap` in the foreground, then unmount and clean up on exit. Defaults to the image's own `Entrypoint`/`Cmd` (or `/bin/sh` if neither is set); pass `-- <command> [args...]` to override. |
|
||||
| `-u, --umount <layer-id>` | Unmount a previously mounted layer (the ID printed by `--mount`/`--run`, or from `containers-storage layers`). |
|
||||
| `-c, --cleanup <layer-id>` | Delete a layer and its ancestor chain from local storage (unmount it first). |
|
||||
| `-n, --no-nsenter` | With `--run`, bind the mount directly instead of `nsenter`-ing into `fuse-overlayfs`'s namespace. Automatic when running as root; use this to force it off otherwise. |
|
||||
| `--user <user>` | With `--run`, run the command as this user (name or numeric uid) instead of the image's own declared user (or root, if it declares none). Resolved against the image's own `/etc/passwd`. Only takes effect when `--run` executes as root. |
|
||||
| `--group <group>` | With `--user`, use this group (name or numeric gid) instead of the user's primary group. |
|
||||
| `-l, --list-images <dir>` | List OCI Image Layout tars (`*.tar`, `*.tar.*`) found directly in `<dir>`, with their `name:tag`. |
|
||||
| `-t, --test` | Print which `bwrap --unshare-xxx` namespaces the running kernel supports. |
|
||||
| `--log-level <level>` | Set log verbosity (`trace`, `debug`, `info`, `warn`, `error`, `critical`, `off`). |
|
||||
| `-h, --help` | Print usage and exit. |
|
||||
| `-V, --version` | Print version information and exit. |
|
||||
|
||||
### Examples
|
||||
|
||||
```sh
|
||||
# Mount an image and inspect it (prints the merged mount path)
|
||||
./buildDir/slocker-lite -m myimage.tar
|
||||
|
||||
# Mount, run the image's default command, then unmount and clean up
|
||||
./buildDir/slocker-lite -r myimage.tar
|
||||
|
||||
# Run a specific command instead
|
||||
./buildDir/slocker-lite -r myimage.tar -- /bin/sh -c 'echo hello'
|
||||
|
||||
# Run as a specific user (as root only)
|
||||
sudo ./buildDir/slocker-lite -r myimage.tar --user git
|
||||
|
||||
# List every OCI image tar in a directory
|
||||
./buildDir/slocker-lite -l ./images
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
Image layers are imported into `containers-storage` (parent-chained) and the
|
||||
resulting top layer is mounted via `fuse-overlayfs`; `-r/--run` then sandboxes the
|
||||
requested command with `bwrap`. Because `containers-storage mount` runs rootless by
|
||||
re-execing into a private user+mount namespace, `-r/--run` normally has to `nsenter`
|
||||
into that namespace to reach the mount — except when running as root, where the mount
|
||||
is already directly visible and `--unshare-user` is skipped entirely (a fresh user
|
||||
namespace isn't needed for root's own privilege, and forces an unrelated
|
||||
supplementary-group bug in that case). Running as root also unlocks `--user`/
|
||||
`--group`: since `bwrap --uid`/`--gid` require a user namespace that isn't available
|
||||
there, `slocker-lite` instead bind-mounts a separate, statically-linked helper
|
||||
(`slocker-lite-priv-drop`) into the sandbox and routes the command through it to drop
|
||||
privileges before exec.
|
||||
|
||||
See `CLAUDE.md` for the full architecture writeup (file-by-file breakdown, the
|
||||
reasoning behind each of the above, and known gaps).
|
||||
|
||||
## License
|
||||
|
||||
GPL-2.0-or-later. See [`COPYING`](COPYING).
|
||||
Reference in New Issue
Block a user