AngoLinux

Realizzazione di un Laboratorio Diskless

- A cura del Prof. Stefano Salvi -


Sommario:

  1. Introduzione
  2. Compilazione del kernel delle stazioni
  3. Preparazione del disco di boot delle workstation
  4. Struttura necessaria nel server
  5. Gestione delle directory con nfsroot
  6. Inconvenienti nell'uso di nfsroot

Introduzione

Come è stato descritto in precedenza, il laboratorio nel quale si è installato Linux è composto da macchine diskless. Si è dovuto quindi scegliere la soluzione diskless per l'installazione.

E' comunque da notare che la soluzione diskless può essere interessante anche se il laboratorio è costituito da macchine con disco fisso.

Una soluzione diskless porta diversi vantaggi:

La soluzione scelta prevede l'uso di un server nfs, sul quale, oltre al normale albero delle directory di Linux, risiede una directory per ogni macchina, che verrà montata come root sulle macchine client.

Compilazione del kernel delle stazioni

Per creare le stazioni client occorre per prima cosa compilare un kernel separato, diverso da quello del server, da installare sulle macchine client.

Naturalmente occorrerà anche compilare nel kernel le driver per le schede di rete installate nel laboratorio.

Per compilare un kernel occorre per prima cosa avere installato tutti i necessari pacchetti.

Nell'ipotesi di utilizzare la distribuzione debian di Linux, dovremo aver installato i seguenti pacchetti:

(Se ho omesso qualcosa dalla lista, avvisatemi che la correggo)

Una volta installati i pacchetti richiesti, troveremo l'albero del sorgente del kernel nella directory /usr/src/linux.

Occorre ora posizionarsi nella directory dei sorgenti e digitare:

make menuconfig

che consente di accedere al menù di configurazione del kernel.

Occorrerà configurare normalmente il kernel ed inoltre attivare le seguenti opzioni:

Una volta selezionate le opzioni che servono, sarà opportuno salvare la configurazione (con la voce del Main Menu Save Configuration to an Alternate File) in modo da poterla recuperare in futuro. Ricordate che questo kernel non andrà tenuto come il kernel del server, ma solo per i client. Il kernel del server dovrà restare quello originale, precedentemente configurato.

A questo punto si può uscire dal programma di configurazione e salvare la configurazione scelta come configurazione attiva.

Adesso viene il momento di compilare il kernel, che si farà come la solito dando la seguente riga di comando:

make dep; make clean; make zImage

Questa operazione richiederà parecchio tempo e creerà alla fine il nuovo kernel compilato /usr/src/linux/arch/i386/boot/zImage.

Per avviare le stazioni si possono usare due metodi:

Nel caso si utilizzi una boot eprom, tutto il processo di rete avverrà attraverso la rete. La boot eprom caricherà il kernel dal server utilizzando un protocollo chiamato tftp che sta per trivial file transfer prolocol. Questo protocollo va a cercare i files necessari nella directory tftpboot.

Per creare una boot eprom per una scheda di rete si può utilizzare il pacchetto netboot nella sezione net.

Questa soluzione, oltre ad essere abbastanza complicata in quanto richiede, tra l'altro, la registrazione di una EPROM, non consente di fare il boot di sistemi operativi diversi su una singola macchina.

La nostra scelta è quindi caduta sulla realizzazione di un dischetto di boot, malgrado questa soluzione sia sicuramente più lenta ed i dischetti siano intrinsecamente poco affidabili. Descriveremo quindi questo secondo metodo, che comunque si distingue solamente per il processo di boot, non per la preparazione del server.

Preparazione del disco di boot delle workstation

Per avviare una stazione diskless, occorre lanciare il kernel appena creato, passandogli come parametro le opzioni necessarie per inizializzare la scheda di rete e per connettessi correttamente al server nfs.

Per creare un dischetto di avvio per linux ci sono tre metodi:

La prima soluzione non va bene, in quanto con questo metodo non è possibile passare parametri al kernel.

La scelta va quindi fatta tra DOS e Lilo.

La soluzine con Lilo consente di avere un dischetto che non possiede software proprietario (il Dos) e probabilmente è più veloce nel boot.

Bisogna notare che è necessario indicare ad ogni stazione alcuni parametri "personalizzati", diversi per ogni stazione. Questi paramteri sono:

