批量重装 Ubuntu 18.04


概述

Ubuntu Server 18.04.5 系统安装使用 debian-installer,兼容 Kickstart 但不够灵活,比如从 5 块 NVMe 硬盘中找到容量最小的盘安装系统这种操作就很难做到。自家的脚本是 Preseed,功能非常强大,能完成一些图形安装界面届不到的操作(缺点是有一点点复杂)。

CentOS 篇中,PXE Server 需要安装 DHCP/TFTP/Nginx 等众多软件。这次改用 Dnsmasq 同时提供 DHCP 和 TFTP 服务。也省去 Nginx,直接从软件源安装系统。

安装软件

下载 Ubuntu 镜像,文中使用的是 ubuntu-18.04.5-server-amdyes.iso

安装 dnsmasq 服务。

sudo apt updatesudo apt install dnsmasq

配置 dnsmasq,开启 DHCP 和 TFTP 功能。

mkdir -p /srv/tftp/vim /etc/dnsmasq.conf

内容如下。

interface=eth0bind-interfacesdhcp-range=172.16.199.1,172.16.199.254dhcp-boot=grubnetx64.efi.signeddhcp-host=172.16.199.1enable-tftptftp-root=/srv/tftp/

其中,interface 是当前使用的网络接口,dhcp-boot 是 grub 引导程序的位置,dhcp-host 是 DHCP Server 网关 IP(可用来可访问本机器),tftp-root 则是 TFTP Server 的根目录。

启动 dnsmasq 服务。

sudo systemctl start dnsmasq

配置 PXE Server

Boot loader

UEFI 启动需要一个 boot loader(文中是 GRUB)。从软件源下载,然后丢进 TFTP 根目录。

sudo apt-get install grub-efi-amd64-signedsudo cp /usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed /srv/tftp/grubnetx64.efi.signed

grubnetx64.efi.signed 这个名字就是在 /etc/dnsmasq.conf 的 dhcp-boot 字段中定义的那个。

GRUB

配置 GRUB,其实就是 Ubuntu 那个选择系统的启动菜单,添加一个启动项,把系统位置从硬盘改为网络。

mkdir -p /srv/tftp/grubvim /srv/tftp/grub/grub.cfg

内容如下。

set default="0"
set timeout=6
menuentry "Install Ubuntu" {
  set gfxpayload=keep
  linux /ubuntu/linux gfxpayload=800x600x16,800x600 --- auto=true priority=critical interface=auto hostname=fox GRUB_DISABLE_OS_PROBER=true url=tftp://172.16.1.1/preseed.cfg quiet
  initrd /ubuntu/initrd.gz
}
...

由于 Ubuntu 18.04 的 os-prober 操作 LVM 分区时会触发 BUG,所以加了个环境变量 GRUB_DISABLE_OS_PROBER=true 禁用 os-prober。其他配置项说明参考 CentOS 篇。

网络引导

这里下载 Ubuntu 的网络引导镜像,解压到 TFTP 目录下。

mkdir -p /srv/tftp/ubuntuwget http://archive.ubuntu.com/ubuntu/dists/bionic-updates/main/installer-amd64/current/images/netboot/netboot.tar.gztar -xvzf netboot.tar.gz -C /srv/tftp/ubuntu

软件包缓存

Ubuntu 安装程序支持 APT 安装软件包,默认是从官方软件源下载。但如果批量安装,外网怕是会炸,所以要在内网(PXE Server)搭建软件包缓存服务。

sudo apt-get install apt-cacher-ng

安装完成后,在 Preseed 脚本中配置源代理 d-i mirror/http/proxy string http://<YOUR_IP>:3142/ 指向该机器。

Preseed

Preseed 脚本可配置项非常多,详细可参见官方文档。下面简单举几个🌰,可根据自身需求修改。

  • 相同的部分

系统盘使用 LVM 方式分区,除了 /boot,/boot/efi 分区外,其余空间全给根目录,禁用 SWAP 分区。启用 ROOT 用户,允许 ROOT 用户远程登录,安装 openssh-server openssh-client vim curl 软件。

  • 系统盘名字固定,比如单块 SATA 系统盘默认设备名是 /dev/sda,单块 NVMe SSD 是 /dev/nvme0n1,这样系统盘可以写死在配置中。
