Abstract: On how to build a PXE server, and the practical application of Ubuntu Autoinstall features.
Note: You must have some bash programming knowledge to read this article.
P.S. : this article is the New Year version, originally intended to be issued before the year, but these two days delayed, have to now.
preface
In a cloud environment, cloud service providers provide host templates (and server images) to speed up the creation of server nodes. There are several architectural approaches to this type of functionality (including those of Vultr and various VPS vendors), typically consisting primarily of KVM infrastructure with upper-level management modules such as Cobble.
PXE
In order to trigger the automatic operation when the customer places an order, the PXE mechanism is required to intervene to make the new node host start the following process from the start of power-on:
- Try to find the DHCP Server and get the IP address of the DHCP from the PXE Server, along with the additional BOOTP parameters
- Use the BOOTP parameter (usually a file name pxelinux.0) to obtain the boot file pxelinux.0 from the TFTP service of the PXE Server
- Pxelinux.0 startup file to start a complete Linux boot sequence, including:
- Find GRUB information and display grub menus
- When a GRUB menu entry is selected or the default entry hits, the corresponding vmlinuz and initrd are loaded to boot the Linux kernel
- The kernel is always booted with the install parameter, so it will automatically enter the standard Linux installation screen
- The cloud-config parameter (user-data file) provided by Autoinstall automatically provides reply data during installation, enabling the installation interface to advance automatically
- Cloud-init is responsible for interpreting meta-data
- The cloud-init mechanism forces later-stage scripts to perform other tasks required by the service provider
Cloud service providers can provide complete online boot services through the above mechanism.
Of course there are a lot of details, but that’s the problem of filling in human lives.
For other OS, pxelinux.0 can be another bootloader, even the filename doesn’t have to be.
cloud-init
Cloud-init is a set of host node startup mechanisms developed by Canonical and the de facto startup standard for major cloud service providers. Different oss can use this mechanism to enable unattended startup.
In Ubuntu, cloud-init is now interlinked using a mechanism called autoinstall. Since both are developed by the same person, it is useful to think of AutoInstall as a concrete implementation of the Ubuntu version of Cloud-init.
Early Ubuntu, as well as the Debian family, used the Preseed mechanism for unattended installation of the operating system, but it has now been taken over by Cloud-init and Autoinstall.
In RedHat, Kickstart was used to do the unattended installation. Now it is done via cloud-init via an Openstack compliant mechanism. Other operating systems have similar schemes.
These are well beyond the scope of this outline.
The body of the
The scope of
We’ll just go through an example of simulating the scenario locally and provide a set of basic scripts to demonstrate the basic flow.
This is not just about preparing a PXE server, but also about providing a reusable, easily tuned DevOPS operational paradigm. You don’t have to use any known high-level wrappers at all.
In this article, you’ll see that we built a PXE-Server and then used it to enable other new virtual machines to automatically install the operating system and configure the working environment unattended.
The profile
Our environment is built in VMWare, and all VMs use a single network card to be connected in NAT mode. NAT network is used to simulate the network of cloud service providers.
A PXE Server runs on a NAT network segment and provides DHCP+BOOTP, TFTP, and WEB services, which provide NewNode with all the required materials for an unattended installation task.
We set up several new VM hosts in the same network segment and set UP BIOS type UEFI mode instead of traditional mode. Then directly boot, let it automatically search DHCP to obtain IP address, enter the installation sequence, complete all installation tasks stay in the boot ready state, so as to achieve the purpose of simulation.
Prepare the PXE server
PXE is a Preboot eXecution Environment (PXE, also known as a preexecution Environment) that provides a mechanism for booting a computer using a Network Interface. This mechanism allows the computer to boot independently of a local data storage device (such as a hard disk) or a locally installed operating system.
In our imagination, LAN a new starting on the bare machine electricity, host node via PXE mechanism for a startup environment first, and then supply it proper installation system, so that the model into the automated installation process, finally getting a new OS is ready to work the node, incorporated into the current production environment being part of a cloud infrastructure.
Therefore, we need to run a PXE server in the LAN to provide DHCP+BOOTP service. The DHCP service waits for the bare-metal nic to call for a New IP address through UDP, and BOOTP responds to the baremetal NIC in the DHCP New IP Requested message. A BOOTP-enabled nic can retrieve the corresponding BOOTP file and load it for initial booting. The DHCP+BOOP service on the PXE server usually responds with a startup file named pxelinux.0, which is customizable.
The client NIC requests the FILE from the TFTP service of the PXE server with the file name, reads the file to a specific location in the memory, and assigns the CPU execution permission to the location to enter the corresponding startup process.
Typical flow for Pxelinux.0:
- In general, this process takes the /grub folder of the TFTP server, obtains grub.cfg and presents the user with a GRUB boot menu with a countdown.
For automatic installation systems, the default value of this menu is to point to a specific location I on the WEB server and pull back the installation image execution from that location to enter the typical Linux system installation process. Note that we assign an unanswerable file, so the Linux installation process automatically executes all sequences without human intervention.
Having said that, now let’s see how to prepare the PXE server in detail
The host | IP | |
---|---|---|
PXE-server | 172.16.207.90 | |
NewNode | – | |
The basic system
First let’s install the base system. Note that this article is only for Ubuntu 20.04 LTS, so pXE-Server also uses this system.
But it’s not necessary. You actually need a server that supports DHCP, TFTP, and WEB services.
As a matter of personal preference, we installed ZSH and plugins to help reduce keystroke stress.
Total entry code
We used a script vS-Builder to do the overall PXE-Server build.
Some helper functions are explained separately in the subsequent section bash.sh (postscript: they are not), but you can imagine them for now: For example, Install_packages is equivalent to sudo apt-get install-y, headline is equivalent to echo for highlighting text, fn_name gets the current bash/ ZSH function name, and so on.
Some of the variables that need to be used may not be described at this point, but you can refer to the script source code later.
The starting point, or entry code, in this script looks like this:
vms_entry() {
headline "vms-builder is running"
local ubuntu_iso_url="https://${ubuntu_mirrors[0]}/ubuntu-releases/${ubuntu_codename}/${ubuntu_iso}"
local alternate_ubuntu_iso_url=${alternate_ubuntu_iso_url:-$ubuntu_iso_url}
local tftp_dir=/srv/tftp
local full_nginx=-full
v_install # install software packages: tftp, dhcp, nginx, etc
v_config # and configure its
v_end #
}
Copy the code
This is what sets this article apart from other articles on the same topic: We provide a set of best practices for writing bash scripts that you can easily tweak and use for other purposes.
In addition, it is a system configuration method that supports synchronization, so you can execute scripts multiple times without worrying about confusing results.
So we’ll explain the programming methods synchronously.
V_install and v_config are key entry points to the entire PXE-server construct. The meaning is self-evident.
Entry for software package installation
The following software packages are required
Package | Usage | |
---|---|---|
tftp-hpa | The TFTP service provides system installation files such as Pxelinux.0 and GRUB | |
isc-dhcp-server | DHCP + the BOOTP service | |
Nginx | Ubuntu 20.04 installation image is available |
The PXE protocol combines DHCP and TFTP. DHCP is used to find the appropriate boot server, TFTP is used to download the network boot program (NBP) and additional files.
Since the Ubuntu installation program uses an ISO image (which is most convenient for us), the Web server is also required to provide download functionality.
Ok, v_install will install them:
v_install() {
echo && headline "$(fn_name)" && line
v_install_tftp_server
v_install_dhcp_server
v_install_web_server
}
v_install_tftp_server() {
headline "$(fn_name)"
install_packages tftpd-hpa
}
v_install_dhcp_server() {
headline "$(fn_name)"
install_packages isc-dhcp-server
}
v_install_web_server() {
headline "$(fn_name)"
install_packages nginx$full_nginx
}
Copy the code
No further elaboration.
Configure the entry of the software package
V_config handles all configuration actions.
v_config() {
echo && headline "$(fn_name)" && line
v_config_dirs
v_download_iso
v_config_boot
v_config_grub
v_config_bash_skel
v_config_tftp
v_config_dhcp
v_config_nginx
v_config_aif # autoinstall files
}
Copy the code
The goal we are going to achieve is to set up a TFTP layout like this:
In addition, you need to configure DHCP, Web Server, and so on.
The following sections will be explained in the order given by v_config.
v_config_dirs
We’ll end up with a whole TFTP folder structure, so here’s the basic structure:
v_config_dirs() {
$SUDO mkdir -pv $tftp_dir/{autoinstall,bash,boot/live-server,cdrom,grub,iso,priv}
}
Copy the code
SUDO is a defensive measure. Here’s how it’s defined:
SUDO=sudo [ "$(id -u)" = "0" ] && SUDO= Copy the code
So for root it is equivalent to nothing, and for others it is the sudo directive.
v_download_iso
Then download the Ubuntu 20.04 Live Server ISO file.
v_download_iso() {
headline "$(fn_name)"
local tgt=$tftp_dir/iso/$ubuntu_iso
[ -f $tgt ] || {
wget "$alternate_ubuntu_iso_url" -O $tgt
}
grep -qE "$tftp_dir/iso/" /etc/fstab || {
echo "$tftp_dir/iso/$ubuntu_iso on $tftp_dir/cdrom iso9660 ro,loop 0 0" | $SUDO tee -a /etc/fstab
$SUDO mount -a && ls -la --color $tftp_dir/cdrom
}
}
Copy the code
There is a set of predefined variables involved, which look like this:
Ubuntu_codename = focal ubuntu_version = 20.04.3 ubuntu_iso = ubuntu -${ubuntu_version}-live-server-amd64.iso ubuntu_mirrors=("mirrors.cqu.edu.cn" "mirrors.ustc.edu.cn" "mirrors.tuna.tsinghua.edu.cn" "mirrors.163.com" "mirrors.aliyun.com") Copy the code
Ubuntu_mirrors is a bash array variable, but only the first value of this list will actually be used:
# in vms_entry(): local ubuntu_iso_url="https://${ubuntu_mirrors[0]}/ubuntu-releases/${ubuntu_codename}/${ubuntu_iso}" local alternate_ubuntu_iso_url=${alternate_ubuntu_iso_url:-$ubuntu_iso_url} Copy the code
:ok:
We started by testing the existence of the file and downloading the ISO file as needed.
At the end of v_download_iso, we grep fstab to see if it hasn’t changed, and then add an entry to mount the downloaded ISO file to/SRV/TFTP /cdrom.
The auto-mount doesn’t delay anything, but in the future we’ll be able to easily extract files from ISO.
v_config_boot
In the previous section, we mounted the iso file to cdrom/
v_config_boot() {
# boot files
local tgt=$tftp_dir/boot/live-server
[ -f $tgt/vmlinuz ] || {
$SUDO cp $tftp_dir/cdrom/casper/vmlinuz $tgt/
$SUDO cp $tftp_dir/cdrom/casper/initrd $tgt/}}Copy the code
Simple without explanation.
v_config_grub
Premise:
local tgt=$tftp_dir/grub
Copy the code
This part of the code first downloads and prepares the pxelinux.0 file;
[ -f $tftp_dir/pxelinux.0 ] || {
$SUDO wget http://archive.ubuntu.com/ubuntu/dists/${ubuntu_codename}/main/uefi/grub2-amd64/current/grubnetx64.efi.signed -O $tftp_dir/pxelinux.0
}
Copy the code
Then copy grub’s font file from cdrom/ :
In the previous section, we have mounted the ISO file to Cdrom /
[ -f $tgt/font.pf2 ] || $SUDO cp $tftp_dir/cdrom/boot/grub/font.pf2 $tgt/
Copy the code
Then generate the grub.cfg file:
[ -f $tgt/grub.cfg ] || {
cat <<-EOF | $SUDO tee $tgt/grub.cfg if loadfont /boot/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=3 Menuentry "Ubuntu Server 20.04 autoinstall" --id=autoinstall { echo "Loading Kernel..." # make sure to escape the '; ' or surround argument in quotes linux /boot/live-server/vmlinuz ramdisk_size=1500000 ip=dhcp url="http://${PXE_IP}:3001/iso/ubuntu-${ubuntu_version}-live-server-amd64.iso" autoinstall ds="nocloud-net; s=http://${PXE_IP}:3001/autoinstall/" root=/dev/ram0 cloud-config-url=/dev/null echo "Loading Ram Disk..." initrd /boot/live-server/initrd } menuentry "Install Ubuntu Server [NEVER USED]" { set gfxpayload=keep linux /casper/vmlinuz quiet --- initrd /casper/initrd } grub_platform # END OF grub.cfg EOF
Copy the code
You must look at the source code rather than copy and paste it from the page, because the hereDoc indentation function requires TAB characters to indent, and the original characters on the page may have been lost.
For advanced tips on HereDoc, see: Know Here Document
In this GRUB menu, the URL =”http://${PXE_IP}:3001/iso/ubuntu-${ubuntu_version}-live-server-amd64.iso” gives you an ISO image of the installation CD, This is accessed through the Web Server service and later in v_config_nginx we will map the TFTP folder to the listable page structure.
ds=”nocloud-net; S =http://${PXE_IP}:3001/autoinstall/” specifies the autoinstall folder, which is intended to provide meta-data and user-data files via the autoinstall specification. They are used for unattended automatic installation.
The ISO file of Ubuntu Live Server is about 1GB, so ramdisk_size=1500000 specifies the disk size to be about 1.5GB to accommodate the ISO, with some allowance for the installation program. So you need to configure at least 2GB of memory for each new host node, or you may not be able to complete the automatic installation process.
Privileged state and pipeline output
For bash writing, an unprivileged user who wants to generate a file from heredoc needs the following idiom:
cat <<-EOF | sudo tee filename
EOF
Copy the code
Then there are some variations, such as appending to filename:
cat <<-EOF | sudo tee -a filename
EOF
Copy the code
This idiom is used to solve the problem that output pipe characters cannot sudo:
echo "dsjkdjs" > filename
Copy the code
If the filename is protected by privilege, the echo pipe output complains, if you want to solve the problem, you need to switch to the cat heredoc | sudo tee filename syntax.
Since bash supports multi-line strings, you can also use heredoc when you don’t want to:
echo "djask
djska
daskl
dajskldjsakl" | sudo tee filename
Copy the code
But it works fine in simple variableless expansions, and if your text is large and may contain complex variable expansions, or is surrounded by multiple single and double quotes, then Cat heredoc is the way to go.
v_config_bash_skel
The purpose of v_config_BASH_skel is to generate the smallest post-installation script boot.sh:
v_config_bash_skel() {
[ -f $tftp_dir/bash/boot.sh ] || {
cat <<-"EOF" | $SUDO tee $tftp_dir/bash/boot.sh
#! /bin/bash
# -*- mode: bash; c-basic-offset: 2; tab-width: 2; indent-tabs-mode: t-*-
# vi: set ft=bash noet ci pi sts=0 sw=2 ts=2:
# st:
#
echo "booted."
[ -f custom.sh ] && bash custom.sh
EOF
}
#
$SUDO touch $tftp_dir/priv/gpg.key
$SUDO touch $tftp_dir/priv/custom.sh
}
Copy the code
Boot.sh will be executed automatically after the Ubuntu installation is complete and the first boot is ready.
In addition, we also create 0 length backup files gpg.key and custom.sh.
If you want to automatically inject a private key, such as when you need to do a pre-deployment devOPS distribution signature, then you can provide a valid gpg.key file, otherwise keep the 0 length.
If you need additional post-processing scripts, you can provide a valid custom.sh script file.
We also provide a more complete boot.sh, but that may need to be covered next time.
v_config_tftp
v_config_tftp() {
cat /etc/default/tftpd-hpa
}
Copy the code
Do nothing!
The default configuration of TFTP is to point to the/SRV/TFTP folder, we will use this, no extra configuration required.
v_config_dhcp
The DHCP IP address pool is configured as follows:
v_config_dhcp() {
local f=/etc/dhcp/dhcpd.conf
$SUDO sed -i -r "s/option domain-name .+\$/option domain-name \"$LOCAL_DOMAIN\ "; /" $f
$SUDO sed -i -r "s/option domain-name-servers .+\$/option domain-name-servers ns1.$LOCAL_DOMAIN, ns2.$LOCAL_DOMAIN; /" $f
grep -qE "^subnet $DHCP_SUBNET netmask" $f || {
cat <<-EOF | $SUDO tee -a $f # https://kb.isc.org/v1/docs/isc-dhcp-44-manual-pages-dhcpdconf subnet $DHCP_SUBNET netmask $DHCP_MASK { option routers $DHCP_DHCP_ROUTER; Option domain - name - the servers 114.114.114.114; option subnet-mask $DHCP_MASK; range dynamic-bootp $DHCP_RANGE; default-lease-time 21600; max-lease-time 43200; next-server $DHCP_DHCP_SERVER; filename "pxelinux.0"; # filename "grubx64.efi"; } EOF
}
$SUDO systemctl restart isc-dhcp-server.service
}
Copy the code
filename “pxelinux.0”; The BOOTP file name is named.
The variables involved are mainly as follows:
LOCAL_DOMAIN="ops.local"DHCP_PRE = 172.16.207 DHCP_SUBNET =$DHCP_PRE. 0 DHCP_MASK = 255.255.255.0 DHCP_DHCP_ROUTER =$DHCP_PRE2.# it should be a router ip in most cases
DHCP_DHCP_SERVER=$DHCP_PRE90.# IP address of 'pxe-server'
DHCP_RANGE="${DHCP_PRE}100.${DHCP_PRE}. 220. "" # the pool
PXE_IP=$DHCP_DHCP_SERVER
PXE_HOSTNAME="pxe-server" # BIOS name of PXE server, or IP address
Copy the code
Because the simulation is performed in a local VMWare VIRTUAL machine, a small network segment plan is used.
v_config_nginx
Simply append the nginx configuration and restart nginx:
v_config_nginx() {
local f=/etc/nginx/sites-available/default
grep -qE 'listen 3001' $f || {
cat <<-EOF | $SUDO tee -a $f server { listen 3001 default_server; listen [::]:3001 default_server; root $tftp_dir; autoindex on; autoindex_exact_size on; autoindex_localtime on; charset utf-8; server_name _; } EOF
$SUDO systemctl restart nginx.service
}
}
Copy the code
This configuration specifies the PXE-server :3003 Web service used in grub.cfg.
v_config_aif
V_config_aif is the highlight, and it constructs the files required by Autoinstall.
According to the Ubuntu Autoinstall specification, meta-data can provide key:value pairs such as instance_ID, or none at all.
User-data files are used to automatically answer the installation process. It is informative, but not difficult to understand. The difficulty probably lies in the question of what can be adjusted and how, and sometimes there is no basis for it. But the following is provided as a function, and the specific placeholders are already in place, so you can pretty much tweak them as you wish — just by changing the bash variable values.
Here is the full view of the function, slightly abridged:
v_config_aif() {
# autoinstall files
$SUDO touch $tftp_dir/autoinstall/meta-data
declare -a na
local network_str="" str="" n=1 i
na=($(ifconfig -s -a | tail -n +2 | grep -v '^lo' | awk '{print $1}'))
for i in ${na[@]}; do
[[ $n -gt 1 ]] && str="," || str=""
str="${str}${i}: {dhcp4: yes,dhcp6: yes}"
network_str="${network_str}${str}"
let n++
done
grep -qE '^#cloud-config' $tftp_dir/autoinstall/user-data || {
cat <<-EOF | $SUDO tee $tftp_dir/autoinstall/user-data #cloud-config autoinstall: version: 1 interactive-sections: [] # https://ubuntu.com/server/docs/install/autoinstall-reference # https://ubuntu.com/server/docs/install/autoinstall-schema apt: primary: - arches: [default] uri: http://${ubuntu_mirrors[0]}/ubuntu user-data: timezone: $TARGET_TIMEZONE # Europe/London disable_root: true # openssl passwd -6 -salt 1234 # mkpasswd -m sha-512 chpasswd: list: | root: ${TARGET_PASSWORD} runcmd: - wget -P /root/ http://$PXE_HOSTNAME:3001/bash/boot.sh - wget -P /root/ http://$PXE_HOSTNAME:3001/priv/gpg.key || echo "no gpg key, skipped" - wget -P /root/ http://$PXE_HOSTNAME:3001/priv/custom.sh || echo "no custom.sh, skipped" - bash /root/boot.sh #- sed -ie 's/GRUB_TIMEOUT=.*/GRUB_TIMEOUT=3/' /target/etc/default/grub identity: hostname: $TARGET_HOSTNAME # username: ubuntu # password: "\$6\$exDY1mhS4KUYCE/2\$zmn9ToZwTKLhCw.b4/b.ZRTIZM30JZ4QrOQ2aOXJ8yk96xpcCof0kxKwuX1kqLG/ygbJ1f8wxED22bTL4F46P0" username: $TARGET_USERNAME password: "${TARGET_PASSWORD}" keyboard: {layout: 'us', variant: 'us'} # keyboard: {layout: 'gb', variant: 'devorak'} locale: $TARGET_LOCALE ssh: allow-pw: no install-server: true authorized-keys: [$(n=1 && for arg in "${TARGET_SSH_KEYS[@]}"; do # arg=\"$arg\" [ $n -gt 1 ] && echo -n ", " echo -n "\"$arg\"" let n++ done)] packages: [$(n=1 && for arg in "${TARGET_PKGS[@]}"; do # arg=\"$arg\" [ $n -gt 1 ] && echo -n ", " echo -n "\"$arg\"" let n++ done)] storage: grub: reorder_uefi: false swap: size: 0 config: # https://askubuntu.com/questions/1244293/how-to-autoinstall-config-fill-disk-option-on-ubuntu-20-04-automated-server-in - {ptable: gpt, path: /dev/sda, 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-sda1} - {fstype: fat32, volume: partition-sda1, preserve: false, type: format, id: format-2} - {device: disk-sda, size: 1073741824, wipe: superblock, flag: linux, number: 2, preserve: false, grub_device: false, type: partition, id: partition-sda2} - {fstype: ext4, volume: partition-sda2, preserve: false, type: format, id: format-0} - {device: disk-sda, size: -1, flag: linux, number: 3, preserve: false, grub_device: false, type: partition, id: partition-sda3} - name: vg-0 devices: [partition-sda3] preserve: false type: lvm_volgroup id: lvm-volgroup-vg-0 - {name: lv-root, volgroup: lvm-volgroup-vg-0, size: 100%, preserve: false, type: lvm_partition, id: lvm-partition-lv-root} - {fstype: ext4, volume: lvm-partition-lv-root, preserve: false, type: format, id: format-1} - {device: format-1, path: /, type: mount, id: mount-2} - {device: format-0, path: /boot, type: mount, id: mount-1} - {device: format-2, path: /boot/efi, type: mount, id: mount-3} EOF}}Copy the code
It uses a separate declaration of the bash variable, excerpted in part below:
TARGET_HOSTNAME="${TARGET_HOSTNAME:-ubuntu-server}"
TARGET_USERNAME="${TARGET_USERNAME:-hz}"
TARGET_PASSWORD="${TARGET_PASSWORD:-$_default_passwd}"
TARGET_LOCALE="${TARGET_LOCALE:-en_US.UTF-8}"
TARGET_SSH_KEYS=(
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDxjcUOlmgsabCmeYD8MHnsVxueebIocv5AfG3mpmxA3UZu6GZqnp65ipbWL9oGtZK3BY+WytnbTDMYdVQWmYvlvuU6 +HbOoQf/3z3rywkerbNQdffm5o9Yv/re6dlMG5kE4j78cXFcR11xAJvJ3vmM9tGSBBu68DR35KWz2iRUV8l7XV6E+XmkPkqJKr3IvrxdhM0KpCZixuz8z9kr Nue6NdpyELT/mvD5sL9LG4+XtU0ss7xH1jk5nmAQGaJW9IY8CVGy07awf0Du5CEfepmOH5gJbGwpAIIubAzGarefbltXteerB0bhyyC3VX0Q8lIHZ6GhMZSq fD9vBHRnDLIL"
)
TARGET_PKGS=(
# net-tools
# lsof
curl
wget
# whois
)
TARGET_TIMEZONE=Asia/Chongqing
Copy the code
_default_passwd you can generate your own:
$ mkpasswd -m sha-512
Copy the code
Or just write like this:
_default_passwd="$(mkpasswd -m sha-512 'password')"
Copy the code
TARGET_SSH_KEYS can be given an array, self-tuning.
TARGET_PKGS can be adjusted, but is not recommended. With curl and wget, you can go one step further and do better post-installation processing in boot.sh than during the system installation. Due to the Ubuntu installation process, the image of the software source may not take full effect during the installation process. Therefore, do not install too many software packages during the installation process. The software source will not be a problem if the operation is performed after the first startup.
Our more complete boot.sh includes utilities like automatic login console, secret free sudo, and TARGET_SSH_KEYS provides remote SSH login capability, so _default_passwd can be specified at will. There’s almost no chance you’ll ever use it yourself, so having a super complicated (but super hard to remember) password is good for server security.
Background: Cloud-init and autoinstall
User-data is part of the cloud-init specification, but cloud-init and autoinstall are derived from one another and are used interchangeably in Ubuntu.
Note that we use the YAML configuration structure. You can use user-data script and other formats if you want.
Expand arrays in heredoc
Note that using bash variable expansion syntax, we wrote an embedded script to expand the TARGET_SSH_KEYS array:
ssh:
allow-pw: no
install-server: true
authorized-keys: [$(n=1 && for arg in "${TARGET_SSH_KEYS[@]}"; do
# arg=\"$arg\"
[ $n -gt 1 ] && echo -n ","
echo -n "\"$arg\""
let n++
done)]
Copy the code
The expanded effect is shown as follows:
ssh:
allow-pw: no
install-server: true
authorized-keys: ["ssh-rsa dskldl"."ssh-rsa djskld"]
Copy the code
Similar practices are useful in the Packages section.
summary
All script ready, run it!
No surprises (of course there won’t be), so pXE-Server is now ready. I’m just waiting for you to test the new machine.
Test results
As long as the newly created host node is in the PXE-Server network segment, the installation can be automatically completed through the PXE search of the nic.
After the new host is powered on and the DHCP+BOOTP boot parameters are obtained, pxelinux.0 is executed and GRUB menu items are automatically executed (initTD and VMlinuz are shown in the figure) :
The status of the unattended system installation process is shown as follows:
What we haven’t solved is:
- Support a variety of systems, a variety of hardware configuration
- Support the programmable management and maintenance of cloud infrastructure architecture
- Apply meta-data metadata sets
- , etc.
These questions are beyond the scope of this article.
Some of these topics may be discussed separately in the future.
Write the post-installation script
We’ve provided what we call a more complete boot.sh post-installation script, which takes care of the basic environment necessary for a working node. These environments are configured so that operations people can be happier working in the node. You can write your own to fit your network architecture.
For the post-installation script, maybe next time, this article is long enough.
bash.sh
See bash.sh, which is a separate file that can be used as a basic skeleton for hand-writing bash scripts.
The best example of how to use it is the VS-Builder script in this article.
Bash.sh provides a set of basic detection functions that can help you write universal scripts. Vs-builder also provides a brief wrapper for package management operations that can be applied across platforms.
I was going to introduce bash.sh itself to help you understand the code in this article, but I realized it was already too long, and I’m not impressed with the Swastikas, so I’ll leave it at that until I can’t wait to see the source code for myself.
Tarball
The code mentioned in this article, such as VS-Builder, and other necessary files, as well as folder structures for reference, are available in the REPO and are welcome.
Afterword.
It should also be mentioned that VMWare provides a dedicated Data Source that can provide Data Source services to cloud-init, so in that sense, this article doesn’t really need that much hassle — but that would require an enterprise platform like VMWare vSphere.
Cloud-init is the de facto standard for cloud infrastructure provisioning.
This is probably one of the few wheels Canonical has made that everyone likes.
reference
- Preboot Execution Environment – Wikipedia
- PXE Specification — The Preboot Execution Environment Specification V2.1 Published by Intel & SystemSoft
- BIS specification – The Boot Integrity Services specification v1.0 published by Intel
- Intel Preboot Execution Environment – Internet-Draft 00 of the PXE Client/Server Protocol included in the PXE specification
- PXE error Codes — A catalogue of PXE error codes
- Automated server install — schema – Ubuntu
- Automated server install reference – Ubuntu
- Cloud-init Documentation – Cloud-init 21.4 Documentation
- cloud-init.io
- hedzr/bash.sh: main entry template of your first bash script file
🔚