Quindi ogni dischetto di boot dovrà essere diverso. Questo ci ha fatto optare per la soluzione con il Dos e Loadlin, in quanto in questo modo è possibile preparare una serie di script diversi per loadlin, uno per ogni workstation, contenente parametri diversi. Si potrà richiamare loadlin dal file autoexec.bat e quindi, di volta in volta, indicare in autoexec il file di parametri di loadlin opportuno per la workstation.

Il file autoexec.bat potrà essere il seguente:

loadlin @load180.par

Mentre il file load180.par, contenente i parametri del kernel conterrà una sola riga con il seguente contenuto:

zimage root=/dev/nfs nfsroot=10.0.50.200:/tftpboot/10.0.100.180 nfsaddrs=10.0.150.180:10.0.50.200:10.0.150.252:255.255.255.0:ws0:eth0

in questa riga zimage è il nome del kernel da caricare, root=/dev/nfs come sempre indica il dispositivo che contiene il file system root.

In questo caso il dispositivo è quello corrispondente al file system nfs (quindi non è un vero dispositivo).

Il parametro nfsroot indica l'indirizzo completo della directory di rete da montare come root. Questo indirizzo deve contenere ovviamente l'indirizzo del server (in forma numerica, in quanto non sarà ancora disponibile il servizio dns), seguito dalla directory da montare come root.

Nel nostro caso, il server sarà 10.0.50.200 mentre la directory per la root sarà /tftpboot/10.0.100.180. Scopriremo più avanti che 10.0.50.180 è l'indirizzo IP della workstation.

Il parametro nfsaddr serve per inizializzare la scheda di rete ed è composto da sei parti, separate dal carattere :. Le parti sono:

  1. 10.0.150.180 è l'indirizzo IP della scheda. Viene indicata esplicitamente, quindi ogni dischetto corrisponderà ad un particolare IP.
  2. 10.0.50.200 è l'indirizzo del server cui collegarsi, che corrisponde al server indicato nel precedente parametro nfsroot.
  3. 10.0.150.252 è il default gateway, per raggiungere le altre reti. In questo caso è indispensabile, dato che il server risiede su un'altra rete. Nel caso invece che il server fosse sulla stessa rete, si potrebbe indicare l'IP del server come gateway.
  4. 255.255.255.0 è la netmask che in questo caso indica una sottorete di 256 indirizzi IP. Questa maschera viene usata dal kernel per sapere se l'indirizzo IP di destinazione dei pacchetti appartiene alla stessa rete della nostra scheda di rete o deve passare per un router.
  5. ws0 è il nome simbolico della stazione. Serve per inizializzare l'hostname di Linux.
  6. eth0 è il dispositivo di rete da utilizzare. Salvo in situazioni molto particolari il nome sarà eth0.

Quindi occorrerà creare un dischetto bootable MS-DOS che conterrà i seguenti file:

msdos.sys
Uno dei due file di sistema del DOS, registrato dal programma di formattazione.
io.sys
L'altro file di sistema, sempre registrato dal programma di formattazione.
command.com
L'interprete di comandi del DOS, serve per interpretare l'autoexec.
autoexec.bat
Il file descritto prima, che richiama loadlin.exe con i parametri corretti.
loadlin.exe
Il programma che carica il kernel di Linux.
zimage
Il kernel di Linux compilato precedentemente, da far caricare a loadlin.
load180.par
Il file di parametri per loadlin descritto in precedenza.

Una volta creati i dischetti con i vari load180.par indicanti diversi indirizzi IP e diverse directory root, si potranno avviare le singole stazioni con questi dischetti e si sarà in Linux.

Struttura necessaria nel server

Come abbiamo visto, le stazioni si connettono al server NFS montando la directory indicata come root.

La directory scelta sarà una sottodirectory della directory tftpboot il cui nome corrisponde all'indirizzo IP della stazione.

Questa scelta è compatibile con quanto avviene con il protocollo tftp citato prima e quindi con il meccanismo delle boot rom.

Nella directory montata come root deve essere disponibile la struttura necessaria per il funzionamento del sistema. Potremmo avere quindi tutti i file e le directory necessarie per un sistema completo.

Questo però comporterebbe un impiego di almeno 100 Mb per ogni stazione, che è estremamente oneroso ed inutile, visto che la maggior parte dei file sono comuni e possono essere in sola lettura.

Si potrà allora pensare di montare le directory con i file comuni direttamente dal server negli opportuni posti nell'albero locale.

