84 lines
4.0 KiB
Bash
84 lines
4.0 KiB
Bash
|
|
#!/usr/bin/env bash
|
|||
|
|
# 強隔離 on this Mac: macOS can't run gVisor directly, and OrbStack/Docker Desktop's Linux VM
|
|||
|
|
# can't take it. This makes a small Ubuntu VM (Lima, Apple Virtualization) with its OWN Docker
|
|||
|
|
# and gVisor (runsc): Bot 的電腦 runs there on a virtualized kernel, verified by a sandboxed
|
|||
|
|
# Chromium — the Mac's kernel is a whole VM away.
|
|||
|
|
#
|
|||
|
|
# ./gvisor-vm.sh create + start the VM (idempotent; re-run to fix/update)
|
|||
|
|
# ./gvisor-vm.sh --rm remove the VM (the box's files live in a volume inside it)
|
|||
|
|
#
|
|||
|
|
# Afterwards, in AnyBot 設定 › 電腦 › 在哪裡執行:
|
|||
|
|
# Docker 主機: ssh://lima-anybot-gvisor
|
|||
|
|
# 容器隔離: 強隔離(gVisor)
|
|||
|
|
# and press 更新 on the computer card. (AnyBot's Docker host accepts ssh://, the VNC viewer
|
|||
|
|
# forwards through it.)
|
|||
|
|
set -euo pipefail
|
|||
|
|
VM=anybot-gvisor
|
|||
|
|
CPUS=4
|
|||
|
|
MEM=6 # GiB
|
|||
|
|
DISK=60 # GiB
|
|||
|
|
|
|||
|
|
if [ "${1:-}" = "--rm" ]; then
|
|||
|
|
limactl delete --force "$VM" 2>/dev/null || true
|
|||
|
|
echo "已移除 VM $VM。"
|
|||
|
|
exit 0
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
command -v limactl >/dev/null 2>&1 || { echo "先裝 Lima:brew install lima"; exit 1; }
|
|||
|
|
|
|||
|
|
STATUS=$(limactl list "$VM" --format '{{.Status}}' 2>/dev/null || true)
|
|||
|
|
if [ "$STATUS" = "Running" ]; then
|
|||
|
|
echo "VM $VM 已在執行。"
|
|||
|
|
elif [ -n "$STATUS" ]; then
|
|||
|
|
echo "VM $VM 是 $STATUS,啟動中…"
|
|||
|
|
limactl start --tty=false "$VM"
|
|||
|
|
else
|
|||
|
|
echo "建立 VM ${VM}($CPUS CPU / ${MEM}GB / ${DISK}GB,第一次要下載映像檔,幾分鐘)…"
|
|||
|
|
# template:docker-rootful = Lima's rootful Docker template (runsc wants a plain root daemon;
|
|||
|
|
# the rootless docker template runs the daemon in a user namespace).
|
|||
|
|
limactl start --name="$VM" --tty=false --cpus "$CPUS" --memory "$MEM" --disk "$DISK" template:docker-rootful
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo "VM 裡安裝 gVisor(runsc,systrap 平台:不需要 KVM,ARM VM 可用)…"
|
|||
|
|
limactl shell "$VM" -- bash -ec '
|
|||
|
|
set -e
|
|||
|
|
if ! command -v runsc >/dev/null 2>&1; then
|
|||
|
|
sudo mkdir -p /etc/apt/keyrings
|
|||
|
|
curl -fsSL https://gvisor.dev/archive.key | sudo gpg --dearmor -o /usr/share/keyrings/gvisor-archive-keyring.gpg
|
|||
|
|
echo "deb [signed-by=/usr/share/keyrings/gvisor-archive-keyring.gpg] https://storage.googleapis.com/gvisor/releases release main" | sudo tee /etc/apt/sources.list.d/gvisor.list >/dev/null
|
|||
|
|
sudo apt-get update -qq
|
|||
|
|
sudo apt-get install -y -qq runsc
|
|||
|
|
fi
|
|||
|
|
# Register the runtime in the VM'\''s Docker daemon (merge, do not clobber other settings).
|
|||
|
|
sudo python3 - <<EOF
|
|||
|
|
import json, os
|
|||
|
|
p = "/etc/docker/daemon.json"
|
|||
|
|
d = json.load(open(p)) if os.path.exists(p) else {}
|
|||
|
|
d.setdefault("runtimes", {})["runsc"] = {"path": "runsc"}
|
|||
|
|
os.makedirs("/etc/docker", exist_ok=True)
|
|||
|
|
json.dump(d, open(p, "w"), indent=2)
|
|||
|
|
EOF
|
|||
|
|
sudo systemctl restart docker
|
|||
|
|
# Prove the wall works: a container whose kernel really is gVisor.
|
|||
|
|
docker run --rm --runtime=runsc --entrypoint sh alpine:3.20 -c "grep -q gVisor /proc/version && uname -r" | sed "s/^/runsc 容器核心: /"
|
|||
|
|
'
|
|||
|
|
|
|||
|
|
# Bot 的電腦 lives in this VM: start it with the Mac, or after a restart the computer is gone
|
|||
|
|
# until someone runs this again.
|
|||
|
|
limactl autostart enable "$VM" >/dev/null 2>&1 || limactl start-at-login "$VM" --enabled >/dev/null 2>&1 || echo "(沒能設定開機自動啟動:Mac 重開機後要再跑一次這個腳本)"
|
|||
|
|
|
|||
|
|
# Lima forwards the VM's Docker socket to the Mac: AnyBot's Docker 主機用這個 unix:// 位址,
|
|||
|
|
# 不用 ssh、不用碰 ~/.ssh/config。
|
|||
|
|
SOCK="$HOME/.lima/$VM/sock/docker.sock"
|
|||
|
|
DOCKER_HOST="unix://$SOCK" docker info --format '{{range $k, $v := .Runtimes}}{{$k}} {{end}}' | grep -qw runsc || { echo "從 Mac 連到 VM 的 Docker 看不到 runsc"; exit 1; }
|
|||
|
|
KERNEL=$(DOCKER_HOST="unix://$SOCK" docker run --rm --runtime=runsc --entrypoint cat alpine:3.20 /proc/version | cut -d' ' -f3)
|
|||
|
|
|
|||
|
|
cat <<EOF
|
|||
|
|
|
|||
|
|
都好了(從 Mac 驗證:runsc 容器的核心是 $KERNEL)。AnyBot 設定 › 電腦 › 在哪裡執行:
|
|||
|
|
Docker 主機: unix://$SOCK
|
|||
|
|
容器隔離: 強隔離(gVisor)
|
|||
|
|
然後在電腦卡片按「建立/更新」。要讓舊 box 的檔案與登入跟著走,
|
|||
|
|
先完全退出 AnyBot、跑同資料夾的 gvisor-migrate.sh,再回來開。
|
|||
|
|
EOF
|