ThinClient lokal booten #

Normalerweise ist es am besten, einen ThinClient - wie auf der Seite LinuxTerminalServer beschrieben - über das Netzwerk von einem zentralen LTSP-Server aus zu booten. Auf diese Art und Weise kann man alle Clients im Netzwerk am besten zentral einrichten und verwalten.

Dennoch kann es sinnvoll sein, einen ThinClient von einem lokalen Medium zu booten. Dies kann z.B. sein, wenn das Netzwerk entweder sehr langsam ist oder erst noch richtig eingerichtet werden muss. Auch bei grundsätzlichen Problemen mit dem Netboot kann eine lokale Installation helfen.

komplette lokale Installation #

Generell muss man sich überlegen, wie viel man lokal installieren will. Im Grunde kann man einen vollwertigen Linux-Rechner installieren und dann dort einen X-Server mit der "-query ..."-Option starten. Oft reicht es aber auch, viel weniger zu installieren.

lokale Installation von Kernel und Initramdisk #

Eine andere Sache ist es, nur den Kernel und die initrd lokal zu installieren. In dieser kann man dann ggf. lokale Einstellungen vornehmen und dann mit Hilfe des bereits funktionierenden Linux-Systems das Netzwerk initialisieren und den Rest des Systems immer noch per NFS vom Server beziehen (um so ein zentrales, identisches System zu erhalten).

Ich habe hier einen ThinClient, der einen internen Flash-Speicher von 32MB hat. Diesen würde ich gerne per WLAN anbinden. In diesen Speicher passt kein komplettes Linux-System - allerdings reicht es, um mit Hilfe einer initrd das WLAN einzurichten und dann dort weiterzumachen.

Tips zum Thema habe ich mir aus dem LTSP-Wiki geholt (ist leider viel zu kompliziert, weil der Autor mehrere Dinge gleichzeitig gemacht hat).

Als erstes habe ich den Client an einem normalen Netzwerk normal gebootet, um mich auf ihm einloggen zu können. Der Flash-Speicher ist wie eine gewöhnliche Festplatte angebunden, also habe ich ihn mit cfdisk eingerichtet und mit mke2fs formatiert. Ich habe die Partition danach gemountet und dann den grub-Bootloader installiert. Zum Abschluss habe ich alle boot-Dateien des Clients kopiert:

  mke2fs /dev/hda1
  mount /dev/hda1 /mnt
  grub-install --root-directory=/mnt /dev/hda
  cp -a /boot/* /mnt/boot/

Dabei ist zu beachten, daß ich in meinem LTSP-Client die ganz normalen Debian-Kernel-Pakete installiert habe. Beim Booten per LTSP werden nämlich der Kernel sowie die initrd per tftp vom LTSP-Server geholt. Ich habe in meinem System aber dennoch (quasi unbenutzte) Dateien mit gleichem Inhalt in /boot/. (Bei Kernel-Updates kopiere ich diese dann jeweils in das tftp-Verzeichnis.)

Nun legen wir eine grub-typische Datei /mnt/boot/grub/menu.lst an. Diese sieht z.B. so aus:

  default=0
  timeout=0
  title ThinClient
        root (hd0,0)
        kernel /boot/vmlinuz ro root=/dev/hda1
        initrd /boot/initrd.img

Als nächstes habe ich den Client rebootet, im BIOS-Menü die Bootreihenfolge umgeschaltet und siehe da: Der Client hat ruck-zuck gebootet. Er hat ohne Probleme den Anschluss ans NFS gefunden, als wäre nichts gewesen.

Eventuell sollte man anhand seiner bisherigen Enistellung noch die Kernel-Aufrufzeile anpassen. Oben steht z.B. hda1, obwohl das offensichtlich nicht als root-Device genommen wird. Dennoch lief es erstmal so. :-)

Manipulation der initramdisk #

Bisher ist ja eigentlich noch nichts spannendes passiert. Nun will ich jedoch, daß die Initramdisk meinen WLAN-Adapter initialisiert, sich in ein WLAN einhängt, eine OpenVPN-Verbindung aufbaut (weil wir ja wohl einem WLAN nicht über den Weg trauen) und dann darüber das NFS-Laufwerk einbindet.

Grundsätzlich empfehle ich das Studium folgender manpage:

  man initramfs-tools

Wichtig zu wissen ist, daß man mit dem Parameter break in der Kernel-Startzeile den Startvorgang an verschiedenen Stellen unterbrechen kann. Das hilft beim Debuggen ungemein!

Installation zusätzlicher Treiber in der Initramdisk #

Ich habe einen WLAN-Adapter von "hama" in Form eines USB-Sticks. Das ist insoweit ganz praktisch, als im Grunde alle ThinClients einen USB-Port besitzen. Er läuft mit dem rt73-Treiber. Dieser ist leider in Debian Etch nicht standardmäßig vorhanden. Ich musste auf ein Paket rt73-source aus "experimental" zurückgreifen, das (am besten auf einem anderen System) mit

  module-assistant build rt73 -l 2.6.18-4-486

in ein Modul-Paket übersetzt wurde. Die Angabe der Kernelversion ist nötig, weil der Kompilierungsrechner in der Regel einen anderen Kernel benutzt als die Thin Clients.

Ansonsten sei hier generell gesagt, daß für irgendwelche andere Hardware natürlich im LTSP-Client-System alle benötigten Treiber installiert sein sollten. Damit sollte man ggf. auch erstmal testen können, ob man den Adapter überhaupt "von Hand" in Betrieb nehmen kann.

Ich habe dann (im LTSP-chroot) das folgende Hook-Skript /etc/initramfs-tools/hooks/wirelessboot (mit gesetzten x-Bit) angelegt:

  #!/bin/sh
  . /usr/share/initramfs-tools/hook-functions

  PREREQ="lvm"
  prereqs()
  {
        echo "$PREREQ"
  }

  case $1 in
        prereqs)
                prereqs
                exit 0
        ;;
  esac

  echo "Wireless-Module einbinden..."
  force_load rt73
  force_load ide-disk
  force_load generic
  force_load tun
  cp -a /root/wireless/* "${DESTDIR}/"

Wie man sieht, kopiere ich ein Verzeichnis /root/wireless, das ich folgendermassen gefüllt habe (auch im LTSP-chroot):

  mkdir -p /root/wireless/etc/Wireless/RT73STA/
  mkdir /root/wireless/mnt/
  cp /etc/Wireless/RT73STA/rt73.bin /root/wireless/etc/Wireless/RT73STA/
  mkdir /tmp/wireless
  cd /tmp/wireless
  aptitude download wireless-tools libiw28 openvpn libssl0.9.8 libc6 liblzo1 zlib1g 
  for package in *.deb ; do dpkg -x $package /root/wireless/ ; done
  cd /root/wireless
  rm -r usr/share/doc
  rm -r usr/share/man

Man kann nun noch nach eigenem Ermessen wieder Dateien löschen (die manpages brauchen wir wirklich nicht in der ramdisk), aber das sollte selbsterklärend sein. Da der Speicher wieder freigegeben wird, ist es letztlich auch nicht soooo wichtig.

Obiges Hook-Skript wird nun während der Installation ausgeführt und bindet sowohl das Kernel-Modul als auch mein wireless-Verzeichnis in die ramdisk ein. Die eigentliche Erzeugung starte ich (wieder auf dem chroot-System) mit

  cd /root/
  mkinitramfs -o initrd.img-2.6.18-4-486 2.6.18-4-486

Der letzte Parameter ist übrigens wieder dem Umstand geschuldet, daß ich diesen Befehl ja in einem chroot-Jail auf meinem LTSP-Server gebe, der einen ganz anderen Kernel haben kann als mein Client-System benutzt. Die neue initramdisk wird so im aktuellen Verzeichnis erzeugt und kann ggf. an Ihren Platz kopiert werden (/mnt/boot/, wenn man obige Vorbereitungen getroffen hat).

Zum Debuggen ist evtl. der Parameter "-k" interessant, der den Inhalt der ramdisk als Verzeichnis erhält, so daß man diesen nochmals kontrollieren kann.

automatischer Aufbau einer WLAN-Verbindung #

Grundsätzlich liegen die boot-Skripte in /etc/initramfs-tools/scripts/. Hier gibt es Unterverzeichnisse für verschiedene Stadien des Bootvorgangs. In /usr/share/initramfs-tools/init kann man im Sourcecode sehen, in welchem Stadium des Bootvorganges welche Skripten aufgerufen werden müssen (maybe_break ...-Zeilen). Im konkreten Fall des wireless Adapters ist das init-premount-Stadium das richtige. In den anderen premount-Skripten wird z.B. udev geladen, das die USB-Module bereits lädt und die Devices einrichtet (Das ist ein Fall für "prereqs"). Nach den mount-Skripten wird dann im nfs-Skript das Interface per DHCP eingerichtet und benutzt. Da müssen wir uns zwischen setzen. Dazu erzeugen wir die Datei /etc/initramfs-tools/scripts/init-premount/wireless:

  #!/bin/sh
  PREREQ="udev"
  prereqs()
  {
        echo "$PREREQ"
  }

  case $1 in
        prereqs)
                prereqs
                exit 0
        ;;
  esac

  for x in $(cat /proc/cmdline); do
        case $x in
                device=*)
                        device=${x#device=}
                ;;
                essid=*)
                        essid=${x#essid=}
                ;;
                wirelesskey=*)
                        wirelesskey=${x#wirelesskey=}
                ;;
                openvpn=*)
                        openvpn=${x#openvpn=}
                ;;
                hostname=*)
                        hostname=${x#hostname=}
                ;;
        esac
  done

  if [ -n "${device}" ]; then
        DEVICE=$device
        # den Wert fuer nachfolgende Skripte speichern
        echo "DEVICE=${device}" >>/conf/param.conf
  fi

  if [ -n "${essid}" ]; then
        # dem USB-System Zeit lassen, den WLAN-Treiber zu installieren
        sleep 5
        # Besonderheit fuer rt73-Treiber, schadet anderen aber wohl nicht:
        ifconfig $DEVICE up
        if [ -n "${wirelesskey}" ]; then
                iwconfig $DEVICE key $wirelesskey
        fi
        iwconfig $DEVICE essid $essid
  fi

  if [ -n "${openvpn}" ]; then
        # Als Parameter muss ein lokales Device angegeben werden, in dem die Schluessel liegen
        echo -n "OpenVPN startet..."
        mount $openvpn /mnt/
        # zuerst sollte die Basisverbindung konfiguriert werden
        ipconfig $DEVICE
        # source relevant ipconfig output
        . /tmp/net-${DEVICE}.conf
        # OpenVPN benoetigt seinerseits evtl. auch den Nameserver
        echo "nameserver $IPV4DNS0" >/etc/resolv.conf
        # Jetzt sollte das Ding starten:
        /usr/sbin/openvpn --daemon --cd /mnt/openvpn --config /mnt/openvpn/${hostname}.conf
        # Ich setze die MAC-Adresse des tun-Devices auf die meiner Ethernet-Schnittstelle
        # So ist es dem DHCP-Server egal, ueber welches Netz ich komme
        ifconfig eth0 down
        until ifconfig tap1; do sleep 1; done
        ifconfig tap1 down
        mac=`ifconfig eth0|grep eth0`
        ifconfig tap1 hw ether ${mac#*HWaddr}
        ifconfig tap1 up
        # Die weiteren Skripte sollen jetzt vom tun-Device als Hauptdevice ausgehen
        echo "DEVICE=tap1" >>/conf/param.conf
        echo "Fertig."
  fi

Wie man sieht, wird das WLAN auf der Kernel-Kommandozeile initialisiert und dann noch ein OpenVPN-Tunnel geöffnet. Beide Konfigurationen liegen letztlich auf dem lokalen Medium. Die Kernel-Bootzeile erscheint übrigens beim Hochfahren mitsamt dem WLAN-Schlüssel kurz auf dem Bildschirm und kann von jemandem, der es schafft, sich auf dem Client direkt einzuloggen mit "cat /proc/cmdline" jederzeit angezeigt werden. Wen das stört, der kann auch diese Konfiguration noch in ein Skript auslagern. Mich stört das nicht, weil ich WLAN per Definition für unsicher halte und deshalb OpenVPN benutze.

die Datei /mnt/boot/grub/menu.lst sieht nun so aus:

  default=1
  timeout=5
  title ThinClient cable
        root (hd0,0)
        kernel /boot/vmlinuz
        initrd /boot/initrd.img

  title ThinClient wireless
        root (hd0,0)
        kernel /boot/vmlinuz device=rausb0 essid=lugkr wirelesskey=<meinkey> openvpn=/dev/hda1 hostname=meinclient
        initrd /boot/initrd.img

Das OpenVPN habe ich serverseitig als Bridge in das LAN eingerichtet, das auf den Terminalserver zugreifen darf. Was nun konkret in das /mnt/openvpn-Verzeichnis gehört, liest man am besten auf der zugehörigen Seite.

Sonstiges #

Nun hat man in dem Client ein ungesichertes (d.h. WEP-gesichertes) und ein gesichertes (VPN-) Interface. Darum sollte man kurz nochmal checken, welche Dienste wo laufen. Bei einem normalen LTSP-Client (siehe LinuxTerminalServer) ist der Haupt-Dienst der X-Server. Hat man sich eingeloggt, kann man mit echo $DISPLAY erfahren, auf welchem Interface er läuft. Damit dieser sich auch wirklich an das richtige Interface bindet, kann man folgendes in die /etc/lts.conf schreiben:

  SCREEN_07 = startx -from meinclient.localdomain -query terminalserver

(Der Name des Clients muss übrigens voll qualifiziert sein oder man trägt die IP-Adresse ein, da der einfache Name auf 127.0.0.2 eingestellt wird.)

Auf welchem System erzeugt man das alles? #

Eigentlich ist es nicht so sinnvoll, das reguläre LTSP-System mit all diesem Installations-Kram vollzumüllen. Die Erzeugung des KErnel-Modul-Paketes mit Hilfe von module-assistant ging auch gut auf einem anderen System. Für die übrigen Sachen habe ich mir einfach eine Kopie des chroot-Verzeichnisses angelegt, mit der ich dann experimentiert habe.

Im Grunde reicht es dann, wenn man später die entstandene initrd in den TFTP-Server kopert und fertig. Man muss also das Client-System gar nicht verändern. Darüberhinaus halte ich es ggf. für sinnvoll, die verwendeten Treiber und Tools (z.B. das rt73-Kernelmodul sowie die wireless-tools in obigem Beispielfall) auf dem echten LTSP Client-System zu installieren, um ggf. im laufenden Betrieb Konfigurationen ändern zu können.

Ein Problem hierbei entsteht bei einem Kernel-Update. Dann wird nämlich in der Regel auch die initrd automatisch neu gebaut. Hier ist zu überlegen, ob man diese jeweils komplett neu erzeugt oder doch obige Skripten und Verzeichnisse auf dem Produktivsystem belässt (womit die erzeugte initrd dann natürlich nur noch für wireless Terminals taugt und nicht mehr für normale...).

Tags:  ThinClient

Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-8) was last changed on 21-Jan-2008 18:14 by PeterHormanns