Bisogna però ricordare che al boot solo il file system root è montato e disponibile. Tutti gli altri filesystem vengono montati più avanti nella fase di boot. Occorrerà allora copiare nella directory 'locale' i file necessari per il boot e montare le directory necessarie in seguito.

Inoltre le directory etc e var contengono file che devono essere diversi da stazione a stazione e file globali che è comodo che siano comuni.

Per risolvere il problema delle directory etc e var, possiamo montare le etc e var originali del server in un posto noto del nostro albero, ad esempio in /server/etc e /server/var e quindi, nelle directory etc e var della stazione mettere dei link simbolici ai file ed alle directory comuni che si trovano nella directory /server e dei file o directory regolari per per i file che devono essere disponibili al boot o che devono essere diversi.

Descriviamo quindi la struttura delle directory, indicando quali sono "locali" e quali provengono dal server:

Naturalmente, per poter montare correttamente le directory indicate, occorre che il server le renda disponibili. Per questo, oltre ad attivare il server nfs, occorre dare gli opportuni diritti ai client tramite il file /etc/exports. Questo file potrà contenere i seguenti dati:


# /etc/exports: the access control list for filesystems which may be exported
#               to NFS clients.  See exports(5).
/usr    10.0.0.0/255.255.0.0(ro,squash_uids=0-100,squash_gids=0-80)
/lib    10.0.0.0/255.255.0.0(ro,squash_uids=0-100,squash_gids=0-80)
/bin    10.0.0.0/255.255.0.0(ro,squash_uids=0-100,squash_gids=0-80)
/sbin   10.0.0.0/255.255.0.0(ro,squash_uids=0-100,squash_gids=0-80)
/etc    10.0.0.0/255.255.0.0(ro,squash_uids=0-100,squash_gids=0-80)
/mnt    10.0.0.0/255.255.0.0(ro,squash_uids=0-100,squash_gids=0-80)
/var    10.0.0.0/255.255.0.0(ro,squash_uids=0-100,squash_gids=0-80)
/home   10.0.0.0/255.255.0.0(rw,no_root_squash)
/tftpboot       10.0.0.0/255.255.0.0(rw,no_root_squash)

In ogni riga troviamo per primo il percorso completo della directory esportata.

Il secondo campo indica gli utenti che si possono connettere alla directory indicata. Nel nostro caso viene indicato un range di indirizzi ip, indicato come rete/maschera, quindi con i dati scritti si potrà accedere alle directory da tutte le stazioni con ip che vanno da 10.0.0.0 a 10.0.255.255.

Tra parentesi è indicato il modo in cui queste stazioni possono accedere alla directory indicata nella riga. Vediamo cosa significano le varie opzioni che troviamo indicate:

Occorre quindi generare, per ogni stazione, una directory contenente tutti i file, i link e le directory necessari. Questa operazione risulta molto lunga e complicata se va ripetuta per ogni singola stazione. Per fortuna è possibile utilizzare uno script che genera le directory ed i link a partire da un prototipo.

Questo script ed un prototipo standard sono contenuti nel pacchetto nfsroot.

Gestione delle directory con nfsroot

Il pacchetto che ci serve per gestire le directory delle stazioni secondo i criteri descritti in precedenza è il pacchetto opzionale nfsroot nella sezione net.

Lo script che crea le directory per le stazioni è mknfsroot nella directory /usr/sbin. Questo è uno script di bash che crea, nella directory /tftpboot, una directory per ogni stazione, con l'ip della stazione come nome.

Mknfsroot va chiamato con una lista di nomi di host (o di ip di host) per i quali creare le directory.

La struttura delle directory che troveremo nella directory della stazione viene copiata dalla directory prototipo /etc/nfsroot/default. Le directory in questo prototipo verranno copiate nella directory della stazione.

Per risparmiare spazio sul disco, i file indispensabili per il boot, contenuti nelle directory /bin e /sbin non vengono copiati direttamente nelle directory delle stazioni, creandone una copia per stazione. Al contrario, questi file vengono copiati nella directory /tftpboot/store e nelle directory delle stazioni troviamo solo dei link (hard link) a questi file.

Un discorso diverso va fatto per la directory /etc e le sue sottodirectory.

Come abbiamo accennato in precedenza, in questa directory devono esistere dei file "privati" relativi alla stazione, eventualmente modificati per contenere i dati della stazione, e dei file condivisi con il server.

