Automate CentOS and RHEL installation with PXE
Pushbutton
Extensive frameworks for Puppet, Chef, Ansible, and Salt are found in many setups for both automation and configuration. What happens once a system is installed and accessible over SSH is clearly defined by these frameworks, so how do you convince a computer to transition to this state? Several tool suites deal with the topic of bare metal deployment in different ways; the installation of the operating system, then, is part of a large task package that the respective software processes, as if by magic.
Not everyone wants the overhead of such solutions, but that doesn't mean you have to sacrifice convenience. Linux systems can usually be installed automatically by onboard resources, without a framework or complex abstraction. In this article, I show how Red Hat Enterprise Linux (RHEL, and by analogy CentOS) can be installed automatically by the normal tools of a Linux distribution with a preboot execution environment (PXE). All of the tasks in the deployment chain are addressed.
Initial State
To install the other systems automatically, you clearly require something like a manually installed nucleus. These systems are often referred to as bootstrap nodes or cluster workstations. Essentially, this is all about the infrastructure that enables the automatic installation of Red Hat or CentOS, although it does not include as many services as you might expect. All that is really needed is working name resolution, DHCP, trivial FTP (TFTP), and an HTTP server that provides the required files. If desired, Chrony or Ntpd can be added so that the freshly rolled out servers have the correct time.
In this article, I assume that all services for the operation of an automatic installation framework are running on one system. Ideally, this is a virtual machine (VM) that runs on a high-availability cluster for redundancy reasons. This setup can be easily realized on Linux with onboard resources by a distributed replicated block device (DRBD) and Pacemaker. Both tools are available for CentOS. DRBD and Pacemaker are discussed elsewhere [1] [2], so this part of the setup is left out here: It is not absolutely necessary anyway. If you can live with the fact that the deployment of machines does not work if the VM with the necessary infrastructure fails, you do not need to worry about high availability at this point.
The basis for the system offering bootstrap services for newly installed servers is CentOS in the latest version from the 8.x branch, but the work shown here can be done with RHEL, as well.
Installing Basic Services
As the first step, you need to install CentOS 8 and set it up to suit your requirements, including, among other things, storing an SSH key for your user account and adding it to the wheel
group on the system so that the account can use sudo
. Additionally, Ansible should be executable on the infrastructure node. Although the operating system of the bootstrap system cannot be installed automatically, nothing can prevent you from using Ansible for rolling out the most important services on this system itself to achieve reproducibility.
Assume you have a CentOS 8 system with a working network configuration, a user who can log in over SSH and use sudo
, and Ansible, so that the command ansible-playbook
can be executed. To use Ansible, the tool expects a specific structure in your local directory, so the next step is to create a folder named ansible/
in the home directory and then, below this folder, the roles/
, group_vars/
, and host_vars/
subfolders.
You also need to create in an editor an inventory for Ansible. For this purpose, create the hosts
file with the content:
[infra] <full_hostname_of_the_Ansible_system> ansible_host=<Primary_IP_of_the_system> ansible_user=<login_name_of_admin_user> ansible_ssh_extra_args='-o StrictHostKeyChecking=no'
The entire entry after [infra]
must be one long line. You can check whether this works by calling
ansible -i hosts infra -m ping
If Ansible then announces that the connection is working, everything is set up correctly.
Configure DHCP and TFTP
Your next steps are to get the required services running on the infrastructure VM. DHCP, TFTP, and Nginx are all it takes to deliver all the required files to requesting clients.
Of course, you can find ready-made Ansible roles for CentOS- and RHEL-based systems that set up DHCP and TFTP, and I use two roles from Dutch developer Bert van Vreckem, because they work well and can be launched with very little effort (Figure 1). In the roles/
subfolder check out the two Ansible modules from Git (installed with dnf -y install git
):
VM> cd roles VM> git clone https://github.com/bertvv/ansible-role-tftp bertvv.tftp VM> git clone https://github.com/bertvv/ansible-role-dhcp bertvv.dhcp
In the file host_vars/-<Hostname_of_infrastructure_system>.yml
, save the configuration of the DHCP server as shown in Listing 1. It is important to get the hostname exactly right. If the full hostname of the system is infrastructure.cloud.internal
, the name of the file must be infrastructure.cloud.internal.yml
. Additionally, the values of the subnet configured in the file, the global address of the broadcast, and the address of the PXE boot server need to be adapted to the local conditions.
Listing 1
Host Variables
dhcp_global_domain_name: cloud.internal dhcp_global_broadcast_address: 10.42.0.255 dhcp_subnets: - ip: 10.42.0.0 netmask: 255.255.255.0 domain_name_servers: - 10.42.0.10 - 10.42.0.11 range_begin: 10.42.0.200 range_end: 10.42.0.254 ntp_servers: - 10.42.0.10 - 10.42.0.11 dhcp_pxeboot_server: 10.42.0.12
The subnet must be a subrange of the subnet where the VM with the infrastructure services itself is located. However, when configuring the range, you need to make sure the addresses that the DHCP server assigns to requesting clients do not collide with IPs that are already in use locally. It is also important that the value of dhcp_pxeboot_server
reflects the IP address of the infrastructure VM (Figure 2); otherwise, downloading the required files over TFTP will fail later.
TFTP is far less demanding than DHCP in terms of its configuration. Bert van Vreckem's module comes with meaningfully selected defaults for CentOS and sets up the TFTP server such that its root directory resides in /var/lib/tftpboot/
, which is in line with the usual Linux standard.
As soon as the two roles are available locally and you have stored a configuration for DHCP in the host variables, you need to create an Ansible playbook that calls both roles for the infrastructure host. In the example, the playbook is:
- hosts: infra become: yes roles: - bertvv.dhcpd - bertvv.tftp
Basically, for the Playbooks added in this article, you need to add a new line with the appropriate value to the entries in roles
. The role's name matches that of the folder in the roles/
directory (Figure 3).
Buy this article as PDF
(incl. VAT)