PXE 技术:基于 Ubuntu Server 的 PXE 自动装机环境的搭建说明

3,776 阅读6分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

基于 Ubuntu Server 的 PXE 自动装机环境的搭建说明

文档说明

本文档,将介绍通过在 Ubuntu 18.04.5 Server 系统上,搭建一套 PXE 自动装机环境(基于DHCP + TFTP + Subiquity),用于批量安装 Ubuntu 20.04.4 Live Server 系统。

基本信息

  • PXE Server
    • 系统:Ubuntu 18.04.5
    • IP地址:10.0.0.4
    • 网络:仅环境部署时需要公网访问
    • 硬件配置:常规即可,无特殊需求,根据装机数量适当调整
  • Node
    • 系统:无操作系统(自行准备 Ubuntu 20.04.4 live server 镜像)
    • IP地址:根据 PXE Server DHCP 动态分配
    • 网络:需要跟 PXE Server 在同一交换机下
    • 硬件配置:内存需 >= 6G(用于加载系统镜像文件)
    • 引导方式:UEFI(引导方式默认不是 UEFI 的主板,需在 BIOS 中设置 Boot 的模式为 UEFI ,禁用 security boot,并且允许从网络启动)

手动部署环境

1. 系统准备

测试环境

  • 在 VMWare 中创建一个系统为 Ubuntu 18.04.5 的虚机,并添加两块网卡:
    • 一块为 VMnet1,模式 NAT,用于访问公网下载依赖包
    • 一块为 VMnet2,模式仅主机,并在虚拟网络编辑器中,将网卡对应子网地址设置为 10.0.0.0,掩码 255.255.255.0,用于模拟二层交换机。
  • 虚机系统装好后,配置 PXE Server 的静态IP
root@server:/etc/netplan# cat 02-netcfg.yaml 
# This file describes the network interfaces available on your system
# For more information, see netplan(5).
network:
  version: 2
  renderer: networkd
  ethernets:
    ens34:
      addresses: [10.0.0.4/24]
      gateway4: 10.0.0.1
	  
root@server:/etc/netplan# netplan apply

# 双网卡模式,为避免虚机 NAT 访问公网失败,需要手动清理下新网卡的默认路由
root@server:/etc/netplan# ip route del default via 10.0.0.1 

生产环境

  • 可以考虑通过以下两种方式进行操作:
    1. 现场找一台物理服务器上手动安装(IPMI or U盘启动) Ubuntu 18.04.5 Server 系统来部署 PXE Server,部署环境时需要能访问公网,部署完成后可再接入内网进行批量安装。
    2. 提前在自己的 esxi 虚机上部署 PXE Server 并打包成镜像,现场找一台物理服务器上安装 esxi 虚拟化,并将 PXE Server 镜像导入使用(待验证)

系统准备好之后,想要通过脚本快速部署 PXE Server 环境,请查看自动部署环境这一步。若想了解详细的安装过程,则继续往下看。

2. 软件安装

需要通过 apt-get 安装以下软件包:

root@server:~# apt-get -y install tftpd-hpa apache2 isc-dhcp-server whois
  • tftpd-hpa :用来给 Node 提供引导及驱动文件
  • apache2 :用来给 Node 提供镜像、应答文件以及一些自定义的文件脚本等
  • isc-dhcp-server:用来给 Node 分配可用的IP地址

3. 配置 tftp server (apache)

配置 tftp 配置,启动 apache 服务:

root@server:~# cat > /etc/apache2/conf-available/tftp.conf <<EOF
<Directory /var/lib/tftpboot>
	Options +FollowSymLinks +Indexes
	Require all granted 
</Directory>
Alias /tftp /var/lib/tftpboot
EOF 

root@server:~# a2enconf tftp 
root@server:~# systemctl restart apache2

目录:/var/lib/tftpboot/作为 tftp 的主要上传目录

4. 镜像及引导文件准备

Ubuntu 20.04.4 Live Server 系统镜像上传或下载到 /var/lib/tftpboot/目录

root@server:~# wget https://old-releases.ubuntu.com/releases/focal/ubuntu-20.04.4-live-server-amd64.iso -O /var/lib/tftpboot/ubuntu-20.04.4-live-server-amd64.iso

准备内核文件、虚拟文件系统:

root@server:~# mount /var/lib/tftpboot/ubuntu-20.04.4-live-server-amd64.iso /mnt/ 
root@server:~# cp /mnt/casper/vmlinuz /var/lib/tftpboot/ 
root@server:~# cp /mnt/casper/initrd /var/lib/tftpboot/ 
root@server:~# umount /mnt

准备网络引导程序(Grub2)