Tutti i file che compaiono nella directory /etc/nfsroot/default/etc oppure nella directory personalizzata /etc/tftpboot/<IP>/etc vengono copiati nella etc della stazione e vengono poi processati tramite sed per modificare i riferimenti alla stringa SERVERIP con l'ip reale del server e la stringa CLIENTIP con l'ip reale della stazione.

Per tutti i file contenuti nella directory /etc del server e non nella directory /etc/nfsroot/default/etc o /etc/tftpboot/<IP>/etc nella directory /etc viene creato un link alla directory /server/etc della stazione, nella quale verrà montata la directory /etc del server.

Se nella directory /etc compaiono tutti i file della /etc originale, tutti i servizi del server verranno anche attivati sulle stazioni.

Dato che questo non è sempre corretto e desiderabile, è opportuno poter eliminare dei file dalla /etc delle stazioni. Per fare questo si può utilizzare il file ignorefiles, sempre contenuto nella directory /etc/nfsroot. Questo file contiene già una serie ragionevole di file da escludere dalla directory /etc o dalle sue sottodirectory. Se dovete escludere altri file, dovete indicare il percorso del file a partire dalla directory /etc, usando anche i caratteri * o ? per indicare gruppi di file, oppure liste, racchiuse tra parentesi e separate da |.

Nella directory /etc/nfsroot ci sono altri file di configurazione:

È da notare che il prototipo contenuto in /etc/nfsroot/default contiene una versione particolare del file etc/init.d/boot che è lo script eseguito dal demone di boot, modificato per avviare la rete il prima possibile e per montare per prima cosa i volumi nfs, a differenza che nei sistemi normali che montano i volumi nfs al termine del processo di boot.

Un altro file importante da notare in quella directory è il file etc/fstab, che contiene i riferimenti a tutte le directory del server da montare, come visto all'inizio della spiegazione.

Occorre infine notare che invece non compare il file /etc/passwd. Questo significa che le stazioni utilizzeranno il file passwd del server.

Dato che le stazioni condividono la directory home del server, vale a dire le directory degli utenti, è giusto utilizzare un unico file passwd che descriva gli utenti.

Il fatto che questo file passwd sia quello del server implica però che questo file non sia modificabile dalle stazioni. Da una stazione quindi non si potrà creare un nuovo utente né cambiare la password degli utenti già presenti. Questo può essere un inconveniente, ma può essere anche visto some una protezione nei confronti degli errori degli studenti.

Inconvenienti nell'uso di nfsroot

L'unico problema che ho incontrato nell'uso di questo pacchetto è stato l'uso che esso fa dei comandi host o nslookup per individuare il nome e l'IP delle stazioni, nella funzione mkhost ().

Nel mio sistema il comando host produce un'uscita diversa da quella che si aspetta lo script, quindi lo script si rifiutava di funzionare.

Per poter ottenere il regolare funzionamento dello script, ho dovuto modificare come segue la funzione mkhost () nello script /usr/sbin/mknfsroot:

function mkhost () {
  host=$1

  fqhostname=`echo $host | nslookup |sed -n "s/^.*Name: *//p"`
  hostname=`echo $fqhostname |cut -d. -f 1`
  # hostip=`echo $host | nslookup |sed -n -e '4,$s/^.*Address: *//p'`
  hostip=`echo $host | nslookup |sed -n 's/^.*Address: *//p'`
  ...
  ...

Naturalmente questa modifica funziona sul mio sistema, ma potrebbe non funzionare in altri. Queste righe devono, a partire dal nome della stazione contenuto nella variabile host, che può essere sia un nome dns che un indirizzo IP, mettere nella variabile hostname il nome dns della stazione e nella variabile hostip l'IP della stazione.

Lo script, come da me modificato, presenta comunque il grave inconveniente di non consultare il file /etc/hosts. Questo è un inconveniente abbastanza pesante, in quanto in genere i nomi delle stazioni non sono elencati in un server dns visto che sono conosciuti solo localmente.

Un metodo per aggirare l'ostacolo è quello di installare un demone dns sul nostro server. Questa soluzione non è ottimale in quanto il server dns non è facile da configurare e prevede una connessione costante ad Internet, in quanto ha bisogno di un server dns "padre" cui rivolgersi per i nomi che non conosce.

Una migliore soluzione sarebbe quella modificare lo script in modo da interrogare il file hosts prima di accedere al dns, ma questa modifica non è ancora stata eseguita.


[Home Page dell'ITIS "Fermi"] [Indice Angolinux] [Precedente] [Successivo]