mirror of
https://github.com/nestriness/nestri.git
synced 2026-11-03 22:22:39 +02:00
Host agent runs as root; NVIDIA host programs ship in the base image (#366)
- **Installer:** piped into `sudo`, installs to `/usr/local/bin`, and hands onboarding `/var/lib/nestri`. Root lets the host agent jail each box under its own uid and give guests a network. A host that ran the agent as the sudo user has that state copied over (never moved), so it keeps its machine identity and its downloads. Pins host agent 0.2.4. - **Base image:** `vhost-user-nvgpu` and `nvgpu-userspace`, static (musl), from the same `NVGPU_REF` as the guest driver and Vulkan layer, under `/boot/host`. The host agent takes them out at unpack, as it does the kernel, and forwards the GPU when it finds the NVIDIA driver loaded. Merge after the host agent 0.2.4 release: the installer pins it.
This commit is contained in:
+40
-11
@@ -4,14 +4,17 @@
|
||||
# This file is the source of what that URL serves, kept in the public
|
||||
# repository so anyone about to pipe it into a shell can read it first.
|
||||
#
|
||||
# curl -fsSL https://api.nestri.io/install.sh | sh -s -- <install-token>
|
||||
# curl -fsSL https://api.nestri.io/install.sh | sudo sh -s -- <install-token>
|
||||
#
|
||||
# What it does, in order: check this is 64-bit Linux, ask where box images
|
||||
# should live, download the host agent for this platform, verify it against the
|
||||
# published SHA256SUMS, install it to ~/.local/bin, and hand over to
|
||||
# the agent's own onboarding, which checks the machine, registers it with the
|
||||
# token and starts the agent as a systemd user service. It never asks for sudo: the agent
|
||||
# runs as the user who ran this.
|
||||
# published SHA256SUMS, install it to /usr/local/bin, and hand over to the
|
||||
# agent's own onboarding, which checks the machine, registers it with the token
|
||||
# and starts the agent as a systemd service.
|
||||
#
|
||||
# It runs as root because the agent does: each box's VMM is jailed under a uid
|
||||
# of its own, which only root can give it, and a box's network needs
|
||||
# CAP_NET_ADMIN. The agent keeps its state in /var/lib/nestri.
|
||||
#
|
||||
# The token comes from the dashboard's Installation page. It registers one
|
||||
# machine, works once and lapses after an hour.
|
||||
@@ -21,9 +24,10 @@ set -eu
|
||||
API="${NESTRI_API:-https://api.nestri.io}"
|
||||
# Pinned, not "latest", so the script and the binary it installs are a pair
|
||||
# somebody chose. Bump when cutting a release; NESTRI_HOST_VERSION overrides it.
|
||||
DEFAULT_VERSION="0.2.3"
|
||||
DEFAULT_VERSION="0.2.4"
|
||||
VERSION="${NESTRI_HOST_VERSION:-$DEFAULT_VERSION}"
|
||||
BIN_DIR="${NESTRI_BIN_DIR:-$HOME/.local/bin}"
|
||||
BIN_DIR="${NESTRI_BIN_DIR:-/usr/local/bin}"
|
||||
STATE_DIR=/var/lib/nestri
|
||||
|
||||
say() { printf '%s\n' "$*" >&2; }
|
||||
die() { printf 'error: %s\n' "$*" >&2; exit 1; }
|
||||
@@ -37,7 +41,31 @@ case "$(uname -m)" in
|
||||
x86_64|amd64) target=x86_64-unknown-linux-gnu ;;
|
||||
*) die "no host build for $(uname -m) yet." ;;
|
||||
esac
|
||||
[ "$(id -u)" -ne 0 ] || die "run this as the user that will run boxes, not as root."
|
||||
[ "$(id -u)" -eq 0 ] || die "run this as root: pipe it into \`sudo sh -s -- <token>\`, as the dashboard shows."
|
||||
|
||||
# --- an install from before the agent ran as root ---------------------------
|
||||
# Hosts used to run the agent as the user who installed it, from a state
|
||||
# directory in their home and a user unit. That user is the one sudo was run by. Their state is copied,
|
||||
# never moved: the machine keeps its identity and what it already downloaded,
|
||||
# and the old directory stays as it was.
|
||||
OLD_HOME=""
|
||||
if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != root ]; then
|
||||
OLD_HOME="$(getent passwd "$SUDO_USER" | cut -d: -f6)"
|
||||
fi
|
||||
OLD_STATE="${OLD_HOME:+$OLD_HOME/.nestri}"
|
||||
if [ -n "$OLD_STATE" ] && [ -f "$OLD_STATE"/onboarding.json ] && [ ! -e "$STATE_DIR" ]; then
|
||||
say "Moving this host's agent from $SUDO_USER to a system service…"
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl --user -M "$SUDO_USER@" disable --now nestri-host.service >/dev/null 2>&1 || true
|
||||
fi
|
||||
mkdir -p "$(dirname "$STATE_DIR")"
|
||||
cp -a "$OLD_STATE" "$STATE_DIR"
|
||||
# The box store that install was given, unless this run names another.
|
||||
if [ -z "${NESTRI_BOX_STORE:-}" ] && [ -f "$OLD_HOME/.config/nestri-host/env" ]; then
|
||||
NESTRI_BOX_STORE="$(sed -n 's/^NESLET_BOX_STORE=//p' "$OLD_HOME/.config/nestri-host/env" | head -n1)"
|
||||
fi
|
||||
say "Copied $OLD_STATE to $STATE_DIR."
|
||||
fi
|
||||
|
||||
# --- fetch ------------------------------------------------------------------
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
@@ -106,15 +134,16 @@ say ""
|
||||
# again by onboarding on the new binary. A host with nothing running is
|
||||
# unaffected.
|
||||
if command -v systemctl >/dev/null 2>&1 &&
|
||||
systemctl --user is-active --quiet nestri-host.service 2>/dev/null; then
|
||||
systemctl is-active --quiet nestri-host.service 2>/dev/null; then
|
||||
say "Stopping the running host agent to upgrade it…"
|
||||
systemctl --user stop nestri-host.service
|
||||
systemctl stop nestri-host.service
|
||||
fi
|
||||
|
||||
# --- onboard ----------------------------------------------------------------
|
||||
# The token goes through the environment rather than argv, so it is not in
|
||||
# `ps` for the length of the run.
|
||||
export NESTRI_INSTALL_TOKEN="$TOKEN" NESTRI_BOX_STORE="$BOX_STORE" NESTRI_API="$API"
|
||||
export NESTRI_INSTALL_TOKEN="$TOKEN" NESTRI_BOX_STORE="$BOX_STORE" NESTRI_API="$API" \
|
||||
NESLET_STATE_DIR="$STATE_DIR"
|
||||
if tty_ok; then
|
||||
exec "$BIN_DIR/nestri-host" onboard </dev/tty
|
||||
else
|
||||
|
||||
+33
-2
@@ -202,6 +202,35 @@ RUN --mount=type=cache,target=/root/.cargo/registry \
|
||||
find /artifacts/nvgpu -type f -printf '/%P\n' > /artifacts/nvgpu/.manifest
|
||||
|
||||
|
||||
# ───────────────────────────────────────────────────────────
|
||||
# virtio-nvgpu's host half — shipped beside the guest's, taken out on the host
|
||||
#
|
||||
# `vhost-user-nvgpu` serves a box's forwarded GPU and `nvgpu-userspace`
|
||||
# stages the host's NVIDIA driver for its guests. They run on the host, never
|
||||
# in a guest: the host agent's onboarding moves /boot/host out of this image
|
||||
# the way it moves the kernel, and turns forwarding on when it finds the
|
||||
# NVIDIA driver loaded. In this image so they are always from the same
|
||||
# NVGPU_REF as the guest driver and the layer above.
|
||||
#
|
||||
# Static (musl), because they run on whatever distribution the host is, and
|
||||
# this one's glibc is newer than most of them.
|
||||
# ───────────────────────────────────────────────────────────
|
||||
FROM builder AS nvgpu-host-build
|
||||
ARG NVGPU_GIT=https://github.com/nestrilabs/virtio-nvgpu.git
|
||||
ARG NVGPU_REF=dev
|
||||
RUN rustup target add x86_64-unknown-linux-musl
|
||||
RUN --mount=type=cache,target=/root/.cargo/registry \
|
||||
git init -q /build/virtio-nvgpu && cd /build/virtio-nvgpu && \
|
||||
git fetch -q --depth=1 "${NVGPU_GIT}" "${NVGPU_REF}" && git checkout -q FETCH_HEAD && \
|
||||
cargo build --release --target x86_64-unknown-linux-musl -p device --features vhost-user \
|
||||
--bin vhost-user-nvgpu --bin nvgpu-userspace && \
|
||||
for b in vhost-user-nvgpu nvgpu-userspace; do \
|
||||
install -Dm755 "target/x86_64-unknown-linux-musl/release/$b" "/artifacts/nvgpu-host/boot/host/$b" && \
|
||||
strip "/artifacts/nvgpu-host/boot/host/$b"; \
|
||||
done && \
|
||||
git rev-parse HEAD > /artifacts/nvgpu-host/boot/host/virtio-nvgpu.rev && \
|
||||
cd / && rm -rf /build/virtio-nvgpu
|
||||
|
||||
# ───────────────────────────────────────────────────────────
|
||||
# The guest kernel — shipped inside the image it boots
|
||||
#
|
||||
@@ -473,9 +502,11 @@ COPY --from=mesa-build /artifacts/mesa /
|
||||
COPY --from=nestri-build /artifacts/nestri /
|
||||
COPY --from=nvgpu-layer-build /artifacts/nvgpu /
|
||||
COPY --from=umu-build /artifacts/umu /
|
||||
# The kernel this image is booted with, for the host to take out. See the
|
||||
# kernel-build stage.
|
||||
# The kernel this image is booted with, and the host's half of GPU
|
||||
# forwarding, for the host to take out. See the kernel-build and
|
||||
# nvgpu-host-build stages.
|
||||
COPY --from=kernel-build /artifacts/kernel /
|
||||
COPY --from=nvgpu-host-build /artifacts/nvgpu-host /
|
||||
|
||||
# **No Proton here.** It is attached to a box at run time, mounted at
|
||||
# /nestri/compat, so this image has no Proton path for a launch to fall back to
|
||||
|
||||
Reference in New Issue
Block a user