root@server:~# wget http://archive.ubuntu.com/ubuntu/dists/focal/main/uefi/grub2-amd64/current/grubnetx64.efi.signed -O /var/lib/tftpboot/grubx64.efi

准备 Grub 配置

root@server:~# mkdir -p /var/lib/tftpboot/grub 
root@server:~# cat > /var/lib/tftpboot/grub/grub.cfg <<EOF 
default=autoinstall 
timeout=0 
timeout_style=menu 
menuentry "Focal Live Installer - automated" --id=autoinstall { 
	echo "Loading Kernel..." 
	linux /vmlinuz ip=dhcp url=http://10.0.0.4/tftp/ubuntu-20.04.4-live-server-amd64.iso autoinstall ds=nocloud-net\;s=http://10.0.0.4/tftp/ 
	echo "Loading Ram Disk..." 
	initrd /initrd 
} 
menuentry "Focal Live Installer" --id=install { 
	echo "Loading Kernel..." 
	linux /vmlinuz ip=dhcp url=http://10.0.0.4/tftp/ubuntu-20.04.4-live-server-amd64.iso 
	echo "Loading Ram Disk..." 
	initrd /initrd 
} 
EOF

5. 配置 DHCP

配置 DHCP 的地址池,可根据内网情况对应修改(注意生产环境下的网络隔离,避免误重装):

root@server:~# cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf.bak 
root@server:~# cat > /etc/dhcp/dhcpd.conf <<EOF 
ddns-update-style none; 
subnet 10.0.0.0 netmask 255.255.255.0 { 
	option routers 				10.0.0.1; 				
	option domain-name-servers 	114.114.114.114; 
	option subnet-mask 			255.255.255.0; 
	range dynamic-bootp 		10.0.0.200 10.0.0.220; 	# Node 地址池
	default-lease-time 			21600; 
	max-lease-time 				43200; 
	next-server 				10.0.0.4; 				# pxe server IP
	filename 					"grubx64.efi"; 			# 网络引导程序
} 
EOF 

root@server:~# systemctl restart isc-dhcp-server

6. 准备自动应答文件 (cloud.init config)

准备meta-data文件:

root@server:~# cat > /var/lib/tftpboot/meta-data <<EOF 
instance-id: autoinstall 
EOF

准备user-data文件:

root@server:/var/lib/tftpboot# cat > user-data <<'EOF'
#cloud-config
autoinstall:
  version: 1
  apt:
    primary:
    - arches: [default]
      uri: http://mirrors.aliyun.com/ubuntu
  # The passwords are all 000000
  user-data:
    timezone: Asia/Shanghai
    disable_root: false
    chpasswd:
      list: |
        root:$6$UenIfx4J$MXuFvAbjNjwotUl6CtEtwC.1SnlPqMkBd7oHg02XZ1iNk97eMglUrRO1hQUVvOZEf3M/aEhgyrQ/gTDx4fizz/
  identity:
    hostname: node
    password: $6$m/xrHiECoB3upm$qVLuNKyH67prn/uOKlM9soMSIugK.Bzy8jU.TpYDQhLRDvTQtn1ga6Hv0musEMbIUZNV1AmIwM6r/59ZfRA8X0
    username: test
  keyboard: {layout: us, variant: ''}
  locale: en_US.UTF-8
  ssh:
    install-server: true

  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}

  late-commands:
  - curtin in-target --target=/target -- wget -P /root/ http://10.0.0.4/tftp/bash/init.sh
  - curtin in-target --target=/target -- wget -P /root/ http://10.0.0.4/tftp/bash/network.sh
  - curtin in-target --target=/target -- bash /root/init.sh
EOF
  • user-data 文件是进行系统自动安装的应答文件,如果对系统安装有特殊需求,可以对此文件进行修改。当某些需求不知道如何修改配置时,可以先手动安装一次 ubuntu 20.04.4,在 /var/log/installer/ 目录下会生成一个 autoinstall-user-data,在根据手动安装的系统配置进行修改。
  • 也可以参考官方文档资料:ubuntu.com/server/docs…

6. 准备初始化脚本

我们还可以通过脚本,对安装好的系统进行初始化操作,下面是两个网络上找到的脚本,可以根据实际情况进行修改使用:

  • init.sh:用于在系统成功重启之前,在安装成功并安装了所有更新和软件包之后运行的初始化脚本。
  • network.sh:用于快速修改网络配置。在装好的系统上执行此脚本,输入IP,即可将动态地址换成静态地址。
root@server:~# mkdir /var/lib/tftpboot/bash
root@server:~# cd /var/lib/tftpboot/bash/
root@server:/var/lib/tftpboot/bash# vim init.sh
root@server:/var/lib/tftpboot/bash# vim network.sh

