Skip to content

Commit 1161d97

Browse files
committed
feat(os): align mkosi backend with Yocto guest stack
1 parent 462821f commit 1161d97

24 files changed

Lines changed: 1777 additions & 25 deletions

os/mkosi/README.md

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
# Experimental mkosi backend
22

3-
This is a deliberately small Debian/mkosi implementation of the dstack guest
4-
OS. It is an experiment, not yet a replacement for the release Yocto backend.
5-
It tracks the Yocto image's confidential-computing, container, storage,
6-
network, TPM, SSH, chrony and dstack guest-service capabilities.
3+
This is an experimental Debian/mkosi implementation of the dstack guest OS.
4+
It is not yet a replacement for the release Yocto backend. Its acceptance
5+
target is functional parity with the Yocto image, not merely release archive
6+
compatibility. `parity.json` is the machine-checked inventory used by a build.
7+
8+
The backend builds the same dstack services plus the pinned Yocto component
9+
set: Linux 7.1, NVIDIA 595.58.03 (open modules, userspace, firmware, Fabric
10+
Manager and NSCQ), nvattest 2026.06.09 with the OCSP-freshness patch, OpenZFS
11+
2.4.0 with upstream Linux 6.19--7.1 compatibility backports, Sysbox 0.6.7,
12+
NVIDIA Container Toolkit, nerdctl, CNI plugins and stargz-snapshotter 0.18.2.
713

814
## Reproducibility model
915

@@ -25,12 +31,15 @@ checked before compilation.
2531

2632
## Build and acceptance
2733

28-
Host requirements include mkosi >= 26, systemd tools, a C/Rust kernel and EDK2
29-
build toolchain, `bc`, `bison`, `flex`, `nasm`, `iasl`, OpenSSL/ELF/UUID
30-
development headers, `patch`, `pax-utils` (`lddtree`), `squashfs-tools`,
31-
`cryptsetup`, `gdisk`, `dosfstools`, `mtools`, `curl`, `xz`, QEMU/KVM and root
32-
privileges (or a working user namespace). Full UKI release assembly also needs
33-
the pinned `nitro-tpm-pcr-compute` described by `os/image/assemble.sh`.
34+
Host requirements include mkosi >= 26, systemd tools, C/C++/Go/Rust kernel and
35+
EDK2 build toolchains, `autoconf`, `automake`, `libtool`, `bc`, `bison`,
36+
`flex`, `nasm`, `iasl`, and development headers for OpenSSL, ELF, UUID, udev,
37+
aio, attr, blkid, curl, seccomp and tirpc. BTF generation requires `pahole`
38+
(the `dwarves` package). Runtime build tools include `patch`,
39+
`pax-utils` (`lddtree`), `squashfs-tools`, `cryptsetup`, `gdisk`,
40+
`dosfstools`, `mtools`, `curl`, `xz`, QEMU/KVM and root privileges (or a
41+
working user namespace). Full UKI release assembly also needs the pinned
42+
`nitro-tpm-pcr-compute` described by `os/image/assemble.sh`.
3443

3544
```sh
3645
./os/mkosi/build.sh lint
@@ -42,6 +51,10 @@ qemu-system-x86_64 -machine q35 -m 2G -nographic \
4251
-drive if=virtio,format=raw,file=os/mkosi/build/out/prod/dstack-0.6.0/disk.raw
4352
```
4453

54+
On a 16-job development host, a clean production work directory takes about
55+
17 minutes (measured 16m45s); allow 20--30 minutes with cold compiler and
56+
network caches. `repro-check` performs two such builds sequentially.
57+
4558
Acceptance means: the static contract passes; a disk with systemd-boot/UKI
4659
boots on x86_64 QEMU; `/proc/config.gz` contains the checked TDX/SNP, TPM,
4760
ACPI, dm-verity/crypt, virtio, container and hardening options; dstack services
@@ -50,8 +63,9 @@ artifact-manifest schema v1 and delegates final assembly to
5063
`os/image/assemble.sh`, exactly like Yocto. Its output contains the same
5164
`dstack-0.6.0/` directory, bare-metal and UKI tarballs, partitioned combined
5265
squashfs/dm-verity image, metadata, measurements, checksums, kernel, initramfs,
53-
OVMF and UKI. Package contents differ because this backend uses Debian, but
54-
consumers see the same release format and partition labels.
66+
OVMF and UKI. Debian supplies the base userspace while the parity checker
67+
requires the Yocto-visible binaries, services, configuration, kernel modules
68+
and production/development separation before assembly is allowed to proceed.
5569

