Serving Diskless Netboot for your Macs without OS X Server
With the official death of the Xserve, some of you may be looking at your future plans for services you currently provide. If you plan to migrate away from OS X server for some functions, NetBoot can be one of them. Read on to find out how…
Ed. Note: This walks you through how to set up a NetBoot image without needing a local drive mounted on the client system. There is a distinction between this and what the Apple materials refer to as diskless NetBoot which is when you would use an AFP share to hold all of the read/write bits you need. Mac OS X Server can do both this method of using the RAM disk, typically used for NetInstall setups, and the later where you would use for an actual "live" system such as for a lab of machines actually in use by users instead of just for imaging purposes. For most admins just wishing to do deployments, using a RAM disk is all you'll most likely need.
Setting up NetBoot on Linux has an excellent article by Jeff McCune, and will not be discussed in this article. We're going to assume you've got your Linux NetBoot server happily serving NetBoot Images. There's one caveat — a Linux NetBoot server does not support diskless booting.
What is Diskless NetBoot?
Simply put, diskless NetBoot is when you boot from your NetBoot server, and it is configured with network storage in order to write OS shadow files. By default, NetBoot will try to mount a shadow file at shadow_mount_path in the /etc/rc.netboot startup script. If that fails (diskless netboot is not enabled for that image), it will store it's shadow files on the local hard drive. In diskless NetBoot, shadow files are written to some network file share (Usually /Library/NetBoot/NetBootClients0/).
Without diskless NetBoot, you cannot unmount the local hard drive. How can we do things, like have a diagnostic NetBoot for diagnosing drive problems? How can we use NetBoot to image hard drives, without diskless booting?
The hack
One hint that led me to this discovery was the fact that NetInstall images do not have an option for diskless NetBoot. This is because they use a RAM Disk. I dug into the /etc/rc.netboot file and made some discoveries. Through some hints from a universal bootable DVD, I found how to create a RAM Disk using the rc.netboot file.
The code is as follows:
RAMDisk()
{
mntpt=$1
echo "Creating RAM Disk for $mntpt"
dev=hdik -drivekey system-image=yes -drivekey eject-upon-logout=no -nomount ram://500000
if [ $? -eq 0 ] ; then
newfs $dev #hack to init partition table automatically
newfs_hfs $dev
mount -t hfs -o nosuid,nodev $dev $mntpt
echo "ramdisk created and mounted OK"
fi
}
#Example: RAMDisk /Volumes
The "ram://500000" section is how much RAM to use for the RAMDisk. I've found 512ish MB of RAM to be sufficient for most machines. In this hack, we must then tell the "local" section of rc.netboot (Because the shadow mount will FAIL) to create the RAMDisk and set it as the shadow file.
This is done with this code, in the local_mount() section of rc.netboot:
volinfo=autodiskmount -F 2>/dev/null
RAMDisk "${NETBOOT_MOUNT}"
common_start "${NETBOOT_MOUNT}/.com.apple.NetBootX" shadowfile
return 0
By changing the rc.netboot file on your NetBoot image, you can "fool" a non OS X Server into providing a diskless NetBoot image.
For more info about NetBoot and shadow files, here are some interesting links:
Mike Bombich's Netboot troubleshooting guide
Amit Singh's System Startup info from Mac OS X Internals
If you still want to use Mac OS X, you can also try NetBoot on OS X Client
Adam Knight – Make any Mac a NetBoot Server (10.4, outdated)
Ryan Lenger – NetBoot on Mac OS X Leopard Client
And apparently DeployStudio (as of RC125) has a built-in NetBoot and DHCP server, which will run on Mac OS X Client. There was an unverified comment from MacWorld SF 2011 that OS X Client has a 10 client AFP limitation.
DeployStudio Rc125 release notes
Finally, here's the modified sections of rc.netboot in full:
local_mount()
{
#tries=0
#limit=11
#while [ $tries -lt $limit ]; do
#tries=$(( tries + 1 ))
#volinfo=autodiskmount -F 2>/dev/null
#if [ $? -ne 0 ]; then
#if [ $tries -lt $limit ]; then
#echo "Waiting for local drives…"
#echo "Waiting for local drives (retry ${tries}/$(( limit – 1 )))…" > /dev/console
#sleep 5
#else
#echo "autodiskmount -F found no local drives"
#return 1
#fi
#else
#tries=$limit
#fi
#done
#set ${volinfo}
#devname=$1
#fstype=$2
#mount -t "${fstype}" -o nosuid,nodev "/dev/${devname}" "${NETBOOT_MOUNT}" 2>&1
#if [ $? -ne 0 ]; then
#echo "mount of ${devname} failed"
#return 1
#fi
volinfo=autodiskmount -F 2>/dev/null
RAMDisk "${NETBOOT_MOUNT}"
common_start "${NETBOOT_MOUNT}/.com.apple.NetBootX" shadowfile
return 0
}
RAMDisk()
{
mntpt=$1
echo "Creating RAM Disk for $mntpt"
dev=hdik -drivekey system-image=yes -drivekey eject-upon-logout=no -nomount ram://500000
if [ $? -eq 0 ] ; then
newfs $dev #hack to init partition table automatically
newfs_hfs $dev
mount -t hfs -o nosuid,nodev $dev $mntpt
echo "ramdisk created and mounted OK"
fi
}
#Example: RAMDisk /Volumes