How to perform unattended Linux installations with Kickstart

Kickstart is an automatic installation method natively available on those distributions which uses the Anaconda installer: Red Hat Enterprise Linux (and its clones) and Fedora. It can also be used to install Ubuntu, actually, but in that context it acts as a layer of compatibility to the debian-native preseeding method. With Kickstart we can perform unattended, customizable and reproducible installations.

In this tutorial we learn the basics of Kickstart, and we see how to perform an unattended installation of a Fedora Workstation system.

In this tutorial you will learn:

  • How to perform unattended installations using Kickstart
  • How to write a Kickstart file
  • How to pass a Kickstart file to the Anaconda installer
How to perform unattended linux installations with kickstart
How to perform unattended Linux installations with Kickstart

 

Software requirements and conventions used
Category Requirements, Conventions or Software Version Used
System Distribution independent
Software No specific software needed
Other None
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command $ – requires given linux-commands to be executed as a regular non-privileged user

Introduction

When we perform a Kickstart installation, instead of interactively answering to the system installer questions about the various aspects of the installation process, we pass a series of command/instructions in the so called Kickstart file. In it, we define what partitions layout we want to use, what locale and timezone to use for the new system, what packages should be installed, etc.



The best way to learn how to write a Kickstart file is to start from a real-world example, and analyze the various sections and commands used in it. For the sake of this tutorial we will take a look at a Kickstart file which can be used to install a Fedora Workstation system. Here it is in its entirety:

url --mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch
repo --name=rpmfusion-free --mirrorlist=https://mirrors.rpmfusion.org/metalink?repo=free-fedora-$releasever&arch=$basearch
rootpw --lock
user --groups=wheel --name=tux --password=$6$fz9G6LVJIRHXk39j$IKgBBqkj9RQBWz8MylDWwViuREVTCIBwuxLEAeY0A6yniK2FIWBZDr9lH5YbUBidmBtqKR5CLA0h9AigOucCT/ --iscrypted --gecos="tux"

lang en_US.UTF-8
keyboard --vckeymap=us --xlayouts=us
timezone Europe/Rome --utc

network --hostname=linuxconfig --device=eth0 --bootproto=dhcp --noipv6 --activate --onboot=yes
xconfig --startxonboot

ignoredisk --only-use=/dev/vda
clearpart --all --initlabel --drives=vda
part /boot/efi --fstype=efi  --ondisk=/dev/vda --size=550 --fsoptions="umask=0077,shortname=winnt"
part /boot     --fstype=ext2 --ondisk=/dev/vda --size=1024
part pv.0 --fstype=lvmpv --ondisk=/dev/vda --grow
volgroup linuxconfig_vg pv.0
logvol /     --fstype=ext4 --vgname=linuxconfig_vg --name=root_lv --size=15360
logvol /home --fstype=ext4 --vgname=linuxconfig_vg --name=home_lv --percent=95
bootloader --location=mbr --boot-drive=/dev/vda

%packages
@workstation-product-environment
-gnome-boxes
%end

Setting the installation source

In the kickstart file above, as a first thing, we defined the installation source. The installation source can be either “local” (a cdrom, for example) or remote, (an installation tree), accessed via one of the supported protocols, such as ftp or http. The latter is exactly what we used in the example:

url --mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch

With the url command we specified we want to use a remote installation source. We passed the URL of the file containing the list of the available mirrors as argument to the --mirrorlist option. The $releasever and $basearch variables in the URL are expanded respectively to the Fedora version (e.g. 37) and the system architecture. As an alternative, we could use a specific mirror directly, by passing its URL as argument to the --url option.

Using additional repositories during the installation

The second line in the kickstart file we used in the example is the following:

repo --name=rpmfusion-free --mirrorlist=https://mirrors.rpmfusion.org/metalink?repo=free-fedora-$releasever&arch=$basearch

The repo command is optional: it is used to specify additional repositories to be used during the installation. In the example we added the RPMFusion repository as a software source; it contains packages which, for a reason or another, are not available in the official Fedora repositories, such as VLC, for example. We used the mandatory --name option to specify the repository ID and, --mirrorlist to specify the URL of the file containing a list of the repository mirrors.

A repository defined as we did in the example would only be available during the installation: to enable it also on the installed system we need to add the --install option.

Another interesting option we may want to use when specifying an additional repository is --cost. The option takes an integer as a value, and is used to define the installation priority. This is useful when a package is available from more than one software source: a lower cost means an higher priority.

Managing system users

In the example above we used two commands to manage users in the newly installed system:

  1. rootpw
  2. user

The first command. rootpw is mandatory: it is used to setup the password of the root user. In this case, we passed the --lock option to the command, which, as you can imagine, is used to lock the password, in order to disable direct root login:

rootpw --lock



Next, we added a non-privileged user to the system, via the user command, using the --groups--name--password--iscrypted and --gecos options:

user --groups=wheel --name=tux --password=$6$fz9G6LVJIRHXk39j$IKgBBqkj9RQBWz8MylDWwViuREVTCIBwuxLEAeY0A6yniK2FIWBZDr9lH5YbUBidmBtqKR5CLA0h9AigOucCT/ --iscrypted --gecos="tux"

The --name option is used to specify the account username and is required. The --groups option, instead, accepts a comma-separated list of the groups the user should be member of. In this case we made the user part of the wheel group, in order to make it able to escalate privileges using sudo.

The --password and --iscrypted options are related. The former is used to provide the user password, the latter to specify it should be assumed to be already encrypted (the opposite of this option is --plaintext). Using an already encrypted password is useful in case we need to somehow share the Kickstart file or putting it under version control. There are various methods we can encrypt a password and obtain the string to place in the file. One option is to use the pwkickstart utility; it takes a password as argument and returns its md5, sha256 and sha512 encrypted versions (the latter is the one we want):

$ pwkickstart mypassword
$1$shCWoE7t$eY546wqr/rrsaUugnvBbs0
$5$pmMb0I1fhyddIHJV$y9lmRW02wpSTxNzAoEh4qljlPBD1jCXulLDgTyvq1v9
$6$77bw2sxFQAU3Ejtw$DBj5IKCU3pw3sAH.XdGCalwqdIH/Nss7NVMnc6a9CbJyevo8BVPU3DFquqQvSzloQVjgfo0Z0YUSDDaZ.z.Tl1

The last option we used is --gecos: it is needed to provide additional user information such as his/her real name. Those information are stored in the fifth field of each line in the /etc/passwd file:

tux:x:1000:1000:tux:/home/tux:/bin/bash

Locale, keyboard and timezone settings

Another, very important part of the system configuration/installation is the localization. In the example we used three directives to setup the system language, the keyboard layout and the system timezone; they are respectively: langkeyboard and timezone.

The lang directive sets both the language to use during the installation, and the system language. It takes the language id as argument:

lang en_US.UTF-8

The keyboard directive is used to set the system keyboard layout. You can see we used two options: --vckeymap and --xlayouts, passing “us” as argument to both:

keyboard –vckeymap=us –xlayouts=us

The former is used to set the console keymap, the latter to set the keyboard layout for the graphical server. Finally, with the timezone directive we set the system timezone:

timezone Europe/Rome --utc

With the --utc option we specified that the system clock is set to UTC.

Disk partitioning and bootloader installation

Disk partitioning is probably the most crucial aspect of a system installation. Using the Kickstart file in the example results in the creation of two standard partitions (the EFI partition, and a dedicated “boot” partition), and the installation of the rest of the system on a LVM (Logical Volume Manager) layout. As a first thing, we used the ignoredisk command:

ignoredisk --only-use=/dev/vda



This command is used as a safety measure, to specify what disks the anaconda installer has access to. We can implement two strategies here: either pass the comma-separated list of excluded drives as argument to the --drives option, or as we did in the example, do the inverse, and pass the list of the accessible disks as argument to the --only-use option.

What we did in the example, was basically allowing the installer to access only the /dev/vda disk. In this case we identified the disk with the name assigned to the kernel, since it is the only one available. On a real-world scenario, it is preferable to use unique identifiers such as UUID or PATH, instead, since they are predictable (the kernel assigns device names in detection order).

Wiping existing partitions

The next command we used is clearpart:

clearpart --all --initlabel --drives=vda

This command is used to wipe all existing partitions from the specified disk(s), before the new ones are created. With the --all options we specified we want to wipe all existing partitions (by using --linux, instead, we would have instructed the installer to remove only “linux” partitions).

