Guest runner
What it is​
runner-guest is the process that executes code inside the microVM. It is compiled statically for Linux and injected into every image as /opt/runner/guest. On the host, it lives at bin/rc-guest-linux-<arch>.
Why static and separate from the host: the host loads libkrun through purego, which forces dynamic linking against glibc on Linux. The language images are Alpine (musl); a dynamic binary there fails with /opt/runner/guest: not found.
How it starts​
The first process of a job VM is /opt/runner/start.sh:
mount -t tmpfs -o size=256m,mode=1777 tmpfs /tmp
# /dev/stdin, /dev/stdout, /dev/stderr and /dev/fd as links to /proc/self/fd
...
# environment from the image's OCI config (PATH, JAVA_HOME...), one variable per line
while IFS= read -r l; do [ -n "$l" ] && export "$l"; done < /opt/runner/env
mkdir -p /tmp/home
export HOME=/tmp/home
# Go build cache warmed in the image, copied to the path the executor enforces
if [ -d /opt/runner/gocache ]; then
cp -a /opt/runner/gocache /tmp/go-cache
fi
exec /opt/runner/guest --port 5000
(Summary of internal/adapters/oci/scripts/start.sh.) In a persistent machine, the first process is
/opt/runner/machine.sh, which mounts the disk and the overlay and runs the same guest in a chroot.
The guest listens on vsock port 5000. libkrun binds that port to a Unix socket on the host.
What it does with a job​
- Reads a frame (4 big-endian bytes of length + JSON) with the job.
- Checks the language and the stdin size.
- Creates a temporary directory under
/tmpand writes the files:- with
files, it writes each one by name; the first is the main file; - with only
code, it writesscript.<ext>(Java:Main.java).
- with
- Runs it according to the language type:
- interpreted (Python, Node.js, Ruby, PHP, Perl, Bash, sh, AWK, jq):
<interpretador> <arquivo>; - compiled (C, C++, Rust): compiles to a binary and runs the binary;
- JVM (Java):
javacand thenjava Main; - Go:
go run; - SQLite: the code goes through the stdin of
sqlite3 :memory:.
- interpreted (Python, Node.js, Ruby, PHP, Perl, Bash, sh, AWK, jq):
- Applies the job timeout (default 10 s).
- Responds with a result frame.
A compilation failure returns exception: "Compilation failed" with the compiler error in stderr. A timeout returns exception: "Timeout".
Other operations​
Besides running code, the guest serves the machine operations, all over the same protocol: exec (argv with no
implicit shell, with env, directory and user), put/get (file copy in 1 MiB chunks), pty (interactive
terminal), workload (the process the machine keeps running), shutdown (signal to the workload, sync and exit),
dial (published port, dialing the guest's 127.0.0.1), set-env (in-memory-only secrets), ssh-agent (socket for
the host's SSH agent) and mount-s3 (s3:// volume via FUSE). Details in vsock protocol.
Isolation between jobs​
The guest does not need to clean anything up between jobs: each VM serves a single job and is destroyed. The tmpfs goes away with it.
Languages the guest knows​
The guest executor (internal/guest/executor.go) has entries for more languages than the catalog publishes. Only the 15 in languages.yaml have an image and are accepted by the API.