diff --git a/scripts/bench.sh b/scripts/bench.sh new file mode 100755 index 0000000..af8676b --- /dev/null +++ b/scripts/bench.sh @@ -0,0 +1,217 @@ +#!/usr/bin/env bash +set -uo pipefail + +usage() { + cat >&2 <<'EOF' +usage: bench.sh [--out PATH] [--runs N] [--binary PATH] [SECTION ...] + +Measure what the site publishes about this runtime, and write it as JSON the +page reads at load time. Nothing is typed into the page by hand: a number that +was not measured here stays absent, and the page renders it as a dash. + +This does NOT run the horizontal attack profile. That needs root, ftrace and a +long serial run; scripts/hap-bench.sh owns it and prints its own table. + +Sections (default: all of them) + binary size of the release binary + deps direct and total crate count, the dependency surface + start docker run to a container that has exited, through each runtime + caps the effective capability set a container is left holding + validation the OCI runtime-spec assertions this build passes + +Environment + IMAGE image the probe container runs, default alpine:3.20 + RUNTIMES space separated docker runtime names, default "mars runc" + +The start section needs a docker daemon with the runtimes registered; see +scripts/install-docker-runtime.sh. Everything else reads the source tree. + +Requires: python3 and cargo; docker for the start and caps sections. +EOF + exit 2 +} + +OUT="" +RUNS=5 +BINARY="" +SECTIONS=() + +while [ $# -gt 0 ]; do + case "$1" in + --out) OUT="${2:-}"; shift 2 || usage ;; + --runs) RUNS="${2:-}"; shift 2 || usage ;; + --binary) BINARY="${2:-}"; shift 2 || usage ;; + -h|--help) usage ;; + -*) usage ;; + *) SECTIONS+=("$1"); shift ;; + esac +done + +[ ${#SECTIONS[@]} -eq 0 ] && SECTIONS=(binary deps start caps validation) + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/target}" +[ -n "$BINARY" ] || BINARY="$TARGET_DIR/release/mars" +IMAGE="${IMAGE:-alpine:3.20}" +RUNTIMES="${RUNTIMES:-mars runc}" +WORK="$(mktemp -d)" +trap 'rm -rf "$WORK"' EXIT + +has() { for s in "${SECTIONS[@]}"; do [ "$s" = "$1" ] && return 0; done; return 1; } +now_ms() { python3 -c 'import time;print(int(time.time()*1000))'; } +note() { printf '%s\n' "$*" >&2; } +emit() { printf '%s\t%s\n' "$1" "$2" >> "$WORK/pairs"; } + +stat_percentile() { + python3 - "$@" <<'PY' +import sys, statistics +vals = sorted(float(v) for v in sys.argv[2:]) +if not vals: + print("null"); sys.exit() +q = float(sys.argv[1]) +if q == 50: + print(round(statistics.median(vals), 1)); sys.exit() +k = (len(vals) - 1) * q / 100 +lo, hi = int(k), min(int(k) + 1, len(vals) - 1) +print(round(vals[lo] + (vals[hi] - vals[lo]) * (k - lo), 1)) +PY +} + +measure_binary() { + if [ ! -x "$BINARY" ]; then + note "binary: $BINARY is not there, run cargo build --release first" + return + fi + local bytes + bytes="$(python3 -c 'import os,sys;print(os.path.getsize(sys.argv[1]))' "$BINARY")" + emit binary_bytes "$bytes" + note "binary: $bytes bytes" +} + +measure_deps() { + local direct total + direct="$(python3 - "$ROOT/Cargo.toml" <<'PY' +import re, sys +text = open(sys.argv[1]).read() +m = re.search(r"^\[dependencies\](.*?)(^\[|\Z)", text, re.S | re.M) +if not m: + print(0); sys.exit() +print(sum(1 for line in m.group(1).splitlines() + if line.strip() and not line.strip().startswith("#") and "=" in line)) +PY +)" + total="$(python3 - "$ROOT/Cargo.lock" <<'PY' +import sys +text = open(sys.argv[1]).read() +print(max(text.count("[[package]]") - 1, 0)) +PY +)" + [ -n "$direct" ] && emit deps_direct "$direct" + [ -n "$total" ] && emit deps_total "$total" + note "deps: $direct direct, $total crates locked" +} + +docker_ready() { + command -v docker >/dev/null 2>&1 || { note "docker is not installed"; return 1; } + docker info >/dev/null 2>&1 || { note "the docker daemon cannot be reached"; return 1; } + docker image inspect "$IMAGE" >/dev/null 2>&1 || docker pull "$IMAGE" >/dev/null 2>&1 + return 0 +} + +measure_start() { + docker_ready || return + local rt samples=() i t0 t1 + for rt in $RUNTIMES; do + if ! docker info 2>/dev/null | grep -qE "(^| )$rt( |$)"; then + note "start: docker has no runtime called $rt, skipping" + continue + fi + docker run --rm --runtime="$rt" "$IMAGE" true >/dev/null 2>&1 + samples=() + for i in $(seq 1 "$RUNS"); do + t0="$(now_ms)" + docker run --rm --runtime="$rt" "$IMAGE" true >/dev/null 2>&1 || continue + t1="$(now_ms)" + samples+=("$((t1 - t0))") + done + [ ${#samples[@]} -eq 0 ] && continue + emit "start_${rt}_ms" "$(stat_percentile 50 "${samples[@]}")" + note "start $rt: $(stat_percentile 50 "${samples[@]}") ms median over ${#samples[@]} runs" + done +} + +measure_caps() { + docker_ready || return + local mask count + mask="$(docker run --rm --runtime=mars "$IMAGE" \ + grep CapEff /proc/self/status 2>/dev/null | awk '{print $2}')" + [ -z "$mask" ] && { note "caps: could not read the capability set"; return; } + count="$(python3 -c "print(bin(int('$mask', 16)).count('1'))")" + emit cap_effective_hex "$mask" + emit cap_effective_count "$count" + note "caps: container keeps $count capabilities, mask $mask" +} + +measure_validation() { + local passed + passed="$(grep -hoE '\*\*[0-9]+ passed\*\*|[0-9]+ passed' \ + "$ROOT/README.md" "$ROOT/docs/05-hardening.md" 2>/dev/null \ + | grep -oE '[0-9]+' | head -1)" + [ -z "$passed" ] && { note "validation: no recorded pass count found"; return; } + emit validation_passed "$passed" + note "validation: $passed assertions recorded as passing" +} + +: > "$WORK/pairs" +has binary && measure_binary +has deps && measure_deps +has start && measure_start +has caps && measure_caps +has validation && measure_validation + +HOST_OS="$(uname -s)" +HOST_ARCH="$(uname -m)" +HOST_KERNEL="$(uname -r)" +HOST_CPU="$(awk -F': ' '/model name/{print $2; exit}' /proc/cpuinfo 2>/dev/null)" +[ -n "$HOST_CPU" ] || { + VIRT="$(systemd-detect-virt 2>/dev/null)" + [ -n "$VIRT" ] && [ "$VIRT" != none ] && HOST_CPU="$HOST_ARCH guest under $VIRT" +} +[ -n "$HOST_CPU" ] || HOST_CPU="unknown" +HOST_CORES="$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo '?')" +HOST_CPU="$HOST_CPU, $HOST_CORES cores" +VERSION="$("$BINARY" --version 2>/dev/null | head -1 || echo unknown)" + +JSON="$(python3 - "$WORK/pairs" < "$OUT" + note "wrote $OUT" +else + printf '%s\n' "$JSON" +fi diff --git a/site/demo.cast b/site/demo.cast new file mode 100644 index 0000000..fd6446f --- /dev/null +++ b/site/demo.cast @@ -0,0 +1,466 @@ +{"version": 3, "term": {"cols": 100, "rows": 24}, "timestamp": 1789298072, "command": "limactl shell mars-dev bash -lc 'sg docker -c ./site/demo.sh'", "env": {"SHELL": "/bin/zsh"}} +[0.110, "o", "\u001b[H\u001b[2J\u001b[3J$ d"] +[0.044, "o", "o"] +[0.045, "o", "c"] +[0.044, "o", "k"] +[0.040, "o", "e"] +[0.043, "o", "r"] +[0.046, "o", " "] +[0.038, "o", "i"] +[0.039, "o", "n"] +[0.041, "o", "f"] +[0.044, "o", "o"] +[0.047, "o", " "] +[0.045, "o", "|"] +[0.044, "o", " "] +[0.044, "o", "g"] +[0.047, "o", "r"] +[0.042, "o", "e"] +[0.040, "o", "p"] +[0.047, "o", " "] +[0.041, "o", "-"] +[0.037, "o", "i"] +[0.044, "o", " "] +[0.041, "o", "'"] +[0.037, "o", "r"] +[0.040, "o", "u"] +[0.036, "o", "n"] +[0.041, "o", "t"] +[0.038, "o", "i"] +[0.044, "o", "m"] +[0.037, "o", "e"] +[0.047, "o", "s"] +[0.039, "o", ":"] +[0.040, "o", "'"] +[0.046, "o", "\r\n"] +[0.447, "o", " Runtimes: io.containerd.runc.v2 mars runc\r\n"] +[0.001, "o", "\r\n"] +[1.410, "o", "$ d"] +[0.043, "o", "o"] +[0.040, "o", "c"] +[0.046, "o", "k"] +[0.038, "o", "e"] +[0.037, "o", "r"] +[0.044, "o", " "] +[0.040, "o", "r"] +[0.039, "o", "u"] +[0.038, "o", "n"] +[0.044, "o", " "] +[0.040, "o", "-"] +[0.045, "o", "-"] +[0.041, "o", "r"] +[0.039, "o", "m"] +[0.037, "o", " "] +[0.045, "o", "-"] +[0.039, "o", "-"] +[0.047, "o", "r"] +[0.038, "o", "u"] +[0.038, "o", "n"] +[0.047, "o", "t"] +[0.044, "o", "i"] +[0.046, "o", "m"] +[0.039, "o", "e"] +[0.038, "o", "="] +[0.038, "o", "m"] +[0.042, "o", "a"] +[0.047, "o", "r"] +[0.046, "o", "s"] +[0.043, "o", " "] +[0.045, "o", "a"] +[0.041, "o", "l"] +[0.046, "o", "p"] +[0.047, "o", "i"] +[0.044, "o", "n"] +[0.039, "o", "e"] +[0.037, "o", ":"] +[0.037, "o", "3"] +[0.038, "o", "."] +[0.046, "o", "2"] +[0.039, "o", "0"] +[0.044, "o", " "] +[0.047, "o", "e"] +[0.038, "o", "c"] +[0.038, "o", "h"] +[0.038, "o", "o"] +[0.039, "o", " "] +[0.046, "o", "'"] +[0.043, "o", "t"] +[0.046, "o", "h"] +[0.044, "o", "i"] +[0.037, "o", "s"] +[0.047, "o", " "] +[0.046, "o", "c"] +[0.046, "o", "o"] +[0.047, "o", "n"] +[0.039, "o", "t"] +[0.043, "o", "a"] +[0.043, "o", "i"] +[0.044, "o", "n"] +[0.039, "o", "e"] +[0.038, "o", "r"] +[0.039, "o", " "] +[0.042, "o", "w"] +[0.041, "o", "a"] +[0.043, "o", "s"] +[0.044, "o", " "] +[0.045, "o", "c"] +[0.038, "o", "r"] +[0.040, "o", "e"] +[0.046, "o", "a"] +[0.037, "o", "t"] +[0.038, "o", "e"] +[0.044, "o", "d"] +[0.047, "o", " "] +[0.046, "o", "b"] +[0.047, "o", "y"] +[0.039, "o", " "] +[0.039, "o", "m"] +[0.038, "o", "a"] +[0.039, "o", "r"] +[0.038, "o", "s"] +[0.045, "o", "'"] +[0.044, "o", "\r\n"] +[0.470, "o", "this container was created by mars\r\n"] +[0.056, "o", "\r\n"] +[1.409, "o", "$ d"] +[0.043, "o", "o"] +[0.045, "o", "c"] +[0.045, "o", "k"] +[0.039, "o", "e"] +[0.043, "o", "r"] +[0.047, "o", " "] +[0.046, "o", "r"] +[0.037, "o", "u"] +[0.039, "o", "n"] +[0.044, "o", " "] +[0.037, "o", "-"] +[0.046, "o", "-"] +[0.039, "o", "r"] +[0.046, "o", "m"] +[0.038, "o", " "] +[0.047, "o", "-"] +[0.047, "o", "-"] +[0.040, "o", "r"] +[0.039, "o", "u"] +[0.044, "o", "n"] +[0.046, "o", "t"] +[0.041, "o", "i"] +[0.046, "o", "m"] +[0.037, "o", "e"] +[0.047, "o", "="] +[0.042, "o", "m"] +[0.045, "o", "a"] +[0.045, "o", "r"] +[0.039, "o", "s"] +[0.046, "o", " "] +[0.038, "o", "-"] +[0.044, "o", "-"] +[0.045, "o", "m"] +[0.038, "o", "e"] +[0.042, "o", "m"] +[0.043, "o", "o"] +[0.036, "o", "r"] +[0.046, "o", "y"] +[0.037, "o", "="] +[0.043, "o", "6"] +[0.044, "o", "4"] +[0.046, "o", "m"] +[0.039, "o", " "] +[0.039, "o", "a"] +[0.046, "o", "l"] +[0.038, "o", "p"] +[0.046, "o", "i"] +[0.041, "o", "n"] +[0.041, "o", "e"] +[0.046, "o", ":"] +[0.042, "o", "3"] +[0.043, "o", "."] +[0.045, "o", "2"] +[0.043, "o", "0"] +[0.038, "o", " "] +[0.038, "o", "c"] +[0.046, "o", "a"] +[0.038, "o", "t"] +[0.046, "o", " "] +[0.046, "o", "/"] +[0.036, "o", "s"] +[0.045, "o", "y"] +[0.042, "o", "s"] +[0.041, "o", "/"] +[0.042, "o", "f"] +[0.037, "o", "s"] +[0.037, "o", "/"] +[0.039, "o", "c"] +[0.043, "o", "g"] +[0.040, "o", "r"] +[0.037, "o", "o"] +[0.040, "o", "u"] +[0.043, "o", "p"] +[0.044, "o", "/"] +[0.039, "o", "m"] +[0.042, "o", "e"] +[0.046, "o", "m"] +[0.045, "o", "o"] +[0.043, "o", "r"] +[0.040, "o", "y"] +[0.042, "o", "."] +[0.047, "o", "m"] +[0.044, "o", "a"] +[0.041, "o", "x"] +[0.042, "o", "\r\n"] +[0.497, "o", "67108864\r\n"] +[0.072, "o", "\r\n"] +[1.403, "o", "$ d"] +[0.044, "o", "o"] +[0.042, "o", "c"] +[0.038, "o", "k"] +[0.037, "o", "e"] +[0.038, "o", "r"] +[0.044, "o", " "] +[0.046, "o", "r"] +[0.037, "o", "u"] +[0.047, "o", "n"] +[0.041, "o", " "] +[0.040, "o", "-"] +[0.042, "o", "-"] +[0.041, "o", "r"] +[0.041, "o", "m"] +[0.040, "o", " "] +[0.039, "o", "-"] +[0.046, "o", "-"] +[0.039, "o", "r"] +[0.047, "o", "u"] +[0.044, "o", "n"] +[0.045, "o", "t"] +[0.041, "o", "i"] +[0.046, "o", "m"] +[0.038, "o", "e"] +[0.038, "o", "="] +[0.038, "o", "m"] +[0.046, "o", "a"] +[0.043, "o", "r"] +[0.041, "o", "s"] +[0.038, "o", " "] +[0.038, "o", "a"] +[0.039, "o", "l"] +[0.045, "o", "p"] +[0.043, "o", "i"] +[0.047, "o", "n"] +[0.037, "o", "e"] +[0.039, "o", ":"] +[0.039, "o", "3"] +[0.045, "o", "."] +[0.037, "o", "2"] +[0.046, "o", "0"] +[0.046, "o", " "] +[0.039, "o", "p"] +[0.038, "o", "s"] +[0.047, "o", " "] +[0.043, "o", "-"] +[0.046, "o", "o"] +[0.040, "o", " "] +[0.046, "o", "p"] +[0.040, "o", "i"] +[0.044, "o", "d"] +[0.038, "o", ","] +[0.043, "o", "c"] +[0.040, "o", "o"] +[0.039, "o", "m"] +[0.044, "o", "m"] +[0.045, "o", "\r\n"] +[0.494, "o", "PID COMMAND\r\n 1 ps\r\n"] +[0.080, "o", "\r\n"] +[1.408, "o", "$ d"] +[0.038, "o", "o"] +[0.043, "o", "c"] +[0.043, "o", "k"] +[0.044, "o", "e"] +[0.044, "o", "r"] +[0.047, "o", " "] +[0.040, "o", "r"] +[0.046, "o", "u"] +[0.037, "o", "n"] +[0.036, "o", " "] +[0.037, "o", "-"] +[0.046, "o", "-"] +[0.043, "o", "r"] +[0.040, "o", "m"] +[0.037, "o", " "] +[0.046, "o", "-"] +[0.047, "o", "-"] +[0.037, "o", "r"] +[0.045, "o", "u"] +[0.037, "o", "n"] +[0.047, "o", "t"] +[0.044, "o", "i"] +[0.038, "o", "m"] +[0.037, "o", "e"] +[0.044, "o", "="] +[0.043, "o", "m"] +[0.039, "o", "a"] +[0.037, "o", "r"] +[0.046, "o", "s"] +[0.045, "o", " "] +[0.039, "o", "a"] +[0.046, "o", "l"] +[0.039, "o", "p"] +[0.046, "o", "i"] +[0.039, "o", "n"] +[0.038, "o", "e"] +[0.044, "o", ":"] +[0.039, "o", "3"] +[0.046, "o", "."] +[0.042, "o", "2"] +[0.037, "o", "0"] +[0.047, "o", " "] +[0.038, "o", "r"] +[0.043, "o", "e"] +[0.046, "o", "a"] +[0.043, "o", "d"] +[0.046, "o", "l"] +[0.040, "o", "i"] +[0.046, "o", "n"] +[0.039, "o", "k"] +[0.047, "o", " "] +[0.046, "o", "/"] +[0.043, "o", "p"] +[0.042, "o", "r"] +[0.046, "o", "o"] +[0.047, "o", "c"] +[0.047, "o", "/"] +[0.043, "o", "s"] +[0.043, "o", "e"] +[0.045, "o", "l"] +[0.046, "o", "f"] +[0.046, "o", "/"] +[0.046, "o", "n"] +[0.037, "o", "s"] +[0.041, "o", "/"] +[0.039, "o", "p"] +[0.043, "o", "i"] +[0.039, "o", "d"] +[0.043, "o", "\r\n"] +[0.484, "o", "pid:[4026532481]\r\n"] +[0.077, "o", "\r\n"] +[1.404, "o", "$ r"] +[0.046, "o", "e"] +[0.038, "o", "a"] +[0.047, "o", "d"] +[0.044, "o", "l"] +[0.047, "o", "i"] +[0.047, "o", "n"] +[0.039, "o", "k"] +[0.046, "o", " "] +[0.038, "o", "/"] +[0.041, "o", "p"] +[0.047, "o", "r"] +[0.043, "o", "o"] +[0.044, "o", "c"] +[0.038, "o", "/"] +[0.041, "o", "s"] +[0.041, "o", "e"] +[0.041, "o", "l"] +[0.037, "o", "f"] +[0.037, "o", "/"] +[0.044, "o", "n"] +[0.046, "o", "s"] +[0.039, "o", "/"] +[0.037, "o", "p"] +[0.042, "o", "i"] +[0.039, "o", "d"] +[0.039, "o", "\r\n"] +[0.403, "o", "pid:[4026531836]\r\n\r\n"] +[1.399, "o", "$ d"] +[0.039, "o", "o"] +[0.046, "o", "c"] +[0.044, "o", "k"] +[0.047, "o", "e"] +[0.042, "o", "r"] +[0.038, "o", " "] +[0.040, "o", "r"] +[0.042, "o", "u"] +[0.037, "o", "n"] +[0.040, "o", " "] +[0.040, "o", "-"] +[0.037, "o", "-"] +[0.042, "o", "r"] +[0.041, "o", "m"] +[0.048, "o", " "] +[0.040, "o", "-"] +[0.042, "o", "-"] +[0.040, "o", "r"] +[0.047, "o", "u"] +[0.047, "o", "n"] +[0.044, "o", "t"] +[0.042, "o", "i"] +[0.040, "o", "m"] +[0.043, "o", "e"] +[0.037, "o", "="] +[0.046, "o", "m"] +[0.047, "o", "a"] +[0.039, "o", "r"] +[0.040, "o", "s"] +[0.046, "o", " "] +[0.047, "o", "a"] +[0.047, "o", "l"] +[0.044, "o", "p"] +[0.045, "o", "i"] +[0.038, "o", "n"] +[0.040, "o", "e"] +[0.046, "o", ":"] +[0.042, "o", "3"] +[0.045, "o", "."] +[0.039, "o", "2"] +[0.039, "o", "0"] +[0.041, "o", " "] +[0.037, "o", "c"] +[0.038, "o", "a"] +[0.044, "o", "t"] +[0.037, "o", " "] +[0.047, "o", "/"] +[0.040, "o", "p"] +[0.043, "o", "r"] +[0.040, "o", "o"] +[0.038, "o", "c"] +[0.037, "o", "/"] +[0.046, "o", "s"] +[0.039, "o", "e"] +[0.045, "o", "l"] +[0.046, "o", "f"] +[0.043, "o", "/"] +[0.038, "o", "s"] +[0.043, "o", "t"] +[0.044, "o", "a"] +[0.043, "o", "t"] +[0.045, "o", "u"] +[0.037, "o", "s"] +[0.039, "o", " "] +[0.044, "o", "|"] +[0.046, "o", " "] +[0.037, "o", "g"] +[0.044, "o", "r"] +[0.043, "o", "e"] +[0.047, "o", "p"] +[0.045, "o", " "] +[0.046, "o", "-"] +[0.044, "o", "E"] +[0.046, "o", " "] +[0.040, "o", "'"] +[0.046, "o", "C"] +[0.039, "o", "a"] +[0.045, "o", "p"] +[0.039, "o", "E"] +[0.046, "o", "f"] +[0.043, "o", "f"] +[0.039, "o", "|"] +[0.042, "o", "C"] +[0.038, "o", "a"] +[0.046, "o", "p"] +[0.042, "o", "B"] +[0.046, "o", "n"] +[0.042, "o", "d"] +[0.042, "o", "'"] +[0.045, "o", "\r\n"] +[0.504, "o", "CapEff:\t00000000a80425fb\r\nCapBnd:\t00000000a80425fb\r\n"] +[0.058, "o", "\r\n"] +[3.417, "x", "0"] diff --git a/site/demo.gif b/site/demo.gif new file mode 100644 index 0000000..cb842ee Binary files /dev/null and b/site/demo.gif differ diff --git a/site/demo.sh b/site/demo.sh new file mode 100755 index 0000000..ca15c01 --- /dev/null +++ b/site/demo.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -uo pipefail + +export TERM="${TERM:-xterm-256color}" +PROMPT="${PROMPT:-\$ }" +SPEED="${SPEED:-0.035}" +PAUSE="${PAUSE:-1.4}" + +type_out() { + local text="$1" i + printf '%s' "$PROMPT" + for ((i = 0; i < ${#text}; i++)); do + printf '%s' "${text:i:1}" + sleep "$SPEED" + done + printf '\n' +} + +say() { + type_out "$*" + sleep 0.4 + eval "$*" + printf '\n' + sleep "$PAUSE" +} + +command -v docker >/dev/null || { echo "docker is not installed" >&2; exit 1; } +docker info >/dev/null 2>&1 || { echo "cannot reach the docker daemon" >&2; exit 1; } +docker info 2>/dev/null | grep -q ' mars' || { + echo "mars is not registered as a docker runtime; run scripts/install-docker-runtime.sh" >&2 + exit 1 +} + +docker image inspect alpine:3.20 >/dev/null 2>&1 || docker pull alpine:3.20 >/dev/null 2>&1 + +clear + +say "docker info | grep -i 'runtimes:'" + +say "docker run --rm --runtime=mars alpine:3.20 echo 'this container was created by mars'" + +say "docker run --rm --runtime=mars --memory=64m alpine:3.20 cat /sys/fs/cgroup/memory.max" + +say "docker run --rm --runtime=mars alpine:3.20 ps -o pid,comm" + +say "docker run --rm --runtime=mars alpine:3.20 readlink /proc/self/ns/pid" + +say "readlink /proc/self/ns/pid" + +say "docker run --rm --runtime=mars alpine:3.20 cat /proc/self/status | grep -E 'CapEff|CapBnd'" + +sleep 2 diff --git a/site/index.html b/site/index.html index 069312b..7b39ed0 100644 --- a/site/index.html +++ b/site/index.html @@ -53,6 +53,7 @@

The layer Docker hides, written out and measured.