一、介绍
Ubuntu 20.04 的服务器安装程序支持新的操作模式:自动安装(automated installation)。自动安装可以通过自动安装配置提前回答所有这些配置问题,并使安装过程无需任何交互即可运行。
在 Ubuntu 18.04 中,用的应答文件是 preseeds(预配置文件),它基于 debian-installer(aka di)来实现自动安装的。需要注意的是,如果你使用的是 cobbler,那你应该使用 ubuntu-20.04-legacy-server-amd64.iso,而不是 live-server(应该是缺少netboot),Ubuntu 20.04 已没有 server。
Ubuntu 20.04 自动安装在以下主要方面与之前的版本有所不同:
• 应答文件格式完全不同。现在是:cloud-init config,通常为 yaml。而之前是:debconf-set-selections 格式。
• 当前提条件中不存在问题的答案时,di会停止并要求用户输入。而自动安装不是这样的:默认情况下,如果根本没有任何自动安装配置,则安装程序将使用任何未回答问题的默认设置(如果没有默认问题,安装程序将失败)。在自动安装中可以将配置中的特定部分指定为“交互式”,这意味着安装程序仍将停止并询问这些部分。
二、环境
在 ubuntu 18.04.5 上部署 autoinstall 来批量安装 ubuntu 20.04.2。还是典型的 PXE + TFTP + HTTP + DHCP + Subiquity(ubuntu 服务器安装程序) 。镜像为:ubuntu-20.04.2-live-server-amd64.iso。注意,引导方式为UEFI。
主机 | 系统 | IP地址 |
---|---|---|
server | ubuntu 18.04.5 | 10.0.0.4 |
node1 | 未安装操作系统 | – |
node2 | 未安装操作系统 | – |
三、部署
1、安装相关软件
isc-dhcp-server :用来给客户端主机分配可用的IP地址。
tftpd-hpa :用来给客户端主机提供引导及驱动文件。
apache2 :用来给客户端主机提供镜像、应答文件以及一些自定义的文件脚本之类的。
root@server:~# apt-get -y install tftpd-hpa apache2 isc-dhcp-server whois
2、配置 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/
。
准备引导文件:vmlinuz(可引导的、压缩的内核),initrd(系统引导过程中挂载的一个临时根文件系统),pxelinux.0(网络引导程序)。
root@server:~# mount /var/lib/tftpboot/ubuntu-20.04.2-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
root@server:~# wget http://archive.ubuntu.com/ubuntu/dists/focal/main/uefi/grub2-amd64/current/grubnetx64.efi.signed -O /var/lib/tftpboot/pxelinux.0
准备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.2-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.2-live-server-amd64.iso
echo "Loading Ram Disk..."
initrd /initrd
}
EOF
3、配置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.2;
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;
default-lease-time 21600;
max-lease-time 43200;
next-server 10.0.0.4;
filename "pxelinux.0";
}
EOF
root@server:~# systemctl restart isc-dhcp-server
4、准备 cloud.init config
root@server:~# cat > /var/lib/tftpboot/meta-data <<EOF
instance-id: focal-autoinstall
EOF
在准备 cloud.init config 前。建议先手动安装一次 ubuntu 20.04.2,在 /var/log/installer/ 目录下会生成一个 autoinstall-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}
packages:
- linux-generic-hwe-20.04-edge
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
以上意思我就不注解了,详细请查阅官方文档:https://ubuntu.com/server/docs/install/autoinstall-reference
5、脚本准备
我这里准备了两个脚本(根据实际修改):
• 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
四、自动部署
以上的部署步骤,我都写成了脚本。并将镜像、脚本和一些文件,打包成了一个压缩包。压缩包下载地址:autoinstall-virtual-无镜像
用法:
将下载下来的压缩包上传到服务器,解压缩,进入解压出来的 autoinstall 目录并把镜像放到其中。
root@server:~# tar -xf autoinstall.tar.gz
root@server:~# cd autoinstall/
root@server:~/autoinstall# ll
total 1188120
-rw-r--r-- 1 root root 5506 Apr 17 15:51 autoinstall.sh
-rw-r--r-- 1 root root 2104 Apr 17 15:43 init.sh
-rw-r--r-- 1 root root 334 Apr 17 16:04 network.sh
-rw-r--r-- 1 root root 1435512 Apr 4 11:30 pxelinux.0
-rw-r--r-- 1 root root 1215168512 Apr 4 11:30 ubuntu-20.04.2-live-server-amd64.iso
根据实际情况修改 autoinstall.sh,主要修改以下几个地方:
# pxe服务端地址,root和普通用户test的密码
pxe_default_server='10.0.0.4'
root_passwd=`mkpasswd -m sha-512 '000000'`
test_passwd=`mkpasswd -m sha-512 '000000'`
# dhcp信息,根据实际网络来。注意实际网络必须要通外网,因为需要从网络下载内核更新,如果不通会报错。
subnet 10.0.0.0 netmask 255.255.255.0 {
option routers 10.0.0.2;
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;
default-lease-time 21600;
max-lease-time 43200;
next-server ${pxe_default_server};
filename "pxelinux.0";
如果想在无网环境下安装,请在 user-data 中去掉 packages 部分。
修改好 autoinstall.sh 后,注意要在 autoinstall 目录下执行脚本。
root@server:~/autoinstall# bash autoinstall.sh
如果发现 autoinstall.sh 修改错误且已经部署了。请删除 /va/lib/tftpboot 下的所有东西。再到 autoinstall 目录下重新执行脚本。
放上脚本内容,结构逻辑比较简单,autoinstall.sh:
#!/bin/bash
apt-get -y install tftpd-hpa apache2 isc-dhcp-server whois
pxe_default_server='10.0.0.4'
root_passwd=`mkpasswd -m sha-512 '000000'`
hb_passwd=`mkpasswd -m sha-512 '000000'`
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.2-live-server-amd64.iso /var/lib/tftpboot/
mount /var/lib/tftpboot/ubuntu-20.04.2-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/pxelinux.0
cp pxelinux.0 /var/lib/tftpboot/pxelinux.0
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.2-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.2-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: hb
password: ${hb_passwd}
username: hb
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#${hb_passwd}#'${hb_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 10.0.0.0 netmask 255.255.255.0 {
option routers 10.0.0.2;
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;
default-lease-time 21600;
max-lease-time 43200;
next-server ${pxe_default_server};
filename "pxelinux.0";
}
EOF
systemctl restart tftpd-hpa apache2 isc-dhcp-server
五、注意事项
1、引导方式
如果使用 VMware 测试,请修改虚拟机的引导方式为UEFI(默认为BIOS)。打开虚拟机设置,选择选项,点击高级,找到固件类型,选择UEFI。
如果使用物理机,请将 BIOS 引导方式修改为 UEFI。
2、内存
使用 VMware 测试,建议分配给虚拟机内存大点(必须大于镜像文件,像20.04,建议3G)。因为在安装过程中,是需要将镜像文件拷贝到内存的,如果虚拟机的内存不足会报错。
3、无网环境,应答文件如果配置
前面有提到实际网络必须要通外网,这是因为在应答文件中我定义 packages,即要安装到目标系统的软件包列表,如果不通网会报错,安装程序会一直卡在错误提示哪里,只能重启。当然重启是可以正常进入系统,系统也是没问题的。
上面说的报错并不会导致系统安装失败,只是安装软件失败,系统在这之前已经安装完毕了。只是后续的应答无法正常进行,像 packages 部分后面是 late-commands,那这一部分就不会执行了。应该是有跳过错误继续进行的指令,自行查阅吧。
如果想在无网环境下安装,最简单的办法就是在 user-data 中去掉 packages 部分。
4、日志查看
如果在自动安装过程中报错卡住。请使用 Ctrl+Alt+F2 进入命令行,查看 /var/log/installer/installer-journal.txt 日志或者其它相关日志。
使用 Ctrl+Alt+F1 可回到安装界面。
参考文章:
https://ubuntu.com/server/docs/install/autoinstall
https://ubuntu.com/server/docs/install/autoinstall-reference
https://askubuntu.com/questions/1235723/automated-20-04-server-installation-using-pxe-and-live-server-image