Performing unattended builds with pre-seed files

Broadly speaking, Ubuntu Server builds (and indeed, other Debian derivative operating systems) function exactly the same way. You specify a script file to tell the installer what actions to take, in place of a human being selecting options. With Ubuntu Server, this is called a pre-seed file. Let's go through this now, and build one up.

The pre-seed files are very powerful, and there is lots of documentation around—however, they can sometimes appear more complex to the naked eye. Starting with the following lines of code, we set the appropriate locale and keyboard layout for our server:

d-i debian-installer/locale string en_GB
d-i console-setup/ask_detect boolean false
d-i keyboard-configuration/xkb-keymap select gb

We then configure the following network parameters:

d-i netcfg/choose_interface select auto
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
d-i netcfg/hostname string automatedubuntu
d-i netcfg/wireless_wep string

Here, you will note that we don't actually need to know the interface name in advance—rather, we can get Ubuntu to guess it, using its automated detection algorithm. We are setting the hostname to automatedubuntu; however, note that the other parameters are used to prevent the installer from prompting for a hostname from the user, thus meaning the installation is not truly unattended. Next, we add some details about where the installer can download its packages from, as shown in the following code block:

d-i mirror/country string manual
d-i mirror/http/hostname string 192.168.201.1
d-i mirror/http/directory string /ubuntu1804
d-i mirror/http/proxy string

These should naturally be adjusted to suit your network, HTTP server setup on your PXE server, and so on.

Many of these are also set in the kernel parameters, as we saw in our PXELINUX configuration earlier—we just need to confirm a few of them here.

We then set up the root account password, and any additional user accounts, as follows:

d-i passwd/root-password password password
d-i passwd/root-password-again password password
d-i passwd/user-fullname string Automation User
d-i passwd/username string automation
d-i passwd/user-password password insecure
d-i passwd/user-password-again password insecure
d-i user-setup/allow-password-weak boolean true
d-i user-setup/encrypt-home boolean false

Note here that I have specified the passwords in plain text, to highlight the possibility to do this here—there are alternative parameters you can specify that will accept a password hash, which is far more secure when creating configuration files. Here, the root password is set to password, and a user account called automation is set up, with the password insecure. As before, our password policy is quite weak and could be strengthened here, or later, using Ansible. We then set the time zone as appropriate, and turn on NTP synchronization, as follows:

d-i clock-setup/utc boolean true
d-i time/zone string Etc/UTC
d-i clock-setup/ntp boolean true

The most complex block of code in our otherwise simplistic example is the following one, which is used to partition and set up the disk:

d-i partman-auto/disk string /dev/sda
d-i partman-auto/method string lvm
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-md/device_remove_md boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-auto-lvm/guided_size string max
d-i partman-auto/choose_recipe select atomic
d-i partman/default_filesystem string ext4
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman-md/confirm boolean true
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true

Although verbose, this section of the file basically says to automatically partition the disk /dev/sda, set up LVM, use automated calculations to determine the filesystem layout, and then create ext4 filesystems. As you can see, there are many safeguards and confirmation prompts that we have flagged as true as otherwise, the installer would stop and wait for user input to proceed. If this were to happen, our installation would again not be truly unattended. From here, we specify the package set we want to be installed, as follows:

tasksel tasksel/first multiselect standard
d-i pkgsel/include string openssh-server build-essential
d-i pkgsel/update-policy select none

The preceding lines of code essentially set up a minimal server build with the openssh-server package and build-essential packages on it. The automated update policy is configured to not automatically update. Finally, to finish off the file, we tell it where to install the boot loader, and to reboot upon successful completion, as follows:

d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
d-i finish-install/reboot_in_progress note

As with our CentOS example, we will serve this file from our web server, and thus, the PXELINUX boot configuration needs adjusting, to make sure we incorporate this file—an appropriate example is shown as follows:

default isolinux/menu.c32
prompt 0
timeout 120

menu title --------- Enterprise Automation Boot Menu ---------

label 1
menu label ^1. Install Ubuntu Server 18.04 from local repo
kernel ubuntu1804/linux
append initrd=ubuntu1804/initrd.gz url=http://192.168.201.1/ubuntu-config/ubuntu-unattended.txt vga=normal locale=en_US.UTF-8 console-setup/ask_detect=false console-setup/layoutcode=gb keyboard-configuration/layoutcode=gb mirror/country=manual mirror/http/hostname=192.168.201.1 mirror/http/directory=/ubuntu1804 mirror/http/proxy="" live-installer/net-image=http://192.168.201.1/ubuntu1804/install/filesystem.squashfs netcfg/get_hostname=unassigned-hostname

Note the following new options in use this time:

  • url: Tells the installer from where to obtain our pre-seed file.
  • console-setup/layoutcode and keyboard-configuration/layoutcode: Prevents the installer from asking about keyboard settings when it is first run.
  • netcfg/get_hostname: Although we have set the hostname in the pre-seed file, we have to specify this parameter here, otherwise the installer will stop, and prompt the user to enter a hostname.

Again, if you test this by booting a server over the network using the preceding configuration, you should see the server build complete. Unlike the CentOS 7 installation, you will not see any menu options—these will only be presented to you if your pre-seed configuration file is incorrect, or is missing some important details. Instead, you will simply see a series of progress bars flash by, as the various stages of the installation are completed. For example, the following screenshot shows that the base system is installed to the disk after the partitions and logical volumes have been set up:

Assuming all goes well, this process will continue until you are presented with a final progress bar, which shows the final tidy-up being completed before the server is rebooted. In the following screenshot, the filesystems are being unmounted, in preparation for a reboot:

When this final progress bar completes, your server will reboot, and you will be presented with a login prompt, from where you can log in with the credentials specified in the pre-seed file d-i passwd parameters shown previously. Note that if you use different credentials for your build, you must use these here, and not those specified previously.

At this stage, you should be able to perform an unattended build of either CentOS or Ubuntu Server over the network and perform basic changes, such as selecting the required packages and setting credentials. In the next section, we will explore methods of additional bespoke customization, beyond the original OS.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset