Technical Theory

Creating Kubernetes Clusters with Kubeadm

Introduction

This tutorial guides you through creating a Kubernetes cluster using kubeadm. kubeadm simplifies the process of bootstrapping a minimal viable Kubernetes cluster. This tutorial assumes you have a basic understanding of Kubernetes concepts and access to at least two virtual machines (VMs) or physical machines, one for the master node and one or more for worker nodes. You will need ssh access to all machines.

Prerequisites:

  • At least two machines (VMs or physical). One will be the master, and the others will be worker nodes.
  • Each machine should have at least 2 CPUs and 2 GB of RAM.
  • A stable network connection between all machines.
  • Internet access for downloading packages.
  • Root privileges on all machines.
  • Familiarity with basic Linux commands.

Task 1: Preparing the Hosts

On all machines (master and worker nodes), perform the following steps:

  1. Install Container Runtime (Containerd):

    NODE_TYPE // bash
    sudo apt-get update
    sudo apt-get install -y apt-transport-https ca-certificates curl
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update
    sudo apt-get install -y containerd
    This tutorial uses containerd as the container runtime. Docker can also be used. Ensure the chosen runtime is configured before proceeding.
    The above example is based on ubuntu. If you are using Debian use the following command: “curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg –dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg”
  2. Configure containerd:

    NODE_TYPE // bash
    sudo mkdir -p /etc/containerd
    sudo containerd config default | sudo tee /etc/containerd/config.toml
    sudo systemctl restart containerd
  3. Disable Swap: Kubernetes requires swap to be disabled.

    NODE_TYPE // bash
    sudo swapoff -a
    sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
    Disabling swap may affect system performance in memory-constrained environments. Ensure your machines have sufficient memory.
  4. Install kubeadm, kubelet, and kubectl:

    NODE_TYPE // bash
    sudo apt-get update
    sudo apt-get install -y apt-transport-https ca-certificates curl
    curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
    sudo apt-get update
    sudo apt-get install -y kubelet kubeadm kubectl
    sudo apt-mark hold kubelet kubeadm kubectl
    kubelet is the agent that runs on each node. kubeadm is the tool for cluster bootstrapping. kubectl is the command-line tool for interacting with the Kubernetes cluster. apt-mark hold prevents these packages from being automatically updated.

Task 2: Initializing the Kubernetes Master Node

Perform these steps only on the machine designated as the master node.

  1. Initialize the Kubernetes cluster:

    NODE_TYPE // bash
    sudo kubeadm init --pod-network-cidr=10.244.0.0/16
    The --pod-network-cidr flag specifies the IP address range for pods. Choose a CIDR that doesn’t conflict with your existing network.

    Keep track of the kubeadm join command output, you’ll need this to join the worker nodes later. It should look similar to:

    NODE_TYPE // output
    kubeadm join <master-ip>:<master-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>
  2. Configure kubectl:

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

    This allows you to use kubectl as a non-root user.

  3. Install a Pod Network Add-on (Calico):

    NODE_TYPE // bash
    kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml
    A pod network add-on is required for pods to communicate with each other. Calico is a popular option. Other options include Flannel, Weave Net, and Cilium.

    Wait for all pods to be in the Running state. This may take a few minutes.

    NODE_TYPE // bash
    kubectl get pods --all-namespaces

Task 3: Joining Worker Nodes

Perform these steps on each machine designated as a worker node.

  1. Join the cluster:

    Use the kubeadm join command that was output during the kubeadm init step on the master node. Replace <master-ip>:<master-port>, <token>, and <hash> with the actual values.

    NODE_TYPE // bash
    sudo kubeadm join <master-ip>:<master-port> --token <token> --discovery-token-ca-cert-hash sha256:<hash>
    If you lost the kubeadm join command, you can regenerate the token on the master node using kubeadm token create --print-join-command.

Task 4: Verifying the Cluster

Back on the master node, verify that the worker nodes have joined the cluster.

  1. Check node status:

    NODE_TYPE // bash
    kubectl get nodes

    You should see all your nodes listed, with their status as Ready.

    NODE_TYPE // output
    NAME         STATUS   ROLES           AGE   VERSION
    master-node   Ready    control-plane,master   10m   v1.27.2
    worker-node1  Ready    <none>          5m    v1.27.2
    worker-node2  Ready    <none>          5m    v1.27.2

Task 5: Deploying a Sample Application

  1. Create a deployment:

    NODE_TYPE // bash
    kubectl create deployment nginx --image=nginx
  2. Expose the deployment:

    NODE_TYPE // bash
    kubectl expose deployment nginx --port=80 --type=NodePort
  3. Get the service information:

    NODE_TYPE // bash
    kubectl get service nginx

    Look for the NodePort.

    NODE_TYPE // output
    NAME    TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
    nginx   NodePort   10.100.1.100   <none>        80:30000/TCP   1m
  4. Access the application:

    Open a web browser and navigate to http://<worker-node-ip>:<node-port> (replace <worker-node-ip> with the IP address of one of your worker nodes and <node-port> with the NodePort obtained in the previous step). You should see the default Nginx welcome page.

Conclusion

You have successfully created a Kubernetes cluster using kubeadm, joined worker nodes, and deployed a sample application. Key takeaways from this tutorial include:

  • kubeadm simplifies Kubernetes cluster bootstrapping.
  • A container runtime (like containerd) is required.
  • A pod network add-on (like Calico) is necessary for pod communication.
  • kubectl is the primary tool for interacting with the cluster.

Next Topic