:wip:
====== Création d'un CD d'installation automatisée pour Debian ======
La distribution GNU/Linux Debian permet une installation automatique
non assistée en utilisant un fichier de préconfiguration
''preseed.cfg''.
''preseed.cfg'' contient les réponses pré-remplies aux questions posées
lors d'une installation interactive classique.
La méthode décrite ci-dessous crée un CD d'installation automatisée.
Une procédure similaire d'installation par le réseau fera l'objet d'un
document dédié.
===== Vue générale de la procédure d'installation classique =====
Lors de l'installation **un système d'exploitation minimal** est chargé
en mémoire.
Ce système d'exploitation minimal a pour seule fonction d'installer
sur le disque dur de l'ordinateur le système d'exploitation final.
La procédure d'installation interactive requiert la présence d'un
administrateur du début à la fin et l'absence d'une réponse à une
question suspend l'installation.
La présence physique d'un administrateur pour superviser cette
opération n'est pas toujours possible et la fréquence à laquelle cette
procédure doit être réalisée peut contrarier la faisabilité d'un
projet.
===== Le fichier preseed.cfg =====
Le fichier ''preseed.cfg'' contient un ensemble d'instructions pour les
différents composants de l'installateur.
Un exemple de fichier ''preseed.cfg'' est fourni par Debian à
[[https://www.debian.org/releases/sarge/example-preseed.txt|cette
adresse]] et mérite d'être examiné.
Quand le programme installateur debian rencontre un fichier
''preseed.cfg'' à la racine du **système d'exploitation minimal**, il
l'utilisera pour renseigner les composantes d'installation au lieu de
solliciter une interaction.
===== En quoi consiste la création d'un CD d'installation non assistée =====
**Le système d'exploitation minimal** est modifié pour inclure le
fichier ''preseed.cfg'' à sa racine.
Pour créer cette version automatisée de CD d'installation, il faut se
munir des paquets suivants :
''# apt-get install bsdtar genisoimage''
Un CD d'installation classique est nécessaire. Le netinst de debian
peut faire l'affaire pour le test mais cela fonctionne de la même
manière pour les autres formats.
''# wget debian-9.6.0-amd64-netinst.iso''
Extraire le contenu de l'image nous permet d'avoir une copie
modifiable. Le paquet ''bsdtar'' simplifie l'opération.
# mkdir isofiles
# bsdtar -C isofiles -xf debian-9.6.0-amd64-netinst.iso
Le contenu du CD d'installation est maintenant disponible à la
modification dans le dossier ''isofiles''.
===== Modification de l'initrd.gz =====
''initrd.gz'' contient le système d'exploitation minimal.
Pour modifier cette archive, il faut la décompresser. Mais d'abord il
faut veiller à autoriser l'écriture dans le dossier contenant
''initrd.gz''.
# ls -l isofiles/install.amd/
total 20M
dr-xr-xr-x 2 sysadm sysadm 4,0K nov. 10 12:34 gtk
dr-xr-xr-x 2 sysadm sysadm 4,0K nov. 10 12:34 xen \o/
-r--r--r-- 1 sysadm sysadm 16M janv. 11 12:34 initrd.gz <------------------- |
-r--r--r-- 1 sysadm sysadm 45 nov. 10 12:34 install.bat / \
-r--r--r-- 3 sysadm sysadm 4,1M nov. 10 12:34 vmlinuz
# chmod +w -R isofiles/install.amd/
# gunzip isofiles/install.amd/initrd.gz
# ls -l isofiles/install.amd/
total 52M
drwxr-xr-x 2 sysadm sysadm 4,0K nov. 10 12:34 gtk
drwxr-xr-x 2 sysadm sysadm 4,0K nov. 10 12:34 xen
-rw-r--r-- 1 sysadm sysadm 48M janv. 11 12:36 initrd
-rw-r--r-- 1 sysadm sysadm 45 nov. 10 12:34 install.bat
-rw-r--r-- 3 sysadm sysadm 4,1M nov. 10 12:34 vmlinuz
===== Incorporer pressed.cfg dans initrd et création du CD final =====
Une fois le fichier ''preseed.cfg'' préparé, il s'agit de l'incorporer
dans l'''initrd''. ''initrd'' est une archive qui peut être manipulée avec
la commande ''cpio'' installée par défaut.
# ls -F
isofiles/
preseed.cfg
# echo preseed.cfg | cpio -H newc -o -A -F isofiles/install.amd/initrd
[...]
# gzip isofiles/install.amd/initrd
# chmod -R -w isofiles/install.amd/
Une dernière étape est nécessaire avant la création de l'iso.
L'installateur Debian s'appuie sur un fichier contenant la somme de
contrôle de tous les fichiers contenus dans le CD pour les valider. Ce
fichier est contenu à la racine du cd et est nommé ''md5sum.txt''
Puisque nous avons modifié le fichier ''initrd.gz'' nous devons
recalculer sa somme de contrôle pour la rapporter dans le fichier
''md5sum.txt''
La commande suivante nous permet reconstruire ''md5sum.txt'' pour tous
les fichiers contenus dans le projet d'iso.
# cd isofiles
# md5sum `find -follow -type f` | sudo tee md5sum.txt
# cd ..
Ça y est, le dossier ''isofiles'' est fin prêt à être converti en
fichier iso.
Nous utilisons la commande genisoimage pour ce faire avec la syntaxe
suivante :
# genisoimage -quiet -r -J -b isolinux/isolinux.bin \
-c isolinux/boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-o DEBIAN-automatique.iso isofiles
La commande crée un fichier ''DEBIAN-automatique.iso'' à partir du
contenu du dossier ''isofiles'' dans lequel nous avons construit un
''initrd.gz'' avec un ''preseed.cfg'' incorporé.
Il ne reste plus qu'à graver le CD sur un support usb ou disque
optique, tester et profiter d'une installation automatisée.
Si celle-ci échoue il faudra modifier le fichier ''preseed.cfg'' et
revenir dans le cycle : incorporation du ''preseed.cfg'' dans
l'''initrd.gz'', reconstruction du fichier de sommes de calculs
''md5sum.txt'' et création de l'iso.
Cette opération peut elle-même être automatisée pour accélérer la
procédure. Un exemple est donné en fin d'article.
===== Aller plus loin avec preseed/late_command =====
Un des éléments les plus intéressants dans cette méthode est la
possibilité d'exécuter des commandes juste avant la fin de
l'installation avec la clé ''preseed/late_command''.
À la fin du ''preseed.cfg'' exemple fourni par Debian, nous pouvons lire
# This command is run just before the install finishes, but when there is
# still a usable /target directory. You can chroot to /target and use it
# directly, or use the apt-install and in-target commands to easily install
# packages and run commands in the target system.
# d-i preseed/late_command string apt-install zsh; in-target chsh -s /bin/zsh
Quelques informations importantes sont données ici :
* Le disque dur de l'ordinateur est accessible sur le point de montage ''/target''
* L'instruction ''in-target'' de la clé ''preseed/late_command'' permet d'exécuter des commandes en ''chroot'' c'est à dire en considérant le disque dur de l'ordinateur comme racine d'exécution.
Dans l'exemple du ''pressed.cfg'' fourni par Debian, le paquet ''zsh'' est
installé et fera partie du système d'exploitation final. Ensuite, avec
''in-target'', la commande de changement de shell de connexion (''chsh
-s'') est exécutée avec le disque dur contenant le système
d'exploitation final comme environnement d'exécution.
===== Exemple d'exploitation de preseed/late_command =====
Après avoir maîtrisé la procédure de modification du système
d'exploitation minimal, une customisation plus approfondi du système
d'exploitation final est possible.
Rien n'empêche l'ajout d'autres fichiers que le ''preseed.cfg'' dans le
système d'installation ''initrd.gz''.
Nous pouvons y incorporer, une liste de clés publiques ssh et les
injecter dans le système final. Ça nous permettra d'accéder à la
machine sans mot de passe.
Nous pouvons également injecter des scripts d'initialisation qui
s'exécuteront au premier redémarrage de la machine après la fin de
l'installation.
Les exemples donnés ici sont triviaux et ne servent qu'à illustrer la
procédure.
De la même manière que nous avons ajouté le fichier ''preseed.cfg'' dans
''initrd'', nous allons ajouter un fichier contenant des clés ssh
publiques et nous utilisons ''preseed/late_command'' pour les injecter
dans le système d'exploitation final.
# echo preseed.cfg | cpio -H newc -o -A -F isofiles/install.amd/initrd
# echo authorized_keys | cpio -H newc -o -A -F isofiles/install.amd/initrd
Et dans le fichier ''preseed.cfg'' :
# [....]
d-i preseed/late_command string \
in-target mkdir /root/.ssh; \
cp /authorized_keys /target/root/.ssh/; \
in-target chmod 700 /root/.ssh; \
in-target chmod 600 /root/.ssh/authorized_keys; \
true;
===== Cycle de développement et de test du preseeding =====
Même en excluant la nécessité d'interaction lors de la procédure
d'installation d'un système d'exploitation, l'opération demeure
lourde.
Utiliser un système de virtualisation pour tester immédiatement le
résultat est incontournable pour avancer en toute sécurité et pour
maîtriser rapidement la procédure.
Ci-dessous un script qui fait usage de ''libvirt'' pour tester l'iso
« preseedé ». Une introduction à ''libvirt'' est accessible à cette [[system_administration:automation:virtualiser_avec_kvm|page]].
#!/bin/bash
##########################################################################################
# This script help on testing preseed.cfg for automatic unattended debian install #
# #
# The script needs genisoimage, bsdtar, syslinux-utils installed on your system #
##########################################################################################
MAKE_VM="$1" # calling this script with `vm' as argument launch the installation
# with the preseeded iso on a virsh domain
# OPDIR="$( cd "$(dirname "$0")" ; pwd -P )"/
ORIGIN_ISO="$(basename "/home/aziz/debian-9.6.0-amd64-netinst.iso")"
TARGET_VM=sarahdeb # the name of the vm to create
DISC_SIZE=8
RAM_SIZE=512
CPU=1
PROVISION_FILES="postinstall.sh preseed.cfg rc.local authorized_keys" # files injected into the install process
RESULT_ISO=sarahdeb-${ORIGIN_ISO} # 'generated iso name' will be 'origin iso name' prefixed with 'preseed-'
ORIGIN_ISO_PATH="/home/aziz/debian-9.6.0-amd64-netinst.iso"
RESULT_ISO_PATH=${OPDIR}${RESULT_ISO}
EXTRACTED_ISO_DIR=${ORIGIN_ISO/\.iso/}
EXTRACTED_ISO_PATH=/tmp/${EXTRACTED_ISO_DIR}/ # The path to directory containing extracted iso files
INSTALLAMD_DIR=install.amd/
INSTALLAMD_PATH=${EXTRACTED_ISO_PATH}${INSTALLAMD_DIR}
INITRDGZ_FILE=initrd.gz
INITRD_FILE=initrd
INITRDGZ_PATH=${INSTALLAMD_PATH}${INITRDGZ_FILE} # path to initrd.gz
INITRD_PATH=${INSTALLAMD_PATH}${INITRD_FILE}
LIST_RUNNING_VM_COMMAND="virsh -c qemu:///system list --state-running --name"
LIST_ALL_VM_COMMAND="virsh -c qemu:///system list --all --name"
function check_deps(){
dpkg-query -l bsdtar &> /dev/null ;
if [ ! $? == "0" ];then
sudo apt-get install -y bsdtar
fi
dpkg-query -l genisoimage &> /dev/null ;
if [ ! $? == "0" ];then
sudo apt-get install -y genisoimage
fi
}
check_deps || exit 2;
function purge_vm(){
# before beginning the vm will be deleted
for i in $(eval $LIST_RUNNING_VM_COMMAND); do
if [ $i == $TARGET_VM ];then
virsh -c qemu:///system destroy $TARGET_VM
break;
fi
done
for i in $(eval $LIST_ALL_VM_COMMAND); do
if [ $i == $TARGET_VM ];then
virsh -c qemu:///system undefine $TARGET_VM --remove-all-storage
break;
fi
done
}
function extract_iso(){
cd $OPDIR
mkdir $EXTRACTED_ISO_PATH
bsdtar -C $EXTRACTED_ISO_PATH -xf $ORIGIN_ISO_PATH
}
function unlock (){ chmod +w -R $1; } # to make a dir writable
function ziplock(){ chmod -w -R $1; } # to revert to readonly
function reuse_extracted_iso_path(){
# if an iso has been already extracted
# just pick the initrd.gz file from a temporary mount
# instead of extracting
tempdir=$(mktemp -d)
sudo mount -o loop $ORIGIN_ISO_PATH $tempdir
unlock $INSTALLAMD_PATH
rm $INITRDGZ_PATH
cp $tempdir/${INSTALLAMD_DIR}${INITRDGZ_FILE} $INITRDGZ_PATH
ziplock $INSTALLAMD_PATH
sudo umount $tempdir
rm -rf $tempdir
}
function rewrite_initrd(){
# Usage: rewrite_initrd file1 file2
# inject space separated list of files into initrd
# then gzip initrd
to_inject="$@"
unlock $INSTALLAMD_PATH
gunzip $INITRDGZ_PATH
cd $OPDIR
for file in $to_inject;
do
echo Adding $file to initrd
echo $file | cpio -H newc -o -A -F $INITRD_PATH
done
gzip $INITRD_PATH
ziplock $INSTALLAMD_PATH
}
function rewrite_isolinux_cfg() {
unlock ${EXTRACTED_ISO_PATH}isolinux
FILE=${EXTRACTED_ISO_PATH}isolinux/txt.cfg
rm $FILE
cat >$FILE </dev/null
cd $OPDIR
}
function geniso(){
# Generating the preseeded iso
cd $OPDIR
sudo genisoimage -quiet -r -J -b isolinux/isolinux.bin \
-c isolinux/boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-o $RESULT_ISO_PATH $EXTRACTED_ISO_PATH
sudo isohybrid $RESULT_ISO_PATH
}
function install_vm_from_preseed(){
# Creating the vm to test install
cd $OPDIR
virt-install --connect qemu:///system \
--virt-type kvm \
--os-variant generic \
--os-type linux \
--network network=default \
--name=$TARGET_VM \
--disk size=$DISC_SIZE \
--ram=$RAM_SIZE \
--vcpus=$CPU \
--graphics vnc \
--console pty,target_type=serial \
--cdrom $RESULT_ISO_PATH
}
function main(){
if [ ! -z $MAKE_VM ]; then
purge_vm;
fi
if [ ! -d $EXTRACTED_ISO_PATH ]; then
extract_iso;
else
reuse_extracted_iso_path;
fi
rewrite_isolinux_cfg;
rewrite_initrd $PROVISION_FILES;
rebuild_md5sum_file;
geniso;
if [ ! -z $MAKE_VM ]; then
install_vm_from_preseed;
fi
}
main
#purge_vm;
function install_vm_from_location(){
cd $OPDIR
virt-install --connect qemu:///system \
--virt-type kvm \
--os-variant generic \
--os-type linux \
--network network=default \
--name=$TARGET_VM \
--disk size=$DISC_SIZE \
--ram=$RAM_SIZE \
--vcpus=$CPU \
--graphics vnc \
--console pty,target_type=serial \
--initrd-inject preseed.cfg \
--extra-args "ipv6.disable=1 BOOT_DEBUG=0 DEBIAN_FRONTEND=text console=ttyS0,115200n8" \
--location "http://ftp2.de.debian.org/debian/dists/stretch/main/installer-amd64/"
}
#install_vm_from_location
===== Exemple d'un fichier preseed.cfg =====
#########################
# Keyboard and TimeZone #
#########################
d-i keyboard-configuration/xkb-keymap select fr(latin9)
d-i debian-installer/locale string fr_FR
d-i time/zone string Africa/Algiers
d-i clock-setup/ntp boolean true
d-i clock-setup/utc boolean true
###################
# Hardware detect #
###################
d-i hw-detect/load_firmware boolean true
#################
# User creation #
#################
d-i passwd/root-login boolean false
d-i passwd/user-fullname string dino
d-i passwd/username string dino
d-i passwd/user-password-again password dingo
d-i passwd/user-password password dingo
#################################
# Network and hostname settings #
#################################
d-i netcfg/get_hostname string dalton
d-i netcfg/hostname string dalton
d-i netcfg/choose_interface select auto
d-i netcfg/get_domain string
d-i netcfg/link_wait_timeout string 5
d-i netcfg/wireless_wep string
#########################
# Partitionning section #
#########################
d-i partman-auto/method string regular
d-i partman-auto/choose_recipe select atomic
d-i partman-auto/disk string /dev/sda
d-i partman/mount_style select uuid
d-i partman/choose_partition select finish
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-md/confirm boolean true
d-i partman-md/device_remove_md boolean true
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
#######################
# Apt mirror settings #
#######################
apt-mirror-setup apt-setup/no_mirror boolean true
d-i mirror/country string manual
d-i mirror/http/directory string /debian
d-i mirror/http/hostname string deb.debian.org
d-i mirror/http/proxy string
d-i mirror/protocol string http
d-i mirror/suite string stretch
d-i mirror/udeb/suite string stretch
d-i apt-setup/contrib boolean true
d-i apt-setup/non-free boolean true
d-i apt-setup/security_host string security.debian.org
d-i apt-setup/services-select multiselect security, updates
d-i apt-setup/use_mirror boolean false
d-i base-installer/install-recommends boolean true
d-i debian-installer/allow_unauthenticated boolean true
############################
# Do not ask about more CD #
############################
apt-cdrom-setup apt-setup/cdrom/set-double boolean false
apt-cdrom-setup apt-setup/cdrom/set-first boolean false
apt-cdrom-setup apt-setup/cdrom/set-next boolean false
#########################
# No popularity contest #
#########################
popularity-contest popularity-contest/participate boolean false
#######################
# Packages to install #
#######################
tasksel tasksel/first multiselect standard
d-i pkgsel/include string openssh-server
d-i pkgsel/upgrade select none
################
# Grub install #
################
d-i grub-installer/bootdev string default
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
#################
# Late commands #
#################
d-i preseed/late_command string \
in-target mkdir /home/dino/.ssh; \
cp /authorized_keys /target/home/dino/.ssh/; \
in-target chown -R dino: /home/dino/.ssh; \
in-target chmod 700 /home/dino/.ssh; \
in-target chmod 600 /home/dino/.ssh/authorized_keys; \
true;
############
# Good Bye #
############
d-i finish-install/reboot_in_progress note