init.sh:

#!/bin/bash
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
systemctl restart sshd
systemctl stop ufw.service
systemctl disable ufw.service
echo -e "NTP=ntp1.aliyun.com\nFallbackNTP=ntp.ubuntu.com" >> /etc/systemd/timesyncd.conf
systemctl restart systemd-timesyncd
cat >> /etc/security/limits.conf << EOF
*       soft        nofile  655350
*       hard        nofile  655350
*       soft        nproc   655350
*       hard        nproc   655350
root        soft        nofile  655350
root        hard        nofile  655350
root        soft        nproc   655350
root        hard        nproc   655350
EOF
rm -rf /root/init.sh

network.sh

#!/bin/bash
cd /etc/netplan
cp *.yaml network.yaml.bak
read -p "please ip address: " IP
Gateway=`echo $IP | awk -F '.' '{print $1"."$2"."$3".2"}'`
sed -i 's#critical: true#addresses: ['${IP}'/24]#' *.yaml
sed -i '/dhcp-identifier: mac/d' *.yaml
sed -i '0,/dhcp4: true/{s/dhcp4: true/gateway4: '${Gateway}'/}' *.yaml 
netplan apply
cd

自动部署环境

1. 创建 autoinstall 目录

root@server:~# mkdir autoinstall

2. 上传系统镜像

Ubuntu 20.04.4 Live Server 系统镜像上传或下载到 /root/autoinstall目录

root@server:~# wget https://old-releases.ubuntu.com/releases/focal/ubuntu-20.04.4-live-server-amd64.iso -O /root/autoinstall/ubuntu-20.04.4-live-server-amd64.iso

生产环境,可以提前下载好镜像,然后通过挂载 U盘的方式上传到 autoinstall 目录(安装脚本上传同此方法)。

Ubuntu 系统识别 exFat 格式 U盘 的方法:

  • apt-get install exfat-fuse exfat-utils
  • mount /dev/sdb1 /mnt

3. 准备自动安装脚本

将 autoinstall.sh、init.sh、network.sh 三个脚本,根据实际情况修改,并上传到 /root/autoinstall目录。

  • autoinstall.sh:
#!/bin/bash

# pxe server IP 相关
pxe_default_server='10.0.0.4'

# root 密码和普通用户 test 密码
root_passwd=`mkpasswd -m sha-512 '123456'`
test_passwd=`mkpasswd -m sha-512 '123456'`

# dhcp 相关
dhcp_subnet_ip='10.0.0.0'
dhcp_pxe_gateway='10.0.0.1'
dhcp_subnet_mask='255.255.255.0'
dhcp_ip_range='10.0.0.200 10.0.0.220'

# Install pkg
apt-get -y install tftpd-hpa apache2 isc-dhcp-server whois

# tftp
cat > /etc/apache2/conf-available/tftp.conf <<EOF
<Directory /var/lib/tftpboot>
        Options +FollowSymLinks +Indexes
        Require all granted
</Directory>
Alias /tftp /var/lib/tftpboot
EOF
a2enconf tftp
systemctl restart apache2

cp ubuntu-20.04.4-live-server-amd64.iso /var/lib/tftpboot/
mount /var/lib/tftpboot/ubuntu-20.04.4-live-server-amd64.iso /mnt/
cp /mnt/casper/vmlinuz /var/lib/tftpboot/
cp /mnt/casper/initrd /var/lib/tftpboot/
umount  /mnt

wget http://archive.ubuntu.com/ubuntu/dists/focal/main/uefi/grub2-amd64/current/grubnetx64.efi.signed -O /var/lib/tftpboot/grubx64.efi

mkdir /var/lib/tftpboot/bash
cp init.sh /var/lib/tftpboot/bash
cp network.sh /var/lib/tftpboot/bash


mkdir -p /var/lib/tftpboot/grub
cat > /var/lib/tftpboot/grub/grub.cfg <<'EOF'
default=autoinstall
timeout=0
timeout_style=menu
menuentry "Focal Live Installer - automated" --id=autoinstall {
    echo "Loading Kernel..."
    linux /vmlinuz ip=dhcp url=http://${pxe_default_server}/tftp/ubuntu-20.04.4-live-server-amd64.iso autoinstall ds=nocloud-net\;s=http://${pxe_default_server}/tftp/
    echo "Loading Ram Disk..."
    initrd /initrd
}
menuentry "Focal Live Installer" --id=install {
    echo "Loading Kernel..."
    linux /vmlinuz ip=dhcp url=http://${pxe_default_server}/tftp/ubuntu-20.04.4-live-server-amd64.iso
    echo "Loading Ram Disk..."
    initrd /initrd
}
EOF
sed -i 's#${pxe_default_server}#'${pxe_default_server}'#g' /var/lib/tftpboot/grub/grub.cfg

