搭建基于 Ubuntu Server 的 PXE 自动安装环境的实用指南

Linux系统
438
0
0
2022-04-18

Ubuntu 在不断进化,从 20.04 开始,Ubuntu 决定更新实时服务器安装程序,只用 Subiquity 就能完全完成操作系统及附加程序的自动安装。以前用的 kickstart、debian-installer 都不是 Ubuntu 自家技术,用起来也不是很方便。

同时,PXE 技术虽然出来很久了,但是整个安装过程还不是特别顺畅,随着 Ubuntu 升级到 20.04,使用 cloud-init 安装配置实现 Subiquity 参数的自动填写,整个过程变得些微优雅起来,让我有较大兴趣尝试使用 PXE 安装 Ubuntu 20.04 Server。

本文,我想讲的是在 Ubuntu 20.04 Server 上搭建一套自动安装 Ubuntu 20.04 Server 的部署环境,其主要内容有两部分:

  1. 使用 PXE 自动从网络加载安装程序,发起安装。
  2. 使用 Ubuntu 的自动安装功能,自动加载 cloud-init 安装配置,完成操作系统的自动选择。

第一部分所有操作系统应该都是一样的,第二部分和 Ubuntu 20.04 版本紧密相关,其他的操作系统需要考虑其他方法。

PXE 安装流程

PXE(预启动执行环境

Pre-boot Execution Environment

)的实现依赖于网卡,只有支持 PXE 客户端的网卡才能实现网络自动安装。这种网卡实现了 DHCP 客户端和 TFTP 客户端,在 BIOS 的引导下通过 DHCP 协议自动分配 IP 地址,通过 TFTP 获取最小内核,然后在最小内核环境下通过 HTTP 协议或 NFS 协议获取 Ubuntu 安装版本。之后最小内核引导进行 Ubuntu 20.04 的安装。

下图是详细的安装流程。

上图有几个前提:

  1. 网卡支持 PXE,今年新出的网卡基本都支持,同时 BIOS 的启动项也要配置,请大家自行研究。
  2. UEFI 启动才会请求 bootx64.efi,如果是传统启动模式
  3. Legacy
  4. ),那么 PXE 客户端会请求 pxelinux.0
  5. 可以采用 nfsboot 方式,这个流程采用的是 ISO 镜像下载再安装的方式。

安装必须的服务端软件

  1. 安装 DHCP、TFTP 服务器。dnsmasq 同时实现了 DHCP、TFTP、DNS 三种服务器
  2. sudo apt-get install dnsmasq
  3. 安装 HTTP 服务器
  4. HTTP 服务器有很多,大家可以使用自己的熟悉的服务器如 Nginx,这里使用的是apache2
  5. sudo apt-get install apache2

准备启动文件

下载 UEFI 引导文件:shim.signed、grub-efi-amd64-signedapt-get download shim.signed
apt-get download grub-efi-amd64-signed
  1. 下载 Ubuntu 20.04 Server ISO 镜像
  2. 直接去官网下载,我下载的是 ubuntu-20.04.2-live-server-amd64.iso,需要注意的是只有 Live 版本才能支持 subiquity。

创建 TFTP 文件夹

TFTP 文件夹是 TFTP 服务的根目录,PXE 启动过程中下载的文件都存在在该目录中:

tftp
├── boot
│   └── live-server
│       ├── initrd
│       └── vmlinuz
├── grub
│   ├── bootx64.efi
│   ├── font.pf2
│   └── grub.cfg
└── grubx64.efi

说明:

  1. bootx64.efigrubx64.efi 引导程序来自 shim.signed 安装包
  2. grub.cfg 自行创建
  3. 其他文件来自 Ubuntu 安装包
  4. 这五个文件是需要的,但是目录结构是自行创建的,大家可以根据自己的喜好修改

创建目录

在 /home/mine(可根据实际情况修改)目录下创建 tftp 目录:

mkdir /home/mine/tftp
mkdir /home/mine/tftp/grub
mkdir /home/mine/tftp/boot
mkdir /home/mine/tftp/boot/live-server

