平时我们安装 Linux,经常会使用 U 盘当作安装介质。但是当我们的安装对象从单机变成集群,插 U 盘安装就不太现实了,一台一台在安装界面点点点也显得很蠢了。那么如何快速自动的给集群安装系统?今天我们来介绍一些方法。

我这里是在pve上做实验,通过安装虚拟机来测试。

dnsmasq

dnsmasq 本来是用来做dhcp和dns的,但他还有一个功能,即tftp和dhcp-boot
dhcp-boot 是 dhcp 的一个选项,在使用pxe启动时,会自动加载 dhcp-boot 的文件,而tftp则类似于ftp,为 pxe 启动提供文件。

修改 /etc/dnsmasq.conf 的一些相关配置

interface=vmbr0
dhcp-range=10.10.10.2,10.10.10.200,255.255.255.0,12h
enable-tftp
tftp-root=/var/ftpd
dhcp-boot=/var/ftpd/pxelinux.0,boothost,10.10.10.1

systemctl restart dnsmasq 即可重新加载配置,另外还需要再 /var/ftpd 目录下再开一个 http server,考虑到可能会有多线程的需求,这里建议开个 nginx 而不是 python -m http.server

server {
  listen 8080 default_server;
  listen [::]:8080 default_server;
  root /var/ftpd;
  autoindex = on;
  server_name _;
}

Ubuntu | cloud-init

Cloud-init 是 C社开发出来的替代 debian preseed的自动安装方式。C社近年来写过很多轮子,比如网络配置 netplan, 防火墙 ufw, 自动化配置 cloud-init, 以及容器化应用包管理 snap。但是往往被人诟病,最后只剩C社自己玩。只有cloud-init确实是发扬光大,各大云都在用。至于前面提到的preseed安装,我们后面再提。

配置完前面那些,便可以 cd /var/ftpd/ 开始工作了

curl -LO https://mirror.sjtu.edu.cn/ubuntu-cd/focal/ubuntu-20.04.2-live-server-amd64.iso
mount ubuntu-*.iso /mnt
cp -r /mnt/casper/ .
cp -r /mnt/boot/grub/ .
# 直接从镜像中提取的grub不支持tftp
curl http://archive.ubuntu.com/ubuntu/dists/focal/main/uefi/grub2-amd64/current/grubnetx64.efi.signed -O pxelinux.0
# 修改 grub 
cat > grub/grub.cfg << EOF
timeout=1
timeout_style=menu
menuentry "Install Ubuntu automatic" {
  set gfxpayload=keep
  linux /casper/vmlinuz ip=dhcp url="http://10.10.10.1:8080/ubuntu-20.04.2-live-server-amd64.iso" autoinstall ds="nocloud-net;s=http://10.10.10.1:8080/" root=/dev/ram cloud-config-url=/dev/null
  initrd  /casper/initrd
}
EOF

然后就是准备 cloud-init 相关的文件配置,有三个文件 user-data meta-data vendor-data 只有 user-data 需要配置,其他都可以留空。

关于 user-data 如何写可以参考 autoinstall-referenceautoinstall-schema

一个最简单的配置为

#cloud-init
autoinstall:
  identity:
    username: ubuntu
    password: ...

如何生成这个 password openssl passwd -6 -salt 1234

正常需要还需要配置一些网络,镜像以及分区,所以我最终的配置为

#cloud-config
autoinstall:
  version: 1
  identity:
    hostname: ubuntu
    username: ubuntu
    password: ...
  keyboard:
    layout: us
    variant: ''
  network:
    network:
      version: 2
      ethernets:
        ens18:
          dhcp4: yes
  apt:
    primary:
      - arches: [default]
        uri: http://mirrors.uestc.cn/ubuntu
  storage:
    layout:
      name: lvm
  ssh:
    install-server: true
    authorized_keys:
      - ssh-rsa ...
    allow-pw: true

配置完这些就可以进行安装了,在pve里创建一个 UEFI 启动的虚拟机,等待安装完成即可,整个过程完全不需要人工介入。

需要吐槽的是,ubuntu在选择lvm安装的时候,默认不会把 vg 的所有空间全部分配到 lv,所以在开机之后可能需要 lvextend,不过也可以手动配置 storage 参数。

Debian | preseed

前面说了,cloud-init 是C社的,清蒸的debian自然不会在安装镜像里加入这种东西,debian 自己有一套名为 preseed 的全自动安装方式。

# 工作目录仍然在 /var/ftpd
# 与 ubuntu 不同,debian提供了一个用于网络启动安装的镜像
curl -LO https://deb.debian.org/debian/dists/buster/main/installer-amd64/current/images/netboot/netboot.tar.gz
tar xf netboot.tar.gz
# 自带的pxelinux.0是isolinux,只能用在bios启动上
cp debian-installer/amd64/grubx64.efi pxelinux.0

创建一个 preseed.txt,关于 preseed 的配置可以参考这个 preseed example

