🧩 Comprehensive template system for creating fully compliant, multi-tenant rootfs filesystems with layered architecture and systemd integration.
| Section | Description |
|---|---|
| 🎯 Template System Overview | Layered template architecture |
| 🏠 Tenant Templates | Infrastructure, VM, container templates |
| 🔧 Extension Image Templates | sysext and confext templates |
| 🌐 Network Templates | Networking configuration patterns |
| ⚙️ Systemd Generators | Dynamic unit generation |
| 🔄 Tenant Instantiation Flow | Provisioning workflow |
| ✅ Directory Structure Compliance | UAPI compliance validation |
BitBuilder Hypervisor uses a layered template system that creates fully compliant rootfs filesystems for each tenant component. Each template is a Git repository that contains a complete filesystem hierarchy adhering to the Linux Userspace API specifications.
graph TB
T[📦 Templates] --> I[🏗️ Infrastructure Templates]
T --> M[🖥️ Machine Templates]
T --> C[📦 Container Templates]
T --> H[🏠 Homed Templates]
T --> N[🌐 Network Templates]
I --> IT[Management layer for each tenant]
M --> MT[VM templates - systemd-vmspawn]
C --> CT[Container templates - systemd-nspawn]
H --> HT[User home directory templates]
N --> NT[Network configuration templates]
style T fill:#e3f2fd
style I fill:#f3e5f5
style M fill:#e8f5e8
style C fill:#fff3e0
style H fill:#fce4ec
style N fill:#f1f8e9
🎯 Purpose: The infrastructure manager runs as a privileged systemd-vmspawn VM within each tenant's namespace and manages all tenant resources.
tenant-infra-template/
├── metadata.json # Template metadata
├── rootfs/ # Compliant root filesystem
│ ├── etc/
│ │ ├── os-release # Required OS identification
│ │ ├── systemd/
│ │ │ ├── system/
│ │ │ │ ├── multi-user.target.wants/
│ │ │ │ ├── infra-manager.service
│ │ │ │ ├── git-sync.service
│ │ │ │ ├── git-sync.timer
│ │ │ │ └── varlink-api.service
│ │ │ └── network/
│ │ │ ├── 10-management.network
│ │ │ └── 10-management.netdev
│ │ └── extension-release.d/ # Extension compatibility
│ ├── usr/
│ │ ├── lib/
│ │ │ ├── os-release -> ../../etc/os-release
│ │ │ ├── systemd/system/ # Vendor units
│ │ │ └── bitbuilder/
│ │ │ ├── infra-manager # Management binary
│ │ │ └── lib/ # Shared libraries
│ │ └── share/
│ │ └── bitbuilder/
│ │ └── schemas/ # JSON schemas
│ ├── var/
│ │ └── lib/
│ │ └── infra/ # Persistent infra data
│ └── run/ # Runtime directory (empty)
├── config/ # Default configuration
│ ├── infra-config.yaml
│ └── resource-limits.yaml
└── scripts/
├── provision.sh # Provisioning script
└── health-check.sh # Health monitoring{
"template": {
"type": "infrastructure",
"version": "1.0.0",
"name": "tenant-infra-template"
},
"requirements": {
"systemd_version": ">=258",
"kernel": ">=6.0",
"features": ["vmspawn", "varlink", "networkd"]
},
"defaults": {
"resources": {
"cpu": 2,
"memory": "2G",
"storage": "10G"
},
"network": {
"mode": "private",
"management_interface": true
}
}
}Template for creating tenant VMs using systemd-vmspawn.
Repository Structure:
tenant-machine-template/
├── metadata.json
├── disk-image/ # Base disk image
│ ├── efi/ # EFI partition
│ │ └── EFI/
│ │ └── systemd/
│ │ └── systemd-bootx64.efi
│ ├── boot/ # Boot partition
│ │ ├── vmlinuz # Kernel
│ │ └── initrd.img # Initial ramdisk
│ └── rootfs/ # Root filesystem
│ ├── etc/
│ │ ├── os-release
│ │ ├── machine-id # Empty (generated)
│ │ └── systemd/
│ │ ├── system/
│ │ └── network/
│ ├── usr/ # Minimal userspace
│ └── var/
├── config/
│ ├── vm-config.yaml
│ └── cloud-init/ # Cloud-init templates
│ ├── user-data
│ └── meta-data
└── extensions/ # VM-specific extensions
├── development.sysext.raw
└── monitoring.confext.raw
Template for creating tenant containers using systemd-nspawn.
Repository Structure:
tenant-container-template/
├── metadata.json
├── rootfs/ # Container root filesystem
│ ├── etc/
│ │ ├── os-release
│ │ └── systemd/
│ │ ├── system/
│ │ │ └── container-init.service
│ │ └── network/
│ │ └── 80-container.network
│ ├── usr/
│ │ ├── bin/ # Essential binaries
│ │ └── lib/
│ └── var/
│ └── lib/
├── config/
│ └── nspawn-settings.conf # systemd-nspawn settings
└── scripts/
└── container-init.sh
[Exec]
Boot=yes
ProcessTwo=yes
NotifyReady=yes
[Network]
Private=yes
VirtualEthernet=yes
Bridge=br-tenant
[Files]
PrivateUsersChown=yes
BindReadOnly=/usr/lib/extensionsTemplate for user home directories managed by systemd-homed.
Repository Structure:
tenant-homed-template/
├── metadata.json
├── home-skeleton/ # Default home structure
│ ├── .config/
│ │ └── systemd/
│ │ └── user/ # User services
│ ├── .local/
│ │ ├── bin/ # User binaries
│ │ └── share/
│ └── .ssh/ # SSH configuration
│ └── authorized_keys.template
├── config/
│ ├── homed-config.json # systemd-homed config
│ └── user-record.json # User record template
└── scripts/
└── home-provision.sh
base-tools.sysext/
├── usr/ # Only /usr and /opt allowed
│ ├── bin/
│ │ ├── htop
│ │ ├── tmux
│ │ └── vim
│ └── lib/
│ └── extension-release.d/
│ └── extension-release.base-tools
└── opt/
└── bitbuilder/
└── tools/
ID=bitbuilder
VERSION_ID=1.0
SYSEXT_LEVEL=1.0
ARCHITECTURE=x86-64network-policies.confext/
└── etc/ # Only /etc allowed
├── systemd/
│ └── network/
│ ├── 20-wireguard.netdev
│ └── 20-wireguard.network
└── extension-release.d/
└── extension-release.network-policies
[NetDev]
Name=br-tenant-%i
Kind=bridge
[Bridge]
STP=yes
Priority=32768
ForwardDelaySec=15
HelloTimeSec=2
MaxAgeSec=20[Match]
Name=br-tenant-%i
[Network]
DHCP=no
IPv6AcceptRA=no
IPForward=yes
IPMasquerade=yes
Address=10.%i.0.1/24
[DHCPServer]
PoolOffset=100
PoolSize=100
EmitDNS=yes
DNS=10.%i.0.1
EmitRouter=yes[NetDev]
Name=wg-tenant-%i
Kind=wireguard
[WireGuard]
PrivateKeyFile=/var/lib/tenants/%i/network/wireguard.key
ListenPort=51820
[WireGuardPeer]
PublicKey=${PEER_PUBLIC_KEY}
AllowedIPs=10.%i.100.0/24
Endpoint=${PEER_ENDPOINT}:51820
PersistentKeepalive=25[Match]
Name=wg-tenant-%i
[Network]
Address=10.%i.100.1/24
[Route]
Destination=10.%i.100.0/24
Scope=link[NetDev]
Name=vxlan-tenant-%i
Kind=vxlan
[VXLAN]
VNI=%i
Group=239.0.0.1
DestinationPort=4789
MacLearning=yes[Match]
Name=vxlan-tenant-%i
[Network]
Bridge=br-tenant-%i
[BridgeVLAN]
PVID=1
EgressUntagged=1[NetDev]
Name=vlan-tenant-%i
Kind=vlan
[VLAN]
Id=%i[Match]
Name=vlan-tenant-%i
[Network]
DHCP=yes
IPv6AcceptRA=yes
[DHCP]
RouteMetric=200
UseDomains=route/usr/lib/systemd/system/netns-tenant@.service:
[Unit]
Description=Network namespace for tenant %i
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/ip netns add tenant-%i
ExecStart=/usr/bin/ip netns exec tenant-%i ip link set lo up
ExecStop=/usr/bin/ip netns delete tenant-%i
[Install]
WantedBy=multi-user.target/usr/lib/systemd/system-generators/tenant-generator:
#!/bin/bash
# Discovers tenants from Git repositories and generates systemd units
GENERATOR_DIR="$1"
TENANT_REGISTRY="/var/lib/bitbuilder/tenants.json"
generate_tenant_units() {
local tenant_id="$1"
local tenant_config="$2"
# Generate main tenant service
cat > "${GENERATOR_DIR}/tenant@${tenant_id}.service" <<EOF
[Unit]
Description=Tenant ${tenant_id}
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
ExecStartPre=/usr/lib/bitbuilder/tenant-provision ${tenant_id}
ExecStart=/usr/lib/bitbuilder/tenant-manager ${tenant_id}
ExecStop=/usr/lib/bitbuilder/tenant-cleanup ${tenant_id}
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
# Generate infrastructure manager service
cat > "${GENERATOR_DIR}/tenant-infra@${tenant_id}.service" <<EOF
[Unit]
Description=Infrastructure manager for tenant ${tenant_id}
After=tenant@${tenant_id}.service
BindsTo=tenant@${tenant_id}.service
[Service]
Type=notify
ExecStart=/usr/bin/systemd-vmspawn \
--machine=infra-${tenant_id} \
--directory=/var/lib/tenants/${tenant_id}/infra/rootfs \
--network-bridge=br-tenant-${tenant_id} \
--bind-ro=/usr/lib/extensions \
--setenv=TENANT_ID=${tenant_id}
Restart=always
[Install]
WantedBy=tenant@${tenant_id}.service
EOF
# Generate network setup service
cat > "${GENERATOR_DIR}/tenant-network@${tenant_id}.service" <<EOF
[Unit]
Description=Network setup for tenant ${tenant_id}
Before=tenant@${tenant_id}.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/lib/bitbuilder/setup-tenant-network ${tenant_id}
ExecStop=/usr/lib/bitbuilder/teardown-tenant-network ${tenant_id}
[Install]
RequiredBy=tenant@${tenant_id}.service
EOF
}
# Read tenant registry and generate units
if [[ -f "$TENANT_REGISTRY" ]]; then
jq -r '.tenants[] | @base64' "$TENANT_REGISTRY" | while read -r tenant_data; do
tenant_json=$(echo "$tenant_data" | base64 -d)
tenant_id=$(echo "$tenant_json" | jq -r '.id')
generate_tenant_units "$tenant_id" "$tenant_json"
done
fi/usr/lib/systemd/system-generators/mount-generator:
#!/bin/bash
# Generates mount units for tenant directories and extensions
GENERATOR_DIR="$1"
TENANT_BASE="/var/lib/tenants"
generate_extension_mounts() {
local tenant_id="$1"
# Generate sysext mount
cat > "${GENERATOR_DIR}/var-lib-tenants-${tenant_id}-sysext.mount" <<EOF
[Unit]
Description=System extensions for tenant ${tenant_id}
Before=tenant@${tenant_id}.service
[Mount]
What=overlay
Where=/var/lib/tenants/${tenant_id}/overlay/usr
Type=overlay
Options=lowerdir=/usr:/var/lib/tenants/${tenant_id}/extensions/sysext,upperdir=/var/lib/tenants/${tenant_id}/overlay/usr,workdir=/var/lib/tenants/${tenant_id}/overlay/.usr-work
[Install]
RequiredBy=tenant@${tenant_id}.service
EOF
# Generate confext mount
cat > "${GENERATOR_DIR}/var-lib-tenants-${tenant_id}-confext.mount" <<EOF
[Unit]
Description=Configuration extensions for tenant ${tenant_id}
Before=tenant@${tenant_id}.service
[Mount]
What=overlay
Where=/var/lib/tenants/${tenant_id}/overlay/etc
Type=overlay
Options=lowerdir=/etc:/var/lib/tenants/${tenant_id}/extensions/confext,upperdir=/var/lib/tenants/${tenant_id}/overlay/etc,workdir=/var/lib/tenants/${tenant_id}/overlay/.etc-work
[Install]
RequiredBy=tenant@${tenant_id}.service
EOF
}
# Generate mounts for each existing tenant
if [[ -d "$TENANT_BASE" ]]; then
for tenant_dir in "$TENANT_BASE"/*; do
if [[ -d "$tenant_dir" ]]; then
tenant_id=$(basename "$tenant_dir")
generate_extension_mounts "$tenant_id"
fi
done
fi# Enable and start a new tenant
systemctl enable --now tenant@tenant123.servicegraph TD
A[systemctl enable tenant@ID] --> B[Tenant Generator]
B --> C[Read tenant registry]
C --> D[Clone Git repositories]
D --> E[Generate systemd units]
E --> F[Setup network namespace]
F --> G[Mount extensions]
G --> H[Start infra manager VM]
H --> I[Provision tenant resources]
I --> J[Start tenant workloads]
tenant@tenant123.service
Requires: tenant-network@tenant123.service
Wants: tenant-infra@tenant123.service
After: network-online.target
Triggers:
var-lib-tenants-tenant123-sysext.mount
var-lib-tenants-tenant123-confext.mount
netns-tenant@tenant123.service
br-tenant-123.netdev
Each template ensures compliance with the Linux File System Hierarchy specification:
-
Root Filesystem Requirements:
/etc/os-releaseor/usr/lib/os-releasepresent- Proper symlink from
/usr/lib/os-releaseto/etc/os-release - No files in
/root directory itself
-
Extension Image Requirements:
- sysext: Only
/usr/and/opt/directories - confext: Only
/etc/directory - Proper
extension-releasefiles in correct locations
- sysext: Only
-
Verification Structure:
- VOA hierarchy at
/etc/voa/and/usr/share/voa/ - Proper certificate fingerprint naming
- ASCII-armored OpenPGP files
- VOA hierarchy at
Each template includes a validation script:
#!/bin/bash
# validate-template.sh
validate_rootfs() {
local rootfs="$1"
# Check for required files
[[ -f "$rootfs/etc/os-release" ]] || error "Missing /etc/os-release"
[[ -L "$rootfs/usr/lib/os-release" ]] || error "Missing /usr/lib/os-release symlink"
# Validate directory structure
for dir in etc usr var proc sys dev run tmp; do
[[ -d "$rootfs/$dir" ]] || error "Missing /$dir directory"
done
# Check permissions
[[ $(stat -c %a "$rootfs/tmp") == "1777" ]] || error "Invalid /tmp permissions"
echo "Template validation successful"
}This template system provides the following capabilities:
- Standardization: All tenants use consistent, validated templates
- Compliance: Full adherence to Linux Userspace API specifications
- Flexibility: Multiple template types for different use cases
- Security: Layered isolation with proper namespace separation
- Automation: Systemd generators handle all instantiation logic
- Networking: Comprehensive network isolation and connectivity options
The combination of Git-based configuration, systemd integration, and compliant filesystem templates creates a robust, secure, and manageable multi-tenant hypervisor platform.