Skip to content

Docker

Faber runs as a Docker container. The container must be privileged and see the host’s cgroup tree, because Faber creates namespaces and cgroups for every task. That makes the container root-equivalent on its host: give Faber a machine or VM of its own. See the isolation tier.

  • Linux 5.8 or newer, with cgroup v2 (stat -fc %T /sys/fs/cgroup prints cgroup2fs).
  • Rootful Docker. Rootless Docker cannot grant the nested mount operations.
  • x86_64 or ARM64.
ImageContents
vgfractal/faber:latestFaber plus GCC, G++ and Make. Moves with every push to main
vgfractal/faber:baseFaber and its runtime dependencies only, no compilers. The base for your own images
vgfractal/faber:<version>A released version, for example 0.3.0. Pin one in production

Both architectures are published under every tag.

Terminal window
docker run -d --name faber --init \
--privileged --cgroupns=host \
-v /sys/fs/cgroup:/sys/fs/cgroup:rw \
--read-only --tmpfs /tmp:size=64m \
--memory 8g --memory-swap 8g --pids-limit 4096 \
--restart unless-stopped \
-e API_KEY="$API_KEY" \
-p 127.0.0.1:3000:3000 \
vgfractal/faber:0.3.0
FlagWhy
--privileged, --cgroupns=host, -v /sys/fs/cgroup:/sys/fs/cgroup:rwRequired. Faber creates namespaces and cgroups beneath its own container’s cgroup, and refuses to start if the cgroup namespace and the mount disagree
--initReaps supervisor processes orphaned by an abnormal exit; Faber is not an init process
--read-only, --tmpfs /tmp:size=64mFaber writes only small sandbox root skeletons, under /tmp
--memory, --memory-swap, --pids-limitA backstop above Faber’s own aggregate limits. Size them with the sizing formula
-p 127.0.0.1:3000:3000Faber speaks plain HTTP; keep it on localhost and put a TLS proxy in front

Configure it with environment variables. The container stops cleanly on SIGTERM within SHUTDOWN_TIMEOUT_MS (5 s), below Docker’s default 10 s grace period.

Check it:

Terminal window
curl -s http://localhost:3000/api/v1/health
docker logs faber

Tasks see the image’s /usr, /bin and /lib read-only, so a language is available to tasks once it is installed in the image. Start from the base image and add only what you serve; the Dockerfile builder writes the Dockerfile for you.

A hand-written example:

FROM vgfractal/faber:base
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc g++ libc6-dev make python3 \
&& rm -rf /var/lib/apt/lists/*
ENV FABER_TOOLCHAINS=c@12,cpp@12,python@3.11

Things to get right:

  • Install under a read-only path. Tasks see only the paths in SANDBOX_READONLY_PATHS. If a toolchain needs files elsewhere (the JDK reads /etc/java-17-openjdk), add that path, keeping the defaults in the list.
  • Put commands on the sandbox PATH. Tasks do not inherit the image’s ENV. Their PATH is /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin unless the request sets one, so link binaries installed elsewhere (for example /usr/local/go/bin/go) into /usr/local/bin, or call them by absolute path.
  • Set FABER_TOOLCHAINS so GET /info can tell clients what the image offers, and FABER_IMAGE_ID if you enable the step cache.
  • Test every language under the default profile before relying on the image. scripts/toolchain-test.sh runs each language’s example against a running instance (API_URL, API_KEY); scripts/vm.sh test-toolchains does it inside a disposable VM.

Faber has no TLS. Terminate TLS in a reverse proxy on the same host and forward only /api/v1/. With Caddy:

Caddyfile
faber.example.com {
handle /api/v1/* {
reverse_proxy 127.0.0.1:3000
}
respond 404
}

With nginx, also raise the body size and the read timeout:

location /api/v1/ {
proxy_pass http://127.0.0.1:3000;
client_max_body_size 64m; # at least UPLOAD_FILE_LIMIT_BYTES
proxy_read_timeout 60s; # above OVERALL_TIMEOUT_MS
}

Only your own servers should hold the API key. Do not let browsers call Faber directly.

Pin a version tag, and upgrade by replacing the container. To avoid failed requests, take the instance out of the load balancer, wait until faber_execution_slots_in_use is 0, then replace it. See the runbook.