项目文件夹

文件
2026-07-13 13:13:07 +08:00

119 行
6.3 KiB
Plaintext

# Docker inside a smolvm microVM
#
# Runs Docker Engine in a bare Alpine VM. Init commands run directly in the VM
# as root via VmExec, so Docker gets full kernel privileges without any
# capability restrictions.
#
# This also works with `--image`: a privileged (default) image-based machine
# runs in an OCI container, but /storage is bind-mounted into it, so the same
# `mount --bind /storage/docker /var/lib/docker` resolves to the ext4 disk just
# as in a bare VM.
#
# ── Kernel requirements ───────────────────────────────────────────────────────
#
# Requires libkrunfw built from config-libkrunfw_aarch64_lean (or later) with:
# CONFIG_OVERLAY_FS=y — overlayfs (rootfs overlay)
# CONFIG_NETFILTER=y — iptables/nftables for Docker networking
# CONFIG_NF_TABLES=y — nftables netlink (Alpine's iptables-nft)
# CONFIG_NFT_COMPAT=y — iptables compatibility via nftables
# CONFIG_BRIDGE=y — docker0 bridge interface
#
# If the current libkrunfw.5.dylib lacks these, see docs/building-libkrunfw-macos.md.
#
# ── Storage driver note ───────────────────────────────────────────────────────
#
# Docker's /var/lib/docker MUST be on ext4 (/dev/vda), not on the rootfs
# overlayfs. This is a hard requirement, not a workaround.
#
# Why: the smolvm rootfs overlay uses the initramfs (ramfs) as its lower
# layer. Ramfs has no file-handle support (no exportfs). This propagates up
# through the overlayfs — any directory ON the rootfs overlay (like
# /var/lib/docker) also lacks file-handle support. The kernel then falls
# back to index=off and rejects it as an upper dir for Docker's nested
# overlay, regardless of CONFIG_OVERLAY_FS_REDIRECT_DIR or index=on mount
# options.
#
# Fix: bind-mount /storage/docker → /var/lib/docker before starting dockerd.
# /storage/ is mounted from /dev/vda (ext4), which supports file handles.
# Docker's overlay2 layers then live on ext4 and nest correctly.
#
# This bind-mount must be re-applied after every VM start (mounts don't
# persist across stop/start). The init commands create the directory on
# first start; the "Start dockerd" exec command does the bind-mount each
# time.
#
# ── Create and start ─────────────────────────────────────────────────────────
#
# smolvm machine create --name docker -s examples/docker-in-vm/docker.smolfile --net-backend virtio-net
# smolvm machine start --name docker
#
# ── Start dockerd ─────────────────────────────────────────────────────────────
#
# smolvm machine exec --name docker -- sh -c '
# mkdir -p /storage/docker /var/lib/docker
# mount --bind /storage/docker /var/lib/docker
# rm -f /var/run/docker.pid
# dockerd --storage-driver=overlay2 >/tmp/dockerd.log 2>&1 &
# for i in $(seq 1 30); do docker info >/dev/null 2>&1 && break; sleep 1; done
# docker info | grep "Storage Driver"'
#
# ── Run containers ────────────────────────────────────────────────────────────
#
# # Pull an image
# smolvm machine exec --name docker -- docker pull alpine
#
# # Run with bridge networking (default — requires netfilter kernel config)
# smolvm machine exec --name docker -- docker run --rm alpine echo "hello from docker"
#
# # Run with host networking (works even without netfilter)
# smolvm machine exec --name docker -- docker run --rm --network=host alpine wget -qO- https://example.com
#
# # Build an image
# smolvm machine exec --name docker -- sh -c '
# printf "FROM alpine\nRUN echo built" > /tmp/Dockerfile
# docker build -t myapp /tmp'
#
# ── Interactive shell inside a Docker container ───────────────────────────────
#
# smolvm machine exec -i --name docker -- docker run --rm -i alpine sh
#
# ── Kubernetes (K3d / kind) ───────────────────────────────────────────────────
#
# The guest kernel + this setup run k3s. The engine now creates /dev/kmsg in
# the container /dev (the kubelet hard-requires it), so K3d works with no extra
# prep beyond a running dockerd:
#
# smolvm machine exec --name docker -- sh -c '
# curl -sL https://github.com/k3d-io/k3d/releases/latest/download/k3d-linux-$(uname -m | sed s/aarch64/arm64/;s/x86_64/amd64/) -o /usr/local/bin/k3d
# chmod +x /usr/local/bin/k3d
# k3d cluster create dev --no-lb
# kubectl get nodes' # -> node Ready
#
# ── Cloud (smolmachines) note ─────────────────────────────────────────────────
#
# On the cloud platform each `exec` runs in its own mount namespace, so the
# `mount --bind` above is invisible to dockerd. Point docker's data-root
# straight at the ext4 disk instead:
#
# dockerd --data-root=/storage/docker --storage-driver=overlay2
#
# ── Stop ─────────────────────────────────────────────────────────────────────
#
# smolvm machine stop --name docker
#
# ─────────────────────────────────────────────────────────────────────────────
cpus = 2
memory = 2048
net = true
storage = 20
init = [
"apk update -q",
# docker: daemon + CLI
"apk add docker -q",
# Bind /var/lib/docker to ext4 storage so overlay2 works (avoids overlay-on-overlay)
"mkdir -p /storage/docker /var/lib/docker",
"mount --bind /storage/docker /var/lib/docker",
]