[−][src]Crate bandsocks
🅱️🧦 bandsocks
it's a lightweight sandbox for Linux, written in pure Rust!
it runs docker images!
it can run nested inside unprivileged containers!
it's a library with minimal external dependencies!
it's highly experimental!
🎶 🎹🧦 🎸🧦 🎸🧦 🎷🧦 🎺🧦 🥁🧦 🎶
Scope
Let's make it easy to run somewhat-untrusted computational workloads like media codecs from inside an existing async rust app. There is no networking or traditional storage support inside containers. The container uses a virtual filesystem backed by read-only image contents and mounted I/O channels.
Getting Started
The easiest way to start is via Container::pull, which sets up a registry client with default options, downloads an image to cache as necessary, and provides a ContainerBuilder for further customization.
#[tokio::main] async fn main() { let s = "busybox@sha256:cddb0e8f24f292e9b7baaba4d5f546db08f0a4b900be2048c6bd704bd90c13df"; bandsocks::Container::pull(&s.parse().unwrap()) .await.unwrap() .arg("busybox").arg("--help") .interact().await.unwrap(); }
Architecture
The isolation in bandsocks comes primarily from a seccomp system call filter. A small set of system calls are allowed to pass through to the host kernel, while many system calls are disallowed entirely and others are emulated by our runtime.
There is a 1:1 relationship between virtualized processes and host processes, but virtual processes have their own ID namespace. File descriptors are also mapped 1:1, so that read() and write() syscalls can be a pass-through after files are opened via a slower emulated open() call.
The emulated paths look a bit like User Mode Linux or gvisor. A ptrace-based
runtime we call sand
is responsible for emulating operations like
open() and exec() using only allowed syscalls. For filesystem access, sand
uses an inter-process communication channel to request live file descriptors
from the virtual filesystem.
The sand
runtime is also written in Rust, but it uses a lower-level style
that bypasses the Rust and C standard libraries in order to have tight
control over its system call usage. It is a single process per container,
using asynchronous rust to respond to events from all processes/threads
within that particular container.
Structs
Container | A running container |
ContainerBuilder | Setup for containers, starting at Container::new() and ending with ContainerBuilder::spawn() |
ContentDigest | A digest securely identifies the specific contents of a binary object |
DefaultRegistry | Additional settings for compatibility with a default registry server |
ExitStatus | Status of an exited container |
Image | Loaded data for a container image |
ImageName | Parsed Docker-style image reference |
Output | Output from an exited container |
Registry | Name of a Docker-style image registry server |
RegistryClient | Registry clients can download and store data from an image registry |
RegistryClientBuilder | Builder for configuring custom RegistryClient instances |
Repository | Name of a Docker-style image repository |
RepositoryIter | Iterator over components of a Repository path |
SharedStream | A single UnixStream which has been shared with a container |
Tag | A tag identifying a specific image version by name |
Enums
ImageError | Errors during container image preparation |
ImageVersion | Either an image tag or a content digest |
RuntimeError | Errors that occur while a container is running |
VFSError | Errors from the virtual filesystem layer, convertible to an errno code |
Traits
Mount | A trait for the ability to mount into a container's filesystem |