PXE batch install Ubuntu 20.04.2

Posted by bulldorc on Fri, 04 Mar 2022 08:32:34 +0100

Original link: https://www.cpweb.top/1698

1, Introduction

  the server installer for Ubuntu 20.04 supports a new operation mode: automated installation. Automatic installation can answer all these configuration questions in advance through automatic installation configuration, and make the installation process run without any interaction.
  in Ubuntu 18.04, the answer file used is presets (pre configuration file), which is based on Debian installer (aka di) to realize automatic installation. It should be noted that if you use cobbler, you should use ubuntu-20.04-legacy-server-amd 64 ISO instead of live server (it should be lack of netboot). Ubuntu 20.04 has no server.
   Ubuntu 20.04 automatic installation is different from previous versions in the following main aspects:
  • the format of response file is completely different. Now it is: cloud init config, usually yaml. Before that: debconf set selections format.
   • when there is no answer to the question in the prerequisite, di will stop and ask the user for input. Automatic installation is not like this: by default, if there is no automatic installation configuration at all, the installer will use the default settings of any unanswered questions (if there are no default questions, the installer will fail). In automatic installation, specific parts of the configuration can be specified as "interactive", which means that the installer will still stop and ask for these parts.
  

2, Environment

  deploy autoinstall on ubuntu 18.04.5 to batch install ubuntu 20.04.2. It is also a typical PXE + TFTP + HTTP + DHCP + subequity (ubuntu server installer). The image is: ubuntu-20.04.2-live-server-amd64.iso . Note that the boot mode is UEFI.

hostsystemIP address
serverubuntu 18.04.510.0.0.4
node1Operating system not installed-
node2Operating system not installed-

  

3, Deploy

1. Install relevant software

ISC DHCP server: used to assign available IP addresses to client hosts.
Tftpd HPA: used to provide boot and driver files for client hosts.
apache2: it is used to provide the client host with images, answer files and some custom file scripts.

root@server:~# apt-get -y install tftpd-hpa apache2 isc-dhcp-server whois

  

2. Configuring tftp and 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

Prepare boot file:

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

Prepare grub

root@server:~# wget http://archive.ubuntu.com/ubuntu/dists/focal/main/uefi/grub2-amd64/current/grubnetx64.efi.signed -O /var/lib/tftpboot/pxelinux.0
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. Configure 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

  

4. Prepare cloud init config

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

  preparing cloud Before init config. It is recommended to manually install ubuntu 20.04.2. An Autoinstall user data will be generated in the / var/log/installer / directory. This is an answer file based on the current system. We can use it as a basis and modify it according to the actual situation.

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

   I won't comment on the above meaning. Please refer to the official documents for details: https://ubuntu.com/server/docs/install/autoinstall-reference

  

5. Script preparation

I have prepared two scripts here (according to the actual modification):
 • init.sh: initialization script used to run after successful installation and installation of all updates and software packages before successful system restart.
 • network.sh: used to quickly modify network configuration. Execute this script on the installed system and enter the IP to replace the dynamic address with the static address.

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

cp /etc/sysctl.conf /etc/sysctl.conf.bak
cat > /etc/sysctl.conf << EOF
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.ip_forward = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.tcp_max_tw_buckets = 6000
net.ipv4.tcp_sack = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_rmem = 4096        87380   4194304
net.ipv4.tcp_wmem = 4096        16384   4194304
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 262144
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_fin_timeout = 1
net.ipv4.tcp_keepalive_time = 30
net.ipv4.ip_local_port_range = 1024    65000
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
EOF
      
/sbin/sysctl -p

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, Automatic deployment

  I have written the above deployment steps into scripts. The image, script and some files are packaged into a compressed package. Compressed package download address:

Usage:
Upload the downloaded compressed package to the server, decompress it and enter the extracted autoinstall directory.

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

Modify autoinstall.com according to the actual situation SH, mainly modify the following places:

# pxe server address, password of root and ordinary user test
pxe_default_server='10.0.0.4'
root_passwd=`mkpasswd -m sha-512 '000000'`
test_passwd=`mkpasswd -m sha-512 '000000'`


# dhcp information, according to the actual network. Note that the actual network must be connected to the external network, because the kernel update needs to be downloaded from the network. If it fails, an error will be reported.
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";

If you want to install in a netless environment, please remove the packages section from user data.
Modify autoinstall After sh, be careful to execute the script in the autoinstall directory.

root@server:~/autoinstall# bash autoinstall.sh

  if autoinstall is found SH modifies errors and has been deployed. Please delete everything under / va/lib/tftpboot. Re execute the script in the autoinstall directory.
   put the script content, the structure logic is relatively simple, 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

5, Precautions

1. Guiding mode

   if you use VMware Workstation, modify the boot mode of the virtual machine to UEFI (BIOS by default). Open the virtual machine settings, select options, click Advanced, find the firmware type, and select UEFI.
   if you use a physical machine, change the BIOS boot mode to UEFI.

2. No network environment, if the answer file is configured

   as mentioned earlier, the actual network must be connected to the external network. This is because I define packages in the response file, that is, the list of software packages to be installed to the target system. If the network is not available, an error will be reported, and the installer will always be stuck in the error prompt and can only be restarted. Of course, you can enter the system normally after restarting, and the system is no problem.
   the error reporting mentioned above will not lead to the failure of system installation, but the failure of software installation. The system has been installed before that. However, the follow-up response cannot be carried out normally. For example, if the package part is followed by late commands, this part will not be executed. It should be an instruction to continue with skip errors. Check it yourself.
  if you want to install in a network free environment, the easiest way is to remove the packages part from user data.

Reference article:
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

Topics: Linux Ubuntu pxe