### Unattended Installationd-i auto-install/enable boolean trued-i debconf/priority select critical### Localizationd-i debian-installer/locale string en_US.UTF-8d-i localechooser/languagelist select end-i localechooser/shortlist/en select USd-i localechooser/continentlist select Asiad-i localechooser/countrylist/Asia select Chinad-i console-setup/ask_detect boolean falsed-i keyboard-configuration/xkb-keymap select us### Account setupd-i passwd/root-login boolean trued-i passwd/make-user boolean falsed-i passwd/root-password password ABC123defd-i passwd/root-password-again password ABC123defd-i user-setup/allow-password-weak boolean true### Network configurationd-i netcfg/choose_interface select autod-i netcfg/get_hostname string catd-i hw-detect/load_firmware boolean true# If you want the preconfiguration file to work on systems both with and# without a dhcp server, uncomment these lines and the static network# configuration below.d-i netcfg/dhcp_failed noted-i netcfg/dhcp_options select Configure network manually# Static network configuration.d-i netcfg/get_ipaddress string 172.16.1.207d-i netcfg/get_netmask string 255.255.0.0d-i netcfg/get_gateway string 172.16.255.254d-i netcfg/get_nameservers string 223.5.5.5d-i netcfg/confirm_static boolean true### Partition# Specify a disk to partition. The device name# can be given in either devfs or traditional non-devfs format.d-i partman-auto/disk string /dev/nvme0n1d-i grub-installer/bootdev string /dev/nvme0n1# In addition, you'll need to specify the method to use.# The presently available methods are: "regular", "lvm" and "crypto"d-i partman-auto/method string lvm# If one of the disks that are going to be automatically partitioned# contains an old LVM configuration, the user will normally receive a# warning. This can be preseeded away...d-i partman-auto/purge_lvm_from_device boolean true# http://cptyesterday.wordpress.com/2012/06/17/notes-on-using-expert_recipe-in-debianubuntu-preseed-files/d-i partman-auto/choose_recipe select boot-rootd-i partman-auto-lvm/new_vg_name string maind-i partman-auto-lvm/guided_size string maxd-i partman-auto/expert_recipe string                \    boot-root ::                                     \        1 1 1 free                                   \            $bios_boot{ }                            \            method{ biosgrub }                       \        .                                            \        256 256 256 fat32                            \            $primary{ }                              \            $iflabel{ gpt }                          \            $reusemethod{ }                          \            method{ efi } format{ }                  \            mountpoint{ /boot/efi }                  \        .                                            \        512 512 512 ext4                             \            $primary{ }                              \            $bootable{ }                             \            method{ format } format{ }               \            use_filesystem{ } filesystem{ ext4 }     \            mountpoint{ /boot }                      \        .                                            \        4096 4096 -1 ext4                            \            $lvmok{ }                                \            method{ format } format{ }               \            use_filesystem{ } filesystem{ ext4 }     \            mountpoint{ / }                          \            lv_name{ root }                          \        .# Write the changes to disks and configure LVMd-i partman/confirm boolean trued-i partman-lvm/confirm boolean trued-i partman-lvm/confirm_nooverwrite boolean true# http://ubuntuforums.org/showthread.php?p=9626883d-i partman-lvm/device_remove_lvm boolean true# This makes partman automatically partition without confirmation.d-i partman/choose_partition \      select Finish partitioning and write changes to diskd-i partman/confirm_nooverwrite boolean trued-i pkgsel/include string openssh-server openssh-client vim curl### Mirror settingsd-i mirror/country string manuald-i mirror/http/hostname string mirrors.ustc.edu.cnd-i mirror/http/directory string /ubuntud-i mirror/http/proxy string http://172.16.1.1:3142/# Custom commandsd-i preseed/late_command string \    in-target sh -c 'sed -i "/#PermitRootLogin/a PermitRootLogin yes" /etc/ssh/sshd_config';finish-install finish-install/keep-consoles boolean falsed-i finish-install/reboot_in_progress note
  • 机器安装多块硬盘,比如有 5 块 NVMe SSD,256GBx1 & 2TBx4,系统装在 256GB 的硬盘上。

基于上面的脚本,在 early_command 中使用 Bash 脚本,通过 debconf-set 来动态指定硬盘位置。

# 删除下面两个配置d-i partman-auto/disk string /dev/nvme0n1d-i grub-installer/bootdev string /dev/nvme0n1# 用这个脚本找出小于 300GB 的硬盘,指定为系统盘d-i partman/early_command string \  for BOOTDEV in nvme0n1 nvme1n1 nvme2n1 nvme3n1 nvme4n1; do \    if [ -d /sys/block/$BOOTDEV ]; then \      SIZE=`cat /sys/block/$BOOTDEV/size`; \      GB=$(($SIZE/2**21)); \      if [ $GB -lt 300 ]; then \        debconf-set partman-auto/disk "/dev/$BOOTDEV"; \        debconf-set grub-installer/bootdev "/dev/$BOOTDEV"; \      fi; \    fi; \  done
  • 机器本来有系统,需要批量重装,原系统也是 LVM 方式分区。

先移除已存在的 LVM 分区,再尝试安装(虽然有相关配置项,但该版本可能存在 BUG)。

# 移除 LVM 分区d-i partman-lvm/device_remove_lvm boolean trued-i partman-auto/purge_lvm_from_device boolean true# 上述配置项可能存在 BUG,那就亲自删一遍d-i partman/early_command string \    set -- $(vgs --rows --noheadings | head -n 1); \    for vg in "$@"; do \        swapoff "/dev/$vg/swap"; \        vgremove -f "$vg"; \    done; \    set -- $(pvs --rows --noheadings | head -n 1); \    for pv in "$@"; do \        pvremove -f "$pv"; \    done

Preseed 文件放到 TFTP 根目录 /srv/tftp/ 下,也就是 GRUB 菜单配置里 url 指定的那个。

PXE 引导

确保内网中没有其他 DHCP 服务,将机器接在 PXE Server 同一个交换机下。重启机器,启动时选择从 PXE 引导,观察是否获得 IP,能否下载启动文件。正常的话稍后就能看到 Ubuntu 安装界面。

参考