Skip to content

Deploying a Kubernetes Cluster on Fedora CoreOS with CRI-O

Last updated on July 26, 2024

Immutable systems, such as Fedora CoreOS, are designed for minimal changes and higher reliability. Fedora CoreOS is a Linux distribution optimized for containerized workloads, providing an immutable and minimal operating system for secure and scalable deployments.

In this post, we’ll walk through setting up Fedora CoreOS, configuring an SSH key, installing necessary tools like Butane, and setting up a Kubernetes cluster with CRI-O as the container runtime.

Generating an SSH Key

First, generate an SSH key to access your Fedora CoreOS system.

ssh-keygen -t rsa

You will be prompted to save the key in a file. The output will look like this:

Enter file in which to save the key (/home/user/.ssh/id_rsa):
Your identification has been saved in /home/user/.ssh/id_rsa.
Your public key has been saved in /home/user/.ssh/id_rsa.pub.
The key fingerprint is:
476:b2:a8:7f:08:b4:c0:af:81:25:7e:21:48:01:0e:98 user@localhost

The key's randomart image is:

+--[ RSA 2048]----+
|+.o.             |
|ooE              |
|oo               |
|o.+..            |
|.+.+..  S .      |
|....+  o +       |
|  .o ....        |
|  .  .. .        |
|    ....         |
+-----------------+

You can view your public key with:

cat ~/.ssh/id_rsa.pub

Installing Butane

Butane converts human-readable Butane Configs into machine-readable Ignition Configs. Install Butane using the appropriate method for your operating system:

On Fedora:

sudo dnf install -y butane

On macOS via Homebrew:

brew install butane

On macOS via MacPorts:

sudo port install butane

On Windows via Scoop:

scoop bucket add extras
scoop install butane

On Windows via winget:

winget install --id Fedora.CoreOS.butane

Creating the Butane Config

Create a Butane config file named config.bu and replace the SSH key with your own:

variant: fcos
version: 1.5.0
passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - ssh-rsa AAAAB3NzaC1......

Convert this Butane config into an Ignition config:

butane --pretty --strict config.bu > config.ign

The resulting config.ign will look like this:

{
  "ignition": {
    "version": "3.4.0"
  },
  "passwd": {
    "users": [
      {
        "name": "core",
        "sshAuthorizedKeys": [
          "ssh-rsa AAAAB3NzaC1yc2EAAAA....."
        ]
      }
    ]
  }
}

Installing Fedora CoreOS on VMware ESXi

Deploy OVF Template: Choose “Deploy OVF Template” and select your downloaded template or download via URL.

Set Name and Folder: Name your VM and select a folder.

Select Compute Resource: Choose your compute resource.

Review Details: Review the details of your deployment.


Select Storage: Choose your storage option.

Select Networks: Configure your network settings.

Customize Template: Paste the content of config.ign into the “Inline Ignition config data” field.


Complete Installation: Press “Finish” to start the installation. Once complete, the screen will show something similar to this:


You can log in to the new system using:

ssh core@ip_address

Installing CRI-O and Configuring the Network

Install CRI-O and additional tools:

rpm-ostree install cri-o open-vm-tools htop

Reboot to ensure the packages are loaded:

systemctl reboot

Load necessary kernel modules:

cat <<EOF > /etc/modules-load.d/crio-net.conf
overlay
br_netfilter
EOF

Set up network settings:

cat <<EOF > /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

sysctl --system

Installing Kubernetes Tools

Configure the Kubernetes repository:

cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/v1.30/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.30/rpm/repodata/repomd.xml.key
EOF

Install Kubernetes tools on the control plane node:

rpm-ostree install kubelet kubeadm kubectl

Reboot and set SELinux to permissive mode:

systemctl reboot
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

Enable and start CRI-O and kubelet:

systemctl enable --now cri-o
systemctl enable --now kubelet

Set the correct cgroup driver for kubelet:

echo "KUBELET_EXTRA_ARGS=--cgroup-driver=systemd" | tee /etc/sysconfig/kubelet

Creating the Kubernetes Cluster

Create a clusterconfig.yml file on the control plane:

apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.30.0
controllerManager:
  extraArgs:
    flex-volume-plugin-dir: "/etc/kubernetes/kubelet-plugins/volume/exec"
networking:
  podSubnet: 10.244.0.0/16
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration

Initialize the cluster:

kubeadm init --config clusterconfig.yml

Configure kubectl on the control plane:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Set up pod networking with kube-router:

kubectl apply -f https://raw.githubusercontent.com/cloudnativelabs/kube-router/master/daemonset/kubeadm-kuberouter.yaml

Adding Worker Nodes

On worker nodes, install CRI-O, kubelet, and kubeadm:

sudo rpm-ostree install kubelet kubeadm cri-o
sudo systemctl enable --now crio kubelet

Change the hostname:

vi /etc/hostname  # Add your hostname

Join the worker nodes to the cluster using the join command from the control plane. If lost, generate it with:

kubeadm token create --print-join-command

Deploying Metrics Server

To test the cluster, deploy the metrics server:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

You should see the metrics server deployed on node1 as intended.

Allowing Master Node to Schedule Pods

To allow the master node to schedule pods (which is disabled by default for security reasons):

kubectl describe nodes | grep -i taints

kubectl taint nodes --all node-role.kubernetes.io/control-plane-

To disable scheduling on control plane or any other node

kubectl taint nodes --all node-role.kubernetes.io/control-plane:NoSchedule

And there you have it—a fully configured Kubernetes cluster on Fedora CoreOS with CRI-O!

Published inKubernetesLinuxOtherSecurity