: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