# Create Kubernetes Cluster with CRI-O on Rocky Linux 9.1

# Overview

As a container orchestration, Kubernetes help anyone who needs to deploy a container service in a declarative way. Kubernetes will manage and maintain every resource to meet the state needed by the developer. Developer simply defined the desired state by JSON or YAML file and sends it to Kubernetes API. In this article, I will guide you to deploy a Kubernetes cluster with CRI-O as container runtime on RHEL-based OS, Rocky Linux 9.1.

# Installation

## Pre-requisites

We need 1 node for the control-plane node and at least 1 node or more nodes for the worker node with the specifications:

* Control-plane node:
    
    * 2 core or more processor
        
    * 2 GB or more memory
        
    * Rocky Linux 9
        
* Worker node:
    
    * 4 core or more processor
        
    * 8 GB or more memory
        
    * Rocky Linux 9
        

## Steps

### Master Node

1. Configure firewall on every node
    
    You need to set firewall rules on the node(s) to open several inbound ports or connections between the Kubernetes cluster node based on [Kubernetes Documentation](https://kubernetes.io/docs/reference/networking/ports-and-protocols/).
    
    ```bash
    firewall-cmd --permanent --new-zone=kubernetes-master
    firewall-cmd --permanent --zone=kubernetes-master --add-service=ssh
    firewall-cmd --permanent --zone=kubernetes-master --add-port={6443,2379,2380,10250,10259,10257}/tcp
    firewall-cmd --reload
    firewall-cmd --permanent --zone=kubernetes-master --change-interface=enp1s0
    firewall-cmd --set-default-zone=kubernetes-master
    ```
    
2. Setup CRI-O
    
    CRI-O repository will be added to YUM depending Kubernetes version want to be installed by specifying the `VERSION` environment variable.
    
    ```bash
    export VERSION=1.26
    export OS=CentOS_8_Stream
    curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo
    yum install cri-o -y
    systemctl enable --now crio
    ```
    
3. Setup kubeadm, kubelet, and kubectl
    
    Kubernetes’ repository will be added to YUM and install kubelet, kubectl and kubeadm following the version of Kubernetes want to installed. See [Kubernetes Releases](https://kubernetes.io/releases/).
    
    ```bash
    cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
    [kubernetes]
    name=Kubernetes
    baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
    enabled=1
    gpgcheck=1
    gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
    exclude=kubelet kubeadm kubectl
    EOF
    # Set SELinux in permissive mode (effectively disabling it)
    sudo setenforce 0
    sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
    yum install kubelet-1.26.5 kubectl-1.26.5 kubeadm-1.26.5 --disableexcludes=kubernetes
    ```
    
4. Configure prerequisites
    
    ```bash
    cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
    overlay
    br_netfilter
    EOF
    
    modprobe overlay
    modprobe br_netfilter
    
    # sysctl params required by setup, params persist across reboots
    cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
    net.bridge.bridge-nf-call-iptables  = 1
    net.bridge.bridge-nf-call-ip6tables = 1
    net.ipv4.ip_forward                 = 1
    EOF
    
    # Apply sysctl params without reboot
    sysctl --system
    ```
    
5. Create kubeadm’s and InitConfiguration and ClusterConfiguration file for master node
    
    ```bash
    vim kubeadm-worker-conf.yaml
    ```
    
    ```yaml
    apiVersion: kubeadm.k8s.io/v1beta3
    kind: InitConfiguration
    nodeRegistration:
     name: "master-node0"
     criSocket: "/var/run/crio/crio.sock"
    ---
    apiVersion: kubeadm.k8s.io/v1beta3
    kind: ClusterConfiguration
    networking:
     serviceSubnet: "10.10.0.0/16"
     podSubnet: "10.10.10.0/24"
     dnsDomain: "jesaya.lab"
    kubernetesVersion: "v1.26.5"
    controlPlaneEndpoint: "[control-plane-ip]:6443"
    clusterName: "[cluster-name]"
    ```
    
6. Initialize Kubeadm
    
    ```bash
    systemctl enable kubelet.service
    kubeadm init --config kubeadm-cluster-conf.yaml
    ```
    
7. Check the Kubernetes has been initilized
    
    ```bash
    mkdir -p $HOME/.kube
    cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    chown $(id -u):$(id -g) $HOME/.kube/config
    kubectl get node
    ```
    

### Worker node(s)

1. Configure firewall on every node
    
    You need to set firewall rules on the node(s) to open several inbound ports or connections between the Kubernetes cluster node based on [Kubernetes Documentation](https://kubernetes.io/docs/reference/networking/ports-and-protocols/).
    
    ```bash
    firewall-cmd --permanent --new-zone=kubernetes-worker
    firewall-cmd --permanent --zone=kubernetes-worker --add-service=ssh 
    firewall-cmd --permanent --zone=kubernetes-worker --add-port={10250,30000-32767}/tcp
    firewall-cmd --reload
    firewall-cmd --permanent --zone=kubernetes-worker --change-interface=enp1s0
    firewall-cmd --set-default-zone=kubernetes-worker
    ```
    
2. Setup CRI-O
    
    CRI-O repository will be added to YUM depending Kubernetes version want to be installed by specifying the `VERSION` environment variable.
    
    ```bash
    export VERSION=1.26
    export OS=CentOS_8_Stream
    curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/devel:kubic:libcontainers:stable:cri-o:$VERSION.repo
    yum install cri-o -y
    systemctl enable --now crio
    ```
    
3. Setup kubeadm, kubelet, and kubectl
    
    Kubernetes’ repository will be added to YUM and install kubelet, kubectl and kubeadm following the version of Kubernetes want to installed. See [Kubernetes Releases](https://kubernetes.io/releases/).
    
    ```bash
    cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
    [kubernetes]
    name=Kubernetes
    baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
    enabled=1
    gpgcheck=1
    gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
    exclude=kubelet kubeadm kubectl
    EOF
    # Set SELinux in permissive mode (effectively disabling it)
    sudo setenforce 0
    sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
    yum install kubelet-1.26.5 kubeadm-1.26.5 --disableexcludes=kubernetes
    ```
    
4. Configure prerequisites needed on node
    
    ```bash
    cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
    overlay
    br_netfilter
    EOF
    
    modprobe overlay
    modprobe br_netfilter
    
    # sysctl params required by setup, params persist across reboots
    cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
    net.bridge.bridge-nf-call-iptables  = 1
    net.bridge.bridge-nf-call-ip6tables = 1
    net.ipv4.ip_forward                 = 1
    EOF
    
    # Apply sysctl params without reboot
    sysctl --system
    ```
    
5. Create kubeadm’s JoinConfiguration file for worker node
    
    ```bash
    vim kubeadm-worker-conf.yaml
    ```
    
    ```yaml
    apiVersion: kubeadm.k8s.io/v1beta3
    kind: JoinConfiguration
    nodeRegistration:
     name: "worker-node0"
     criSocket: "/var/run/crio/crio.sock"
    discovery: 
      bootstrapToken: 
        token: "[bootstrap-token]"
        apiServerEndpoint: "[control-plane-ip]:6443"
        caCertHashes: 
        - "[CA-cert-Hash]"
    ```
    
6. Joining worker node
    
    ```bash
    systemctl enable kubelet.service
    kubeadm join --config kubeadm-worker-conf.yaml
    ```
