服务器商家提供的系统镜像虽然方便,但是其中总是包含多余的东西,我比较喜欢干净的系统,每次拿到新机器后都会进VNC控制台手动安装系统。但是手动执行系统比较费时费力,一台还好,但是我的服务器很多,一台一台地弄太慢了,把自己整的很烦躁。因此,我决定尝试使用自动化脚本来简化这一过程,提高效率。在服务器管理和运维领域,自动化脚本是节省时间和提高效率的关键。现在正好放寒假,于是我利用空闲的时间深入研究了如何使用preseed.cfg自动化部署Debian系统

脚本已经写好:bash <(curl -sL https://sitao.org/myscripts/installDebian)
可选择的系统:Debian 10, 11, 12
在debain或者ubuntu上运行脚本,一般在十分钟内完成,机器性能好的话可能才五六分钟,期间可以打开vnc控制台查看进度

脚本设计

1.检查权限: 脚本首先检查用户是否以 root 权限运行,以确保能够执行必要的系统操作。

2.选择版本: 脚本提示用户选择要安装的 Debian 版本,并根据用户的选择下载相应的 netboot 文件。

3.设置密码: 用户需要输入 root 用户的密码,以便在安装过程中使用。

4.网络配置: 脚本获取系统的网络接口信息,并自动配置 IP 地址、子网掩码、网关等参数。

5.创建 preseed 文件: 脚本生成 preseed.cfg 文件,其中包含了自动安装过程中的各种配置,如时区、分区方案、软件包选择等。

6.修改 GRUB 配置: 脚本将自动生成的 preseed 文件添加到 GRUB 菜单中,以便系统启动时使用。

7.更新 GRUB 配置并重启: 脚本修改 GRUB 的默认选项和超时时间,并更新配置后重启系统。

实现细节

1.下载 Debian netboot 文件
在自动化部署 Debian 系统的过程中,正确下载所需的 netboot 文件是非常重要的一步。这些文件包含了 Debian 安装程序的核心组件,能够实现从网络启动并自动化安装系统的功能。

使用 wget 命令来下载以下两个文件:
Linux 内核文件 (linux): 这是 Debian 安装程序的内核文件,负责引导系统并加载安装过程所需的模块和驱动程序。
初始化 RAM 磁盘镜像文件 (initrd.gz): 这是一个压缩的初始化 RAM 磁盘镜像文件,包含了安装程序所需的各种工具、驱动程序和配置文件。

2.网络配置: 获取系统的网络接口信息并不是一件简单的任务,通过使用 ip 和 ifconfig 命令来获取相关信息,并进行了一些字符串处理和过滤。

# 获取活动网络接口名称
interface=$(ip -o link show | awk '$2 != "lo:" {print substr($2, 1, length($2)-1); exit}')
# 获取IP地址
ip=$(ifconfig $interface | awk '/inet / {print $2}')
# 获取子网掩码
netmask=$(ifconfig $interface | awk '/netmask / {print $4}')
# 获取网关
gateway=$(ip route | awk '/default/ {print $3}')

3.生成 preseed 文件: preseed.cfg 文件是自动化安装过程中的核心配置文件,我花了不少时间来研究各种配置选项,并根据实际需求进行了调整和优化。
关于如何加载preseed.cfg,有两种方法:
(1)指定url
(2)把preseed.cfg放在 initrd 的根目录里面,安装程序自动检测并加载
我的脚本用的是第二种

两种我都试过,指定url方便,但是不比把preseed.cfg放在 initrd 的根目录里灵活。比如有些商家不提供DHCP服务,指定url的方式似乎就显得无力了,url的preseed文件不能灵活获取机器的静态IP,安装程序执行到配置网络这个环节时就会停下来让我们自己手动配置网络。然而放在initrd里的方法不仅可以通过DHCP配置网络,还可以获取机器的静态IP存到preseed.cfg里,不用我们手动配置,所以我多花了一些时间研究如何把preseed.cfg放在 initrd 的根目录里

preseed.cfg 内容:

d-i debian-installer/locale string en_US
d-i debian-installer/language string en
d-i debian-installer/country string US
d-i keyboard-configuration/xkb-keymap select us
d-i passwd/user-fullname string daiyu lin
d-i passwd/username string daiyu
d-i passwd/root-password password $passwd
d-i passwd/root-password-again password $passwd
d-i passwd/user-password password Iamnotpassword
d-i passwd/user-password-again password Iamnotpassword
d-i user-setup/allow-password-weak boolean true
d-i netcfg/choose_interface select auto
d-i netcfg/dhcp_failed note
d-i netcfg/dhcp_options select Configure network manually
d-i netcfg/get_ipaddress string $ip
d-i netcfg/get_netmask string $netmask
d-i netcfg/get_gateway string $gateway
d-i netcfg/get_nameservers string 8.8.8.8
d-i netcfg/confirm_static boolean true
d-i netcfg/get_hostname string debian
d-i netcfg/get_domain string debian
d-i mirror/country string manual
d-i mirror/http/hostname string deb.debian.org
d-i mirror/http/directory string /debian
d-i mirror/http/proxy string
d-i clock-setup/utc boolean true
d-i clock-setup/ntp boolean true
d-i time/zone string Asia/Shanghai
d-i partman-auto/disk string /dev/[sv]da
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-basicfilesystems/no_swap boolean false
d-i partman-auto/expert_recipe string                       \
200 1 200 ext4 \
        $primary{ } $bootable{ } \
        method{ format } format{ } \
        use_filesystem{ } filesystem{ ext4 } \
        mountpoint{ /boot } \
    . \
201 2 -1 ext4 \
        $primary{ } \
        method{ format } format{ } \
        use_filesystem{ } filesystem{ ext4 } \
        mountpoint{ / } \
    .
d-i partman-md/confirm_nooverwrite boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
tasksel tasksel/first multiselect minimal
d-i pkgsel/include string openssh-server
d-i pkgsel/update-policy select none
d-i pkgsel/upgrade select none
d-i apt-setup/services-select multiselect
d-i grub-installer/grub2_instead_of_grub_legacy boolean true
d-i grub-installer/only_debian boolean true
d-i grub-installer/bootdev string /dev/[sv]da
d-i preseed/late_command string \
chroot /target sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config;
d-i finish-install/reboot_in_progress note

4.添加自定义的 GRUB 菜单项

cat << EOF >> /etc/grub.d/40_custom
menuentry "Daiyu Debian Installer AMD64" {
    set root="(hd0,$partitionr_root_number)"
    linux /netboot/linux auto=true priority=critical lowmem/low=true preseed/file=/preseed.cfg
    initrd /netboot/initrd.gz
}
EOF

期间阅读的官方文档:
https://wiki.debian.org/DebianInstaller/Preseed
https://www.debian.org/releases/stable/i386/apb.zh-cn.html