selfinst构建自安装的系统镜像
Table of Contents
无人值守安装(unattended install)
主流linux发行版一般都有自己的无人值守安装系统,例如redhat系的Anaconda(anaconda-ks.cfg)、suse系的AutoYaST(autoinst.xml) 、debian系的Debian-Installer(preseed.cfg)。
其实它们的工作流程都是类似的,无非就是下载官方的基础iso镜像,再配上一个描述文件,最后生成一个新的iso镜像。所以我把流程理了一下,写了个selfinst的项目,把整个流程脚本化,接口只要提供源iso、描述文件、目标iso这三个参数就可以了。
我目前所有的linux 机器统一都用debian,因此只写了selfinst-debian.sh这一个脚本。不过暂时足够我使用了,后续如果有需求再添加就行,反正基础流程已经统一了,再写起来也是大同小异。
以debian为例子
debian-installer使用的preseed.cfg作为描述文件,所以描述文件的第二个参数需要提供preseed.cfg,跑起来也非常简单,只需要像下面这样。
两种方式使用
selfinst-debian.sh #or selfinst-debian.sh [src.iso] [preseed.cfg] [dst.iso]
1.第一种就是直接不带参数使用selfinst-debian.sh,它会根据脚本中一个叫iso_name的变量下载指定版本的ISO,然后生成一个带有preseed前缀的新镜像。 2.第二种则是提供已经下载的src.iso和描述文件以及设置要生成的dst.iso路径,这样就会根据提供的镜像生成新的无人值守镜像,名字就是dst提供的文件名。
下面简单介绍一下selfinst-debian的工作流程
参数获取
path_src_iso=$(readlink -f "$1") path_preseed=$(readlink -f "$2") path_dst_iso=$(readlink -f "$3") PATH_SCRIPT=$(dirname "$(realpath "$0")") PATH_WORK="$PATH_SCRIPT/iso-debian" PATH_SRC="$PATH_WORK/iso-decompressed" PATH_DST="$PATH_WORK/iso-new"
src iso、preseed.cfg、dst iso三个变量通过脚本参数获取,然会通过PATH_WORK SRC DST三个变量构建出iso-debian、iso-decompreseed、iso-new三个目录,分别用来存放源镜像,解压后的iso以及新生成的ISO。
镜像下载以及较检
iso="" iso_name=$(wget -q -O - https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/ | grep -oP 'debian-\d+\.\d+\.\d+-amd64-netinst\.iso' | sort -r | head -n 1) if [ -z "$iso_name" ]; then echo "Failed to find the latest ISO name" exit 1 fi mkdir -p $PATH_WORK $PATH_SRC $PATH_DST cd $PATH_WORK if [ "$path_src_iso" = "" ] ; then if [ ! -f "$PATH_WORK/$iso_name" ] ; then wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/$iso_name if [ $? -ne 0 ]; then echo "Failed to download $iso_name" exit 1 fi wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA512SUMS if [ $? -ne 0 ]; then echo "Failed to download SHA512SUMS" exit 1 fi computed_checksum=$(sha512sum $iso_name | awk '{ print $1 }') expected_checksum=$(grep $iso_name SHA512SUMS | awk '{ print $1 }') if [ "$computed_checksum" = "$expected_checksum" ]; then echo "ISO sha512 checksum matches!" else echo "ISO sha512 checksum does not match!" exit 1 fi fi iso=$PATH_WORK/$iso_name else if [ ! -e "$path_src_iso" ] ; then echo "Source ISO file $path_src_iso does not exist!" exit 1 fi cp $path_src_iso $PATH_WORK iso=$path_src_iso fi cat $iso | bsdtar -C "$PATH_SRC" -xf -
如果没有提供源镜像,就会下载最新的镜像并用sha512校检,然后解压到iso-decompressed目录中。
描述文件生成
#------------------------- preseed ----------------------------------- preseed_hostname="selfinst" preseed_nameservers="114.114.114.114" preseed_mirror_url="mirrors.ustc.edu.cn" preseed_password_root="selfinstroot" preseed_user="g" preseed_password_g="selfinstg" preseed_package="openssh-server build-essential vim syncthing barrier" if [ "$path_preseed" = "" ]; then cat << EOF > ./preseed.cfg ### Localization d-i debian-installer/locale string en_US d-i console-keymaps-at/keymap select us d-i keyboard-configuration/xkb-keymap select us ### Network configuration d-i netcfg/choose_interface select auto d-i netcfg/get_hostname string $preseed_hostname d-i netcfg/get_domain string lan d-i netcfg/get_nameservers string $preseed_nameservers ### Mirror settings # mirror and apt setup d-i mirror/protocol string http d-i mirror/country string manual d-i mirror/http/hostname string $preseed_mirror_url d-i mirror/http/directory string /debian #d-i mirror/suite string stable #d-i mirror/suite string testing d-i mirror/suite string unstable d-i mirror/http/proxy string ### Apt setup d-i apt-setup/non-free boolean true d-i apt-setup/contrib boolean true #d-i apt-setup/use_mirror boolean false #d-i apt-setup/enable-source-repositories boolean true d-i apt-setup/disable-cdrom-entries boolean true d-i apt-setup/services-select multiselect main, security d-i apt-setup/security_host string $preseed_mirror_url d-i apt-setup/cdrom/set-first boolean false d-i apt-setup/cdrom/set-next boolean false d-i apt-setup/cdrom/set-failed boolean false ### Package selection tasksel tasksel/first multiselect standard, web-server, kde-desktop tasksel tasksel/desktop multiselect kde d-i pkgsel/include string $preseed_package d-i pkgsel/upgrade select none d-i pkgsel/language-packs multiselect en, zh d-i pkgsel/update-policy select none ### Account setup d-i passwd/root-password password $preseed_password_root d-i passwd/root-password-again password $preseed_password_root d-i passwd/user-fullname string $preseed_user d-i passwd/username string $preseed_user d-i passwd/user-password password $preseed_password_g d-i passwd/user-password-again password $preseed_password_g ### Clock and time zone setup d-i clock-setup/utc boolean false d-i time/zone string Asia/Shanghai ### Partitioning d-i partman-auto/disk string /dev/sda d-i partman-auto/method string regular d-i partman-lvm/device_remove_lvm boolean true d-i partman-md/device_remove_md boolean true d-i partman-auto/choose_recipe select atomic d-i partman-partitioning/confirm_write_new_label boolean true d-i partman/choose_partition select finish d-i partman/confirm boolean true d-i partman/confirm_nooverwrite boolean true popularity-contest popularity-contest/participate boolean false ### Boot loader installation d-i grub-installer/only_debian boolean true d-i grub-installer/bootdev string default ### Finishing up the installation d-i finish-install/keep-consoles boolean true d-i finish-install/reboot_in_progress note
描述文件我将preseed.cfg里常见的几个参数写到了几个变量里,放一起改起来比较方便,然后在用echo重定向生成一个preseed.cfg文件。
preseed_hostname="selfinst" preseed_nameservers="114.114.114.114" preseed_mirror_url="mirrors.ustc.edu.cn" preseed_password_root="selfinstroot" preseed_user="g" preseed_password_g="selfinstg" preseed_package="openssh-server build-essential vim syncthing barrier"
设置preseed
chmod -R +w $PATH_SRC gunzip $PATH_SRC/install.amd/initrd.gz echo preseed.cfg | cpio -H newc -o -A -F $PATH_SRC/install.amd/initrd gzip $PATH_SRC/install.amd/initrd chmod -w -R $PATH_SRC/install.amd/ #regenerate md5sum cd $PATH_SRC chmod +w md5sum.txt find -follow -type f ! -name md5sum.txt -print0 | xargs -0 md5sum > md5sum.txt chmod -w md5sum.txt #remove startup menu sed -i '/default vesamenu.c32/d' isolinux/isolinux.cfg
debian需要将preseed.cfg写入到install.amd/initrd的文件中,然后在重新给镜像计算md5值。然后通过删除isolinux.cfg里default vesamenu.c32,使镜像启动之后不会被menu的选择影响停住。
生成新的镜像
if [ "$path_dst_iso" = "" ]; then genisoimage -r -J -b isolinux/isolinux.bin -c isolinux/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table \ -o $PATH_DST/preseed-$iso_name $PATH_SRC else genisoimage -r -J -b isolinux/isolinux.bin -c isolinux/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table \ -o $path_dst_iso $PATH_SRC fi
最后就是用genisoimage把解压后以及设置过preseed.cfg的镜像,指定好-o输出位置然后生成新的ISO。
最后
开源社区里其实已经有一些生成自定义镜像的工具了。但是我更喜欢自动动手用官方的方式来生产镜像,并且统一成自己想要的接口,这样可以更好得对工具进行定制化,来满足我自己的需求。