获取引导文件

  1. 在安装包下载目录创建一个 shim 文件夹
  2. 解压 shim 安装包到 shim文件夹:dpkg -x <%刚才下载的shim.signed 安装包包名%> shim
  3. 解压 grub 安装包到 grub 文件夹
  4. 拷贝引导文件到 tftp目录
cp ./sgrub/usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed  /home/mine/tftp/grubx64.efi
cp ./shim/usr/lib/shim/shimx64.efi.signed  /home/mine/tftp/grub/bootx64.efi

获取内核镜像文件

  1. 在下载目录挂载 ISO 文件
sudo mount ubuntu-20.04.2.0-desktop-amd64.iso /media
  1. 系统会提示只读,不影响使用。
mount: /media: WARNING: device write-protected, mounted read-only.
  1. 拷贝内核镜像文件
cp /media/casper/initrd       /home/mine/tftp/boot/live-server
cp /media/casper/vmlinuz      /home/mine/tftp/boot/live-server
  1. 拷贝 grub 文件
  2. grub.cfg 拷贝过来做个参考,内容会被全部修改掉。
cp /media/grub/font.pf2       /home/mine/tftp/grub
cp /media/grub/grub.cfg       /home/mine/tftp/grub

配置 dnsmasq

关键配置有以下几个:

  1. 配置 DHCP 地址段
  2. 配置引导文件目录
  3. 配置 tftp 根目录
  4. 配置日志路径
  5. 配置服务网卡,多网卡机器需关注
# 配置外网 DNS 服务器地址
server=114.114.114.144

# 指定服务的网卡
interface=enp2s0,lo

# 绑定端口
bind-interfaces

# 设置 DHCP 分发 IP 端范围、地址掩码、IP 地址有效时间
dhcp-range=192.168.1.100,192.168.1.150,255.255.255.0,12h

# 指定网关地址
# 和安装无关,应该可以不配置
dhcp-option=3,192.168.1.9

# 指定 DNS 服务器地址
# 和安装无关,应该可以不配置
dhcp-option=6,114.114.114.114

# 设置引导程序相对 tftp 根目录的路径
dhcp-match=set:efi-x86_64,option:client-arch,7
dhcp-boot=tag:efi-x86_64,grub/bootx64.efi

# 启用 tftp 服务
enable-tftp

# 设置 tftp 根路径
tftp-root=/home/mine/tftp

# 设置日志路径
log-facility=/var/log/dnsmasq.log

修改配置后,重启 dnsmasq 服务才能生效。

创建 HTTP 文件夹

Apache2 的默认服务根目录是 /var/www/html,在其下创建目录:

html/
├── autoinstall
│   ├── meta-data
│   └── user-data
├── index.html
└── iso
    └── ubuntu-20.04.2-live-server-amd64.iso

说明:

  1. autoinstall 目录存放参数自动配置文件,user-datameta-data 是cloud-init 要求的文件名
  2. iso 目录存放操作系统镜像文件

创建目录

mkdir /var/www/html/autoinstall
mkdir /var/www/html/iso

拷贝 ISO 文件

到下载目录拷贝 ISO 文件:

cp  ubuntu-20.04.2-live-server-amd64.iso /var/www/html/iso

创建参数自动配置文件

先创建空文件,meta-data 无需修改,user-data 后续会详细描述配置。

touch /var/www/html/autoinstall/user-data
touch /var/www/html/autoinstall/meta-data

配置 grub.cfg

if loadfont /grub/font.pf2 ; then 
        set gfxmode=auto
        insmod efi_gop
        insmod efi_uga
        insmod gfxterm
        terminal_output gfxterm
fi

set menu_color_normal=white/black
set menu_color_highlight=black/light-gray
set timeout=5

menuentry "Ubuntu server 20.04 autoinstall" {
        set gfxpayload=keep
        linux  /boot/live-server/vmlinuz root=/dev/ram0 ramdisk_size=1500000 ip=dhcp url='http://192.168.1.9/iso/ubuntu-20.04.2-live-server-amd64.iso' autoinstall ds=nocloud-net\;s=http://192.168.1.9/autoins
tall/ ---
        initrd /boot/live-server/initrd
}