d-i debian-installer/locale string en_US
d-i keyboard-configuration/xkb-keymap select us
d-i netcfg/choose_interface select auto
d-i netcfg/hostname string debian
d-i netcfg/domain string
d-i netcfg/wireless_wep string
d-i mirror/country string manual
d-i mirror/http/hostname string mirrors.uestc.cn
d-i mirror/http/directory string /debian
d-i mirror/http/proxy string
d-i passwd/root-login boolean false
d-i passwd/user-fullname string Debian
d-i passwd/username debian
d-i passwd/user-password-crypted password [password hash]
d-i passwd/user-uid string 1010
d-i clock-setup/utc boolean true
d-i time/zone string Asia/Shanghai
d-i clock-setup/ntp boolean true
d-i partman-efi/non_efi_system boolean true
d-i partman-auto/method string lvm
d-i partman-auto-lvm/guided_size string max
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-md/device_remove_md boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite 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
d-i partman-md/confirm boolean true
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
tasksel tasksel/first multiselect standard, ssh-server
d-i pkgsel/upgrade select none
popularity-contest popularity-contest/participate boolean false
d-i grub-installer/only_debian boolean true
d-i grub-installer/bootdev  string default
d-i finish-install/reboot_in_progress note

preseed 和 cloud-init 不同,是没有默认配置的,这个配置基本上就是 minimal 的配置了,再删除就没法自动化安装了,会被中间的一些选项卡住。(注意替换密码)

接着要修改 debian-installer/boot/amd64/grub/grub.cfg

if loadfont $prefix/font.pf2 ; then
  set gfxmode=800x600
  set gfxpayload=keep
  insmod efi_gop
  insmod efi_uga
  insmod video_bochs
  insmod video_cirrus
  insmod gfxterm
  insmod png
  terminal_output gfxterm
fi

if background_image /isolinux/splash.png; then
  set color_normal=light-gray/black
  set color_highlight=white/black
elif background_image /splash.png; then
  set color_normal=light-gray/black
  set color_highlight=white/black
else
  set menu_color_normal=cyan/blue
  set menu_color_highlight=white/blue
fi

insmod play
play 960 440 1 0 4 440 1
menuentry 'Install' {
    set background_color=black
    linux    /debian-installer/amd64/linux vga=788 auto=true url=http://10.10.10.1:8080/preseed.cfg hostname=debian domain=debian.local
    initrd   /debian-installer/amd64/initrd.gz
}

多的我不列了,主要是要修改内核的参数,这里我一定要吐槽的是关于 hostnamedomain 的配置,尽管前面 preseed.cfg 中已经指定了,但是 debian 这个 installer 会在配置 hostnamedomain 之后才去请求 preseed.cfg。所以需要现在内核启动参数中指定。

接下来的过程就是等待安装了。

CentOS | Kickstart

虽然 CentOS 修改了发行方式,💊已经是无需争议的事实。但是考虑到 CentOS 7 要到 2024.06 才 EOL,而国内又喜欢用这个,所以还是看了一下 CentOS 的安装方法。

工作目录依然是 /var/ftpd

curl -LO http://mirrors.uestc.cn/centos/7/isos/x86_64/CentOS-7-x86_64-NetInstall-2009.iso
mount CentOS-7-*.iso /mnt/
cp /mnt/images/pxeboot/{initrd.img, vmlinuz} .
umount /mnt
grub-mknetdir --net-directory=/var/ftpd --subdir=/boot/grub -d /usr/lib/grub/x86_64-efi/
cp boot/grub/x86_64-efi/core.efi pxelinux.0

接着就是修改 boot/grub/grub.cfg

if loadfont $prefix/fonts/unicode.pf2 ; then
  set gfxmode=800x600
  set gfxpayload=keep
  insmod efi_gop
  insmod efi_uga
  insmod video_bochs
  insmod video_cirrus
  insmod gfxterm
  insmod png
  terminal_output gfxterm
fi

insmod play
play 960 440 1 0 4 440 1
menuentry 'Install' {
    set background_color=black
    linux    /vmlinuz ip=dhcp inst.repo=http://mirrors.uestc.cn/centos/7/os/x86_64/ inst.ks=http://10.10.10.1:8888/anaconda.cfg
    initrd   initrd.img
}

这个 anaconda.cfg 怎么写呢?CentOS 给的建议是,先正常安装一个系统,安装之后在 /root/anaconda.cfg 就是这次安装的配置,可以直接拿来用。我这里的配置是

#version=DEVEL
# System authorization information
auth --enableshadow --passalgo=sha512
# Use graphical install
graphical
# Run the Setup Agent on first boot
firstboot --enable
ignoredisk --only-use=sda
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8

# Network information
network  --bootproto=dhcp --device=ens18 --ipv6=auto --activate
network  --hostname=localhost.localdomain

# Use network installation
url --url="http://mirrors.uestc.cn/centos/7/os/x86_64/"
#Root password
rootpw --lock
# System services
services --enabled="chronyd"
# System timezone
timezone Asia/Shanghai --isUtc
user --groups=wheel --name=cent --password=$6$AQn4M.TYbiyXUYsy$vaWynwtwRwtBwraTkLArmwb71RP0hUUoXXsvQpplJDSCA4mVVdKL.qfk79Amc2v7eKQ2q/yCaexjoczFNyCRD0 --iscrypted --gecos="Cent"
# System bootloader configuration
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=sda
autopart --type=lvm
# Partition clearing information
clearpart --none --initlabel

%packages
@^minimal
@core
chrony
kexec-tools

%end

%addon com_redhat_kdump --enable --reserve-mb='auto'

%end

%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end

比起前面两个我试了半天的配置这个还是简单多了

Reference

  1. https://itectec.com/ubuntu/ubuntu-automated-20-04-server-installation-using-pxe-and-live-server-image/
  2. https://ubuntu.com/server/docs/install/autoinstall
  3. https://wiki.debian.org/DebianInstaller/Preseed
  4. https://docs.centos.org/en-US/centos/install-guide/Simple_Installation/