The --initlabel option is used to initialize the disk with a MBR or GPT partition label, depending on the architecture and the way we booted the installer (UEFI or BIOS). Finally, --drives is used to specify on what drives the partitions should be cleared.

Creating partitions and the LVM setup

As a next step, we defined the actual partitions and logical volumes. Since we want to install the system in UEFI mode, with a GPT partition schema, we need to create an EFI partition. The command used to create a standard partition is part:

part /boot/efi --fstype=efi  --ondisk=/dev/vda --size=550 --fsoptions="umask=0077,shortname=winnt"



The first argument passed to the command is the mountpoint of the partition that will be created. It can either be an actual filesystem path, or some “special” value like “swap” (used for swap partitions), or pv.<id> for LVM physical volumes.

The --fstype option is used to specify the filesystem that should be created on the partition. In this case “efi” is not the filesystem type per-se, but tells the system we want to create an EFI partition.

The --ondisk option is used to specify on which disk the partition should be created. Here we used /dev/vda (to re-use an existing partition --onpart is used, instead).

The --size option is used to specify the minimum partition size in MiB. Finally, --fsoptions takes a comma separated list of mount options which is copied into the /etc/fstab file.

The second partition we created is the boot partition:

part /boot --fstype=ext2 --ondisk=/dev/vda --size=1024

The use of a separate boot partition and the ext2 filesystem on it is really not necessary, since GRUB supports both LVM and ext4, it’s just the force of habit. Next, we defined the partition to be used as LVM physical volume. Here you can notice we used lvmpv as filesystem type, and the --grow option: with it we specify that the partition should take all the available space:

part pv.0 --fstype=lvmpv --ondisk=/dev/vda --grow

With the volgroup command we created an LVM volume group. This directive takes the volume group name as first argument, and the physical volumes to be added to it as the second:

volgroup linuxconfig_vg pv.0

After the volume group, we created the logical volumes with the logvol command. This commands works similarly to part, but accepts some additional options, as for example --vgname which is needed to specify the volume group the logical volume belongs to, and --percent which can be used to specify the size of the logical volume as a percentage of the available space.

Bootloader installation

Finally, we used the bootloader command, which is needed to configure how and where the bootloader is installed:

bootloader --location=mbr --boot-drive=/dev/vda

Here we used the --location and --boot-drive options to specify that the bootloader should be installed in the mbr (actually in the EFI partition on UEFI installed systems), of the /dev/vda drive.

Specifying the package list

By using Kickstart, we can specify, in detail, the packages which should be installed in the new system, and those which should be excluded. We list packages inside the %packages section, one per line. The section must be closed with the %end tag:

%packages
@workstation-product-environment
-gnome-boxes
%end



In this example, you can see we explicitly included the @workstation-product-environment package group (a group is identified by a @ in front of the name), and we excluded the gnome-boxes package by placing the - sign before its name.

The %pre and %post sections

Let’s talk about two sections we didn’t use in our example: %pre and %post: these sections inside a Kickstart file can be very useful, since in them we can perform custom actions using one of the available scripting language on the system (Bash is the default). Both sections must be closed with an %end tag, but are executed in different stages of the installation. The %pre section is executed before the installation begins, just after the Kickstart file has been parsed; the %post section, instead, is executed after the installation is complete. The commands we execute in it, run in the installed system, in chroot.

Passing the Kickstart file to the installer

Once our Kickstart file is ready, we must tell the installer where to find it. We do this via the inst.ks boot option. We can, for example, make the Kickstart file available online, than point the installer to it as we did below (we saved the file as test.ks):

Using the inst.ks boot option to reference the kickstart file
Using the inst.ks boot option to reference the Kickstart file

Conclusions

In this tutorial we learned the Kickstart basics. We saw how to use the appropriate commands to set the installation source, add extra repositories, set the system locale and define a partition layout. We also saw how to specify what packages should be installed and talked about the %pre and %post sections which can be used to script custom actions, performed before the installation starts, and after it is completed, respectively. Finally, we saw an example of how to pass the Kickstart file to the Anaconda installer. For the complete list of Kickstart commands please take a look at the official documentation.



Comments and Discussions
Linux Forum