menuentry 之前是配置样式,也可以删除,重点关注 menuentry "Ubuntu server 20.04 autoinstall" 内的配置:

  1. 指定镜像文件相对于 tftp 根目录的路径 /boot/live-server/initrd
  2. root=/dev/ram0 ramdisk_size=1500000 为了指定内核镜像挂载空间,是否可删除我不确定
  3. ip=dhcp 指定内核镜像挂载后使用 DHCP 获取 IP 地址
  4. url= 指定 ISO 文件的网络存放路径
  5. autoinstall ds=nocloud-net\;s=http://192.168.1.9/autoinstall/ --- 该配置指明参数自动填写,并指明配置文件所在路径

网上很多文章配置是这么写的 ds=nocloud-net;s=http://192.168.1.9/autoinstall/,我试了很多次,都没有自动安装。

在网上查到,由于 UEFI 启动使用了 grub,它将 ; 识别为了特殊字符,所以要在 ;前加 \ 转义。

配置 user-data

#cloud-config
autoinstall: 
  version: 1 
  # 修改apt 服务地址 
  apt: 
    primary: 
    - arches: [default]
      uri: https://mirrors.tuna.tsinghua.edu.cn/ubuntu 
  user-data: 
    # 配置时区 
    timezone: Asia/Shanghai 
    # 去使能 root账号 
    disable_root: true 
  # 配置用户   
  identity: 
    hostname: ubuntu-server 
    password: "yours" 
    username: ubuntu 
  # 配置键盘   
  keyboard: {layout: us, variant: ''}
  locale: en_US.UTF-8 
  # 配置代理 
  proxy: http://192.168.1.112:3128 
  # 默认安装ssh server 
  ssh: 
    install-server: true 
  # 指定安装的包 
  packages: 
    - net-tools 
    - python3-pip 
  # 配置磁盘分区 
  storage: 
    grub: 
      reorder_uefi: False 
    config: 
    - {ptable: gpt, path: /dev/sda, wipe: superblock-recursive, preserve: false, name: '',
      grub_device: false, type: disk, id: disk-sda}
    - {device: disk-sda, size: 536870912, wipe: superblock, flag: boot, number: 1,
      preserve: false, grub_device: true, type: partition, id: partition-0}
    - {fstype: fat32, volume: partition-0, preserve: false, type: format, id: format-0}
    - {device: disk-sda, size: -1, wipe: superblock, flag: '', number: 2,
      preserve: false, type: partition, id: partition-1}
    - {fstype: ext4, volume: partition-1, preserve: false, type: format, id: format-1}
    - {device: format-1, path: /, type: mount, id: mount-1}
    - {device: format-0, path: /boot/efi, type: mount, id: mount-0}

说明:

  1. 密码需要加密,可以先用工具对自己的密码进行加密后填入
  2. 代理不是必须的配置,与网络拓扑有关
  3. 磁盘分区配置要注意,配置不对会导致自动安装走不下去,提示 crash;这个配置的整体思路是先格式化 disk-sda,然后在 disk-sda 下划分 /dev/sda1/dev/sda2 ,然后分别挂载 //boot/efi 目录
  4. 安装过程日志在 /var/log/installer/,如果安装失败可以通过 nc 等工具实时发出去

网络拓扑

  1. 我在电脑上搭建了 DHCP、TFTP、HTTP 三种服务
  2. 我在代理机上搭建了 squid,作为 HTTP 代理
  3. 目标机器不能上网,三台机器在同一个局域网

配置静态 IP

在服务机开始服务前,需要在提供服务的网卡上配置静态 IP,Ubuntu 20.04 配置 netplan 即可,参考以下配置修改文件 /etc/netplan/00-installer-config.yaml,修改完成后执行 netplan apply 配置即可生效。

# This is the network config written by 'subiquity'
network: 
  ethernets: 
    enp2s0: 
      addresses: 
      - 192.168.1.9/24 
      gateway4: 192.168.1.1 
      nameservers: 
        addresses: 
        - 114.114.114.114 
        search: 
        - 114.114.114.114

鸣谢

  1. 文章的基石来自 Grffion,没有这篇文章我会摸索更长时间
  2. 这篇 askubuntu 的讨论 解决了坑
  3. user-data 磁盘分区配置来自 小崔

本文作者梦见山,授权转载。题图来源网络。