cat > /var/lib/tftpboot/meta-data <<EOF
instance-id: focal-autoinstall
EOF

cat > /var/lib/tftpboot/user-data <<'EOF'
#cloud-config
autoinstall:
  version: 1
  apt:
    primary:
    - arches: [default]
      uri: http://mirrors.aliyun.com/ubuntu
  user-data:
    timezone: Asia/Shanghai
    disable_root: false
    chpasswd:
      list: |
        root:${root_passwd}
  identity:
    hostname: node
    password: ${test_passwd}
    username: test
  keyboard: {layout: us, variant: ''}
  locale: en_US.UTF-8
  ssh:
    install-server: true

  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}

  # packages:
  # - linux-generic-hwe-20.04-edge
  late-commands:
  - curtin in-target --target=/target -- wget -P /root/ http://${pxe_default_server}/tftp/bash/init.sh
  - curtin in-target --target=/target -- wget -P /root/ http://${pxe_default_server}/tftp/bash/network.sh
  - curtin in-target --target=/target -- bash /root/init.sh
EOF
sed -i 's#${root_passwd}#'${root_passwd}'#' /var/lib/tftpboot/user-data
sed -i 's#${test_passwd}#'${test_passwd}'#' /var/lib/tftpboot/user-data
sed -i 's#${pxe_default_server}#'${pxe_default_server}'#g' /var/lib/tftpboot/user-data

cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf.bak
cat > /etc/dhcp/dhcpd.conf <<EOF
ddns-update-style none;
subnet ${dhcp_subnet_ip} netmask ${dhcp_subnet_mask} {
     option routers             ${dhcp_pxe_gateway};
     option domain-name-servers 114.114.114.114;
     option subnet-mask         255.255.255.0;
     range dynamic-bootp        ${dhcp_ip_range};
     default-lease-time         21600;
     max-lease-time             43200;
     next-server                ${pxe_default_server};
     filename "grubx64.efi";
}
EOF

systemctl restart  tftpd-hpa apache2 isc-dhcp-server
[[ $? == 0 ]] && echo "PXE Server 安装完成!"
  • init.sh
#!/bin/bash
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
systemctl restart sshd
systemctl stop ufw.service
systemctl disable ufw.service
echo -e "NTP=ntp1.aliyun.com\nFallbackNTP=ntp.ubuntu.com" >> /etc/systemd/timesyncd.conf
systemctl restart systemd-timesyncd
cat >> /etc/security/limits.conf << EOF
*       soft        nofile  655350
*       hard        nofile  655350
*       soft        nproc   655350
*       hard        nproc   655350
root        soft        nofile  655350
root        hard        nofile  655350
root        soft        nproc   655350
root        hard        nproc   655350
EOF
rm -rf /root/init.sh
  • network.sh
#!/bin/bash
cd /etc/netplan
cp *.yaml network.yaml.bak
read -p "please ip address: " IP
Gateway=`echo $IP | awk -F '.' '{print $1"."$2"."$3".2"}'`
sed -i 's#critical: true#addresses: ['${IP}'/24]#' *.yaml
sed -i '/dhcp-identifier: mac/d' *.yaml
sed -i '0,/dhcp4: true/{s/dhcp4: true/gateway4: '${Gateway}'/}' *.yaml 
netplan apply
cd

4. 执行脚本自动安装

autoinstall目录,执行 autoinstall.sh脚本进行自动安装:

root@server:~/autoinstall# bash autoinstall.sh
....安装过程省略
PXE Server 安装完成!

装机环节

测试环境

  1. 如果使用 VMware 测试,请修改虚拟机的引导方式为UEFI(默认为BIOS)。
    • 打开虚拟机设置,选择选项,点击高级,找到固件类型,选择UEFI。
  2. 给虚拟机添加 VMnet2 网卡,模拟 PXE Server 和 虚拟机 Node 在同一交换机下。
  3. 使用 VMware 测试,建议分配给虚拟机内存大点(必须大于镜像文件,像20.04.4,建议6G)。因为在安装过程中,是需要将镜像文件拷贝到内存的,如果虚拟机的内存不足会报错。

生产环境

  1. 如果使用物理机,需在 BIOS 中设置 Boot 的模式为 UEFI ,禁用 security boot,并且允许从网络进行引导启动。
  2. 待装机的物理机需要和 PXE Server 服务器在同一交换机下。
  3. 物理机的内存一般都大于6G,不排除个别类型服务器内存过小,影响自动装机过程。

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情