Part 1: Preparing Linux Nodes for Kubernetes

Why node preparation matters
Most Kubernetes failures don’t start in Kubernetes itself; they start at the operating system level.
Unstable storage, incorrect time synchronization, broken DNS, or leftover defaults like swap can silently cause problems that are extremely difficult to debug later. Kubernetes assumes the underlying system is predictable and correctly configured.
In this part of the series, we’ll prepare Linux nodes so they are ready to run Kubernetes reliably. Nothing in this section is optional. If these steps are done correctly, the rest of the cluster setup becomes much smoother.
What we will do in this part
In this article, we will:
Create dedicated storage for Kubernetes and workloads
Disable swap permanently
Configure time synchronization (NTP)
Prepare networking and DNS for Kubernetes
Verify the system is ready for Kubernetes installation
Prerequisites
Before continuing, make sure you’ve read Part 0 – Before You Begin and that:
You have Linux nodes ready (RHEL / Rocky / Alma / CentOS Stream–like OR Ubuntu/Debian based flavors)
You have root or sudo access
Storage structure is already configured (Optional if you understand the storage of your machines)
Nodes have static IPs and proper hostnames
If any of these are missing, fix them before proceeding.
Creating dedicated storage for Kubernetes
Why separate storage is important
Kubernetes nodes generate data in two very different ways:
Container runtime data (images, layers, logs)
Persistent workload data (volumes used by applications)
Mixing this data with the root filesystem is risky. Disk pressure on / can break the node, and recovering from it is painful. Separating storage makes the system easier to operate and troubleshoot.
In this guide, we’ll create:
one mount for container runtime data
one mount for persistent workloads (used later by storage systems)
1. Create required mount directories
Purpose
Create directories that will later be used as mount points for the logical volumes.
The -p flag ensures parent directories are created if they don’t already exist.
Syntax
mkdir -p <directory_1> <directory_2>
Example
mkdir -p /home/longhorn_data /home/containerd_data
2. Create a logical volume for Containerd data
Purpose
Create a logical volume (LV) of a specified size inside an existing volume group (VG).
This LV will be dedicated to Containerd storage.
Syntax
lvcreate -L <size> -n <logical_volume_name> <volume_group_name>
Example
lvcreate -L 50G -n lv_containerd_data myvg
50G → size of the logical volume
lv_containerd_data → logical volume name
myvg → existing volume group
3. Create a logical volume for Longhorn data
Purpose
Create a larger logical volume for Longhorn, which typically requires more storage for persistent volumes.
Syntax
lvcreate -L <size> -n <logical_volume_name> <volume_group_name>
Example
lvcreate -L 300G -n lv_longhorn_data myvg
4. Format the Containerd logical volume with XFS
Purpose
Format the logical volume with the XFS filesystem so it can be mounted and used.
Syntax
mkfs.xfs /dev/<volume_group>/<logical_volume>
Example
mkfs.xfs /dev/myvg/lv_containerd_data
5. Format the Longhorn logical volume with XFS
Purpose
Apply the XFS filesystem to the Longhorn logical volume.
Syntax
mkfs.xfs /dev/<volume_group>/<logical_volume>
Example
mkfs.xfs /dev/myvg/lv_longhorn_data
6. Mount the Containerd logical volume
Purpose
Attach the formatted logical volume to its directory so the OS can use it for storage.
Syntax
mount /dev/<volume_group>/<logical_volume> <mount_point>
Example
mount /dev/myvg/lv_containerd_data /home/containerd_data/
7. Mount the Longhorn logical volume
Purpose
Mount the Longhorn logical volume to its designated directory.
Syntax
mount /dev/<volume_group>/<logical_volume> <mount_point>
Example
mount /dev/myvg/lv_longhorn_data /home/longhorn_data/
8. Verify mounted filesystems
Purpose
Display disk usage and confirm that the new logical volumes are mounted correctly.
Syntax
df -h
This command shows:
Mounted filesystems
Total size
Used space
Available space
Mount points
9. Make the mounts persistent using /etc/fstab
Purpose
By default, mounts created using the mount command are not persistent and will be lost after a system reboot.
Adding entries to /etc/fstab ensures that the logical volumes are automatically mounted at boot time.
9.1 Get the UUID of the logical volumes
Purpose
Using UUIDs instead of device paths (/dev/myvg/...) is recommended because UUIDs remain consistent even if device names change.
Syntax
blkid /dev/<volume_group>/<logical_volume>
Example
blkid /dev/myvg/lv_containerd_data
blkid /dev/myvg/lv_longhorn_data
Sample output
/dev/myvg/lv_containerd_data: UUID="a1b2c3d4-e5f6-7890" TYPE="xfs"
/dev/myvg/lv_longhorn_data: UUID="f9e8d7c6-b5a4-3210" TYPE="xfs"
9.2 Add entries to /etc/fstab
Purpose
Define how and where each filesystem should be mounted during boot.
Syntax:
UUID=<uuid> <mount_point> <filesystem_type> <options> <dump> <fsck>
Example:
UUID=a1b2c3d4-e5f6-7890 /home/containerd_data xfs defaults 0 0
UUID=f9e8d7c6-b5a4-3210 /home/longhorn_data xfs defaults 0 0
Field breakdown
Field | Description |
|---|---|
UUID | Unique identifier of the filesystem |
Mount point | Directory where the filesystem will be mounted |
Filesystem type |
|
Options |
|
Dump | Usually |
Fsck |
|
9.3 Validate /etc/fstab entries
Purpose
Verify that all /etc/fstab entries are correct without rebooting.
This step helps prevent boot failures caused by misconfigured fstab entries.
Syntax
mount -a
Example
mount -a
If the command returns no output, the configuration is valid.
9.4 Confirm persistent mounts
Purpose
Ensure that the logical volumes are mounted as expected.
Syntax
df -h | grep -E "containerd_data|longhorn_data"
10. Disabling swap (mandatory)
Why swap must be disabled
Kubernetes requires swap to be disabled so it can make reliable scheduling and memory management decisions. Leaving swap enabled can cause kubelet failures or unpredictable pod behavior.
10.1 Disable swap immediately
Purpose
Turn off all active swap devices and swap files on the system.
Syntax
swapoff -a
Expected output
(no output)
No output indicates swap was disabled successfully.
10.2 Verify current swap status
Purpose
Confirm whether any swap devices or files are still active.
Syntax
swapon --show
Expected output (swap disabled)
(no output)
Example output (swap enabled – before disabling)
NAME TYPE SIZE USED PRIO
/dev/mapper/myvg-swap partition 16G 0B -2
10.3 Remove swap entries from /etc/fstab
Purpose
Prevent swap from being automatically enabled during system boot.
Syntax (swap partition)
<swap_device> none swap sw 0 0
Example
/dev/mapper/myvg-swap none swap sw 0 0
Modified /etc/fstab entry
# /dev/mapper/myvg-swap none swap sw 0 0
Commenting out the line disables swap persistence while keeping the reference for future use.
10.4 (Optional) Disable and remove swap file
Purpose
If the system uses a swap file instead of a swap partition, it should be removed to fully disable swap.
Syntax
rm -f <swap_file>
10.5 Validate swap is fully disabled
Purpose
Confirm that swap is disabled at runtime and will remain disabled after reboot.
Syntax
free -h
Expected output sample
total used free shared buff/cache available
Mem: 32Gi 4.1Gi 22Gi 120Mi 5.9Gi 27Gi
Swap: 0B 0B 0B
The Swap row must show
0Bacross all columns.
10.6 Final safety check (recommended)
Purpose
Ensure /etc/fstab contains no invalid entries that could cause boot failures.
Syntax
mount -a
Expected output
(no output)
Any output here indicates a configuration error that should be fixed before rebooting.
The output should show 0 swap.
If swap is still present, do not continue — fix it first.
Configuring time synchronization (NTP)
Why time synchronization matters
In a Kubernetes cluster, time drift can cause:
certificate validation failures
leader election problems
confusing logs and debugging issues
All nodes must agree on time.
Configure chrony (closed or controlled environments)
We’ll be using chrony as the NTP server and client in our setup, make sure you have chronyd installed on your machine or you can install with sudo dnf install chronyd (RHEL flavors) or sudo apt install chronyd (Debian/Ubuntu flavors)
Edit the chrony configuration:
vim /etc/chrony.conf
Comment out the default pool ONLY if it is not accessible in your network premises:
This is a sample entry; your file may differ depending on your distro.
# pool 2.rhel.pool.ntp.org iburst
Add your NTP server:
server <Your NTP server> prefer
Example:
server 192.168.1.1 prefer
Enable and start chrony:
systemctl enable --now chronyd
Verify time sync
Run:
timedatectl
chronyc sources
Confirm:
NTP is enabled
A valid time source is selected
Preparing networking for Kubernetes
Firewall decision (important context)
For clarity and learning purposes, this guide intentionally disables the firewall and assumes a trusted internal network. This avoids hidden networking issues during setup.
Hardening and firewall rules can be added later once the cluster is stable.
Configure networking services
Stop and disable the firewall, enable required services, and ensure DNS consistency:
systemctl disable firewalld
systemctl stop firewalld
Enable iptables and systemd dns resolver, create a symlink for dns resolver entries:
systemctl enable --now iptables ip6tables systemd-resolved
ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf
Why this matters:
Kubernetes relies heavily on DNS
Inconsistent resolvers cause subtle failures
Node-to-node traffic must not be blocked
Verify networking readiness
Check:
Nodes can ping each other by IP and hostname
/etc/resolv.confpoints to systemd-resolvedDNS resolution works consistently
Do not proceed until networking is clean.
Final system checks before Kubernetes
Before moving on, verify all of the following:
Swap is disabled
Storage mounts are present and persistent
Time synchronization is active
Firewall is disabled
DNS resolution works
Node has been rebooted after changes
If any check fails, fix it now — not later.
What’s next
In Part 2, we will install and configure the container runtime (containerd) along with essential node-level tooling. This is the foundation Kubernetes will run on, and correctness here is critical.






