Ubuntu LTSP (ltsp-server package) provides a very easy and convenient method for deploying a thin-client environment (see ltsp.org), but is centered primarily around one server being the DHCP/TFTP/NBD and image build server. Being in an enterprise environment, I needed to be able to split these functions in order to deploy thin clients. The image below depicts what I needed to achieve. Essentially I wanted to have ubuntu 14.04 images served by older release servers, so my "build" server needs to be 14.04. Plus I wanted to be able to server multiple custom images off the same server(s). Note: I have existing DHCP/TFTP and NBD servers - so this post assumes these are already established - If you do not, then the ltsp-server package has everything you need, and this post is kinda moot.
First, on my build server, I did the following:
apt-get install ltsp-server
ltsp-build-client --dist trusty --arch amd64 --base /opt/ltsp-trusty
This builds your base client system, in my case an amd64 architecture ubuntu 14.04 base. It takes about 20 minutes depending on your Internet connection and system speed. Then any customizations can be done via ltsp-chroot:
ltsp-chroot -a amd64 -b /opt/ltsp-trusty --mount-package-cache
(more on what I customized in later post)
And to build the image:
ltsp-update-image --base /opt/ltsp-trusty
So what we have now on the build server, is the image in /opt/ltsp-trusty/images called amd64.img and the needed tftpboot files in /var/lib/tftpboot/ltsp. In very simple terms, we now need to deploy the image "amd64.img" to the NBD server, and the PXE boot environment to the TFTP server, and then tweak configuration files to point to the right places.
NBD server (Network Block Device)
For every different image you want to deploy, you need nbd-server listening on a different port. I am using inetd to spawn the nbd-server instances. Here is my inetd.conf, which is configured for 3 images on ports 2000 thru 2002:
2000 stream tcp nowait nobody /usr/sbin/tcpd /usr/sbin/nbdrootd /opt/ltsp/images/i386.img
2001 stream tcp nowait nobody /usr/sbin/tcpd /usr/sbin/nbdrootd /opt/ltsp-trusty/images/amd64.img
2002 stream tcp nowait nobody /usr/sbin/tcpd /usr/sbin/nbdrootd /opt/ltsp-trusty/images/i386.img
The image files have to be accessible directly, so in my case I copied them from my build server.
TFTP server (Trivial File Transfer Protocol)
For every different image, you need a specific PXE environment defined in /var/lib/tftpboot. In my case I have 3:
/var/lib/tftpboot/ltsp/i386
/var/lib/tftpboot/ltsp-trusty/amd64
/var/lib/tftpboot/ltsp-trusty/i386
These can be copied as is from the same location on the build server - each environment can have its own lts.conf file.
Now, there is some tweaking required in order for the client to grab the correct NBD image. You need to add
nbdroot={ipaddress}:{port} to the kernel boot parameters for any image served by the non-standard 2000 NBD port. This is done in the pxelinux.cfg/ltsp file - snippet below.
# This file is regenerated when update-kernels runs.
# Do not edit, see /etc/ltsp/update-kernels.conf instead.
default ltsp-NBD
ontimeout ltsp-NBD
# This file is regenerated when update-kernels runs.
# Do not edit, see /etc/ltsp/update-kernels.conf instead.
label ltsp-NBD
menu label LTSP, using NBD
kernel vmlinuz-3.13.0-37-generic
#append ro initrd=initrd.img-3.13.0-37-generic init=/sbin/init-ltsp quiet splash root=/dev/nbd0
append ro initrd=initrd.img-3.13.0-37-generic init=/sbin/init-ltsp nosplash root=/dev/nbd0 nbdroot=192.168.202.4:2001
ipappend 2
DHCP server (Dynamic Host Configuration Protocol)
Your DHCP configuration is key, as it directs the PXE booting client to the correct TFTP server and PXE path. I use an Etherboot gPXE image served by a local TFTP server to fix issues with older network cards - but you may not need that. Here is one client config section example:
host webc2 { hardware ethernet 20:cf:30:6f:0a:9e;
fixed-address webc2;
option host-name "webc2";
if substring (option vendor-class-identifier, 0, 9) = "PXEClient" {
if exists user-class and option user-class = "gPXE" {
next-server 192.168.202.4;
filename "/ltsp-trusty/i386/pxelinux.0";
} else { filename "/tftpboot/undionly.kpxe"; }
} else {
next-server 192.168.202.4;
filename "/ltsp-trusty/i386/nbi.img";}}
The "next-server" portion points it to the TFTP server and PXE file.
You'll probably notice that in my case, my TFTP server and NBD server are on the same server, but its not necessary.
Anyway, in another post I'll discuss an improvement I made to LTSP to allow better scripting via TFTP.