5670
The firmware is not Debian's generic OVMF: `build-ovmf.sh` builds the same
5771
EDK2 stable-202502 revision and `pre202505` TDX measurement layout selected by

os/mkosi/build.sh

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,26 @@ build_one() {
2222
local out=$1 work=$2 flavor=$3
2323
local stage="$work/rootfs-stage" kstage="$work/kernel-stage" tree="$work/rootfs"
2424
rm -rf "$work" "$out"; mkdir -p "$stage" "$kstage" "$out"
25-
"$SELF/scripts/stage-rootfs.sh" "$stage"
25+
"$SELF/scripts/stage-rootfs.sh" "$stage" "$flavor"
26+
"$SELF/scripts/build-container-stack.sh" "$work/container-stack-build" "$stage"
27+
"$SELF/scripts/build-sysbox.sh" "$work/sysbox-build" "$stage"
28+
"$SELF/scripts/build-nvattest.sh" "$work/nvattest-build" "$stage"
2629
"$SELF/scripts/build-kernel.sh" "$work" "$kstage"
30+
"$SELF/scripts/build-nvidia.sh" "$work/nvidia-build" \
31+
"$work/linux-$KERNEL_VERSION" "$work/kernel-build" "$stage" "$kstage"
32+
"$SELF/scripts/build-zfs.sh" "$work/zfs-build" \
33+
"$work/linux-$KERNEL_VERSION" "$work/kernel-build" "$stage" "$kstage"
2734
"$SELF/scripts/build-ovmf.sh" "$work/ovmf-build" "$kstage/ovmf.fd"
35+
# ExtraTrees is copied over Debian's usr-merged root where /bin, /sbin and
36+
# /lib are symlinks. Normalize build systems (notably OpenZFS) that install
37+
# into the legacy physical directories before handing the tree to mkosi.
38+
for legacy in bin sbin lib lib64; do
39+
if [[ -d $stage/$legacy && ! -L $stage/$legacy ]]; then
40+
mkdir -p "$stage/usr/$legacy"
41+
cp -a "$stage/$legacy/." "$stage/usr/$legacy/"
42+
rm -rf "${stage:?}/$legacy"
43+
fi
44+
done
2845
cat > "$work/mkosi.local.conf" <<EOF
2946
[Content]
3047
ExtraTrees=$stage
@@ -43,13 +60,15 @@ EOF
4360
fi
4461
devargs=()
4562
if [[ $flavor == dev ]]; then
46-
devargs+=(--package=strace --package=tcpdump --package=gdb --package=vim)
63+
devargs+=(--package=strace --package=tcpdump --package=gdb --package=vim \
64+
--package=openssh-server)
4765
fi
4866
mkosi --directory "$SELF" --force --extra-tree="$stage" "${devargs[@]}" \
4967
--format=directory --output-directory="$work" --output=rootfs \
5068
--compress-output=no --bootable=no build
5169
mkdir -p "$tree/usr/lib/modules"
5270
cp -a "$kstage/usr/lib/modules/." "$tree/usr/lib/modules/"
71+
"$SELF/tests/check-parity.py" "$SELF/parity.json" "$tree" "$kstage" "$flavor"
5372
artifact_dir="$work/artifacts/$flavor"
5473
"$SELF/scripts/make-release-artifacts.sh" "$tree" "$kstage" "$artifact_dir" "$flavor"
5574
DIST_DIR="$out" \

os/mkosi/kernel.config

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ CONFIG_XFS_FS=m
5656
CONFIG_BTRFS_FS=m
5757
CONFIG_OVERLAY_FS=y
5858
CONFIG_OVERLAY_FS_METACOPY=y
59-
CONFIG_FUSE_FS=m
59+
CONFIG_FUSE_FS=y
6060
CONFIG_BLK_DEV_LOOP=y
6161
CONFIG_TMPFS_XATTR=y
6262
CONFIG_TMPFS_POSIX_ACL=y
@@ -79,10 +79,10 @@ CONFIG_BPF_SYSCALL=y
7979
CONFIG_BPF_JIT=y
8080
CONFIG_BRIDGE=m
8181
CONFIG_BRIDGE_NETFILTER=m
82-
CONFIG_VETH=m
83-
CONFIG_VLAN_8021Q=m
82+
CONFIG_VETH=y
83+
CONFIG_VLAN_8021Q=y
8484
CONFIG_TUN=m
85-
CONFIG_WIREGUARD=m
85+
CONFIG_WIREGUARD=y
8686
CONFIG_NETFILTER=y
8787
CONFIG_NETFILTER_ADVANCED=y
8888
CONFIG_NF_TABLES=m
@@ -118,3 +118,68 @@ CONFIG_SUSPEND=n
118118
CONFIG_BT=n
119119
CONFIG_WLAN=n
120120
CONFIG_MMC=n
121+
122+
# Yocto dstack fragments and minimal guest-only hardware policy.
123+
CONFIG_9P_FS_POSIX_ACL=y
124+
CONFIG_SERIAL_8250_PCI=y
125+
CONFIG_NR_CPUS=512
126+
CONFIG_DEBUG_INFO_BTF=y
127+
CONFIG_DEBUG_INFO_BTF_MODULES=y
128+
CONFIG_KPROBES=y
129+
CONFIG_HOTPLUG_PCI=n
130+
CONFIG_INPUT=n
131+
CONFIG_SCSI=n
132+
CONFIG_CUSE=y
133+
CONFIG_TCG_VTPM_PROXY=y
134+
CONFIG_NETFILTER_XT_MATCH_IPVS=m
135+
CONFIG_NF_TABLES_INET=y
136+
CONFIG_NF_TABLES_NETDEV=y
137+
CONFIG_NFT_NAT=m
138+
CONFIG_NFT_MASQ=m
139+
CONFIG_NFT_REDIR=m
140+
CONFIG_NFT_CT=m
141+
CONFIG_NFT_LOG=m
142+
CONFIG_NFT_LIMIT=m
143+
CONFIG_NFT_REJECT=m
144+
CONFIG_NFT_REJECT_INET=m
145+
CONFIG_NFT_HASH=m
146+
CONFIG_SECURITY_SELINUX=y
147+
CONFIG_BRIDGE_VLAN_FILTERING=y
148+
CONFIG_XFRM=y
149+
CONFIG_XFRM_USER=y
150+
CONFIG_XFRM_ALGO=y
151+
CONFIG_NETFILTER_XT_MATCH_BPF=y
152+
CONFIG_CRYPTO_SEQIV=y
153+
CONFIG_BTRFS_FS_POSIX_ACL=y
154+
CONFIG_BRIDGE_NF_EBTABLES=m
155+
CONFIG_NETFILTER_FAMILY_BRIDGE=y
156+
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
157+
CONFIG_IP_SET_HASH_IP=m
158+
CONFIG_IP_SET_HASH_NET=m
159+
CONFIG_IP_SET_HASH_IPPORT=m
160+
CONFIG_IP_SET_HASH_IPPORTIP=m
161+
CONFIG_IP_SET_HASH_IPPORTNET=m
162+
CONFIG_IP_SET_HASH_NETPORT=m
163+
CONFIG_IP_SET_HASH_NETIFACE=m
164+
CONFIG_IP_SET_BITMAP_IP=m
165+
CONFIG_IP_SET_BITMAP_PORT=m
166+
CONFIG_IP_SET_LIST_SET=m
167+
CONFIG_NETFILTER_XT_SET=m
168+
CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
169+
CONFIG_BLK_DEV_THROTTLING=y
170+
CONFIG_CRYPTO_ECC=y
171+
CONFIG_CRYPTO_ECDSA=y
172+
CONFIG_CRYPTO_ECDH=y
173+
CONFIG_DRM_I915=n
174+
CONFIG_DRM_AMDGPU=n
175+
CONFIG_DRM_NOUVEAU=n
176+
CONFIG_SOUND=n
177+
CONFIG_MEDIA_SUPPORT=n
178+
CONFIG_WIRELESS=n
179+
CONFIG_USB_SUPPORT=n
180+
CONFIG_DEBUG_INFO=y
181+
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
182+
CONFIG_VT=n
183+
CONFIG_ATA=n
184+
CONFIG_DRM_FBDEV_EMULATION=n
185+
CONFIG_EXPERT=y

os/mkosi/mkosi.conf

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ Packages=
3232
iptables
3333
nftables
3434
docker.io
35+
docker-cli
3536
docker-compose
3637
containerd
3738
chrony
38-
openssh-server
3939
wireguard-tools
4040
cryptsetup
4141
dmsetup
@@ -48,11 +48,12 @@ Packages=
4848
e2fsprogs
4949
gdisk
5050
parted
51-
zfsutils-linux
5251
busybox-static
5352
cryptsetup-bin
5453
ovmf
5554
systemd-boot-efi
55+
acpid
56+
numactl
5657
SkeletonTrees=mkosi.skeleton
5758
PostInstallationScripts=mkosi.postinst
5859
KernelCommandLine=console=ttyS0,115200n8 console=tty0 panic=30 coherent_pool=64M

os/mkosi/mkosi.postinst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ set -euo pipefail
55
# mkosi executes post-installation scripts outside the image with BUILDROOT.
66
B=${BUILDROOT:?}
77
mkdir -p "$B/dev" "$B/proc" "$B/sys" "$B/run" "$B/tmp" "$B/dstack" \
8-
"$B/etc/wireguard" "$B/var/lib/docker" "$B/var/lib/containerd"
8+
"$B/etc/wireguard" "$B/var/lib/docker" "$B/var/lib/containerd" \
9+
"$B/var/volatile" "$B/dstack/.host-shared"
910
rm -f "$B/etc/machine-id" "$B/var/lib/dbus/machine-id"
1011
: > "$B/etc/machine-id"
1112
rm -rf "$B/var/cache/apt/"* "$B/var/lib/apt/lists/"* "$B/var/log/"*
@@ -14,8 +15,14 @@ ln -sfn dstack "$B/tapp"
1415
ln -sfn ../lib/systemd/systemd "$B/usr/sbin/init"
1516

1617
systemctl --root="$B" enable systemd-networkd systemd-resolved chrony docker \
18+
var-volatile.mount dstack-volatile-binds.service \
1719
dstack-firstboot.service dstack-prepare.service \
1820
dstack-guest-agent.socket dstack-guest-agent.service \
19-
app-compose.service wg-checker.service
21+
app-compose.service wg-checker.service nvidia-persistenced.service \
22+
nvidia-fabricmanager.service containerd-stargz-grpc.service \
23+
sysbox.service sysbox-fs.service sysbox-mgr.service
2024
systemctl --root="$B" mask getty@.service serial-getty@.service debug-shell.service \
2125
sleep.target suspend.target hibernate.target hybrid-sleep.target
26+
if [[ -x $B/usr/bin/dstack-tee-simulator ]]; then
27+
systemctl --root="$B" enable dstack-tee-simulator.service
28+
fi
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
{
2-
"iptables": true,
3-
"ip6tables": true,
4-
"storage-driver": "overlay2"
2+
"log-driver": "json-file",
3+
"log-opts": {"max-size": "100m", "max-file": "10"},
4+
"runtimes": {
5+
"nvidia": {"args": [], "path": "nvidia-container-runtime"},
6+
"sysbox-runc": {"path": "/usr/bin/sysbox-runc"}
7+
}
58
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: Apache-2.0
3+
set -euo pipefail
4+
5+
for name in cache lib log spool tmp; do
6+
source=/var/volatile/$name
7+
target=/var/$name
8+
mkdir -p "$source" "$target"
9+
mountpoint -q "$target" || mount --bind "$source" "$target"
10+
done
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
[Unit]
3+
Description=Bind volatile state over the immutable root
4+
DefaultDependencies=no
5+
Requires=var-volatile.mount
6+
After=var-volatile.mount
7+
Before=local-fs.target
8+
9+
[Service]
10+
Type=oneshot
11+
ExecStart=/usr/bin/dstack-volatile-binds.sh
12+
RemainAfterExit=yes
13+
14+
[Install]
15+
WantedBy=local-fs.target
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
[Unit]
3+
Requires=dstack-volatile-binds.service
4+
After=dstack-volatile-binds.service
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
[Unit]
3+
After=systemd-tmpfiles-setup.service var-volatile.mount
4+
Requires=var-volatile.mount

0 commit comments

Comments
 (0)