Kubernetes Cluster On VirtualBox: A Step-by-Step Guide

by Team 55 views
Kubernetes Cluster on VirtualBox: A Step-by-Step Guide

Setting up a Kubernetes cluster on VirtualBox is a fantastic way to learn about Kubernetes, test deployments, or even run small-scale applications in a local environment. This comprehensive guide will walk you through the entire process, from installing VirtualBox and setting up your virtual machines to deploying your first application on your brand-new Kubernetes cluster. Let's dive in, guys!

Prerequisites

Before we get started, make sure you have the following:

  • VirtualBox: Download and install the latest version of VirtualBox from the official website.
  • Vagrant: Vagrant will help us automate the creation and configuration of our virtual machines. Grab it from the Vagrant website.
  • kubectl: This is the Kubernetes command-line tool that allows you to interact with your cluster. You can download it from the Kubernetes website or use a package manager like apt or brew.
  • Basic understanding of Kubernetes concepts: Familiarize yourself with pods, deployments, services, and namespaces. It will make the process a lot smoother. Don't worry if you're a beginner, we will guide you, but having some basic knowledge definitely helps!

Step 1: Install VirtualBox and Vagrant

This step is pretty straightforward. Just download the installers from the official websites of VirtualBox and Vagrant and follow the on-screen instructions. Once installed, verify that they are working correctly by opening a terminal and running the following commands:

vboxmanage --version
vagrant --version

You should see the version numbers of both VirtualBox and Vagrant printed in the terminal. If you don't, double-check that they are correctly installed and that their executables are in your system's PATH.

Step 2: Create a Vagrantfile

The Vagrantfile is the heart of our setup. It defines the virtual machines that will make up our Kubernetes cluster. Create a new directory for your project and create a file named Vagrantfile inside it. Here's an example Vagrantfile that creates three virtual machines: one master node and two worker nodes:

Vagrant.configure("2") do |config|
  # Configure the master node
  config.vm.define :master do |master|
    master.vm.box = "ubuntu/focal64" # Use Ubuntu 20.04
    master.vm.hostname = "k8s-master"
    master.vm.network "private_network", ip: "192.168.56.10"
    master.vm.provider "virtualbox" do |vb|
      vb.name = "k8s-master"
      vb.memory = "2048" # 2GB RAM
      vb.cpus = 2
    end

    master.vm.provision "shell", inline: <<-SHELL
      sudo apt-get update
      sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
      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 docker-ce docker-ce-cli containerd.io
      sudo apt-get update
      sudo apt-get install -y kubelet kubeadm kubectl
      sudo apt-mark hold kubelet kubeadm kubectl
      sudo kubeadm config images pull
      sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.56.10
      mkdir -p $HOME/.kube
      sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
      sudo chown $(id -u):$(id -g) $HOME/.kube/config
      kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    SHELL
  end

  # Configure the worker nodes
  (1..2).each do |i|
    config.vm.define "worker-#{i}" do |worker|
      worker.vm.box = "ubuntu/focal64" # Use Ubuntu 20.04
      worker.vm.hostname = "k8s-worker-#{i}"
      worker.vm.network "private_network", ip: "192.168.56.1#{i}"
      worker.vm.provider "virtualbox" do |vb|
        vb.name = "k8s-worker-#{i}"
        vb.memory = "1024" # 1GB RAM
        vb.cpus = 1
      end

      worker.vm.provision "shell", inline: <<-SHELL
        sudo apt-get update
        sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
        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 docker-ce docker-ce-cli containerd.io
        sudo apt-get update
        sudo apt-get install -y kubelet kubeadm kubectl
        sudo apt-mark hold kubelet kubeadm kubectl
        sudo kubeadm config images pull
        sudo kubeadm join 192.168.56.10:6443 --token <YOUR_TOKEN> --discovery-token-ca-cert-hash sha256:<YOUR_HASH>
      SHELL
    end
  end
end

Explanation of the Vagrantfile:

  • Vagrant.configure("2") do |config|: This line specifies that we're using Vagrant version 2.
  • config.vm.define :master do |master|: This defines the configuration for the master node. We name it :master.
  • master.vm.box = "ubuntu/focal64": This specifies the base image for the virtual machine. We're using Ubuntu 20.04 (Focal Fossa). You can choose other images if you prefer.
  • master.vm.hostname = "k8s-master": Sets the hostname of the master node.
  • master.vm.network "private_network", ip: "192.168.56.10": Configures a private network for the virtual machine with a static IP address. Make sure this IP address is within a range that doesn't conflict with your existing network.
  • master.vm.provider "virtualbox" do |vb|: Specifies VirtualBox as the provider.
  • vb.name = "k8s-master": Sets the name of the virtual machine in VirtualBox.
  • vb.memory = "2048": Allocates 2GB of RAM to the master node. Adjust this based on your system's resources. 2GB is a minimum recommendation.
  • vb.cpus = 2: Assigns 2 CPUs to the master node. Again, adjust based on your resources. 2 CPUs are recommended.
  • master.vm.provision "shell", inline: <<-SHELL: This section contains a shell script that will be executed on the master node after it's created. This script installs Docker, Kubernetes components (kubelet, kubeadm, kubectl), pulls necessary container images, initializes the Kubernetes cluster using kubeadm init, configures kubectl to connect to the cluster, and deploys the Flannel CNI plugin for networking.
  • (1..2).each do |i|: This loop creates two worker nodes.
  • config.vm.define "worker-#{i}" do |worker|: Defines the configuration for each worker node.
  • The worker node configuration is similar to the master node, but with some key differences: It has a different hostname, IP address, less memory (1GB), and the shell script joins the existing Kubernetes cluster using kubeadm join. You'll need to replace <YOUR_TOKEN> and <YOUR_HASH> with the values generated by kubeadm init on the master node.

Important:

  • Replace <YOUR_TOKEN> and <YOUR_HASH> in the worker node's shell script with the actual token and hash generated by kubeadm init on the master node. You'll get these values after running vagrant up and the master node provisioning is complete. The kubeadm init command will output the exact kubeadm join command you need to use.
  • Adjust the memory and CPU allocations based on your system's resources. The values provided in the example are minimum recommendations.
  • Make sure the IP addresses assigned to the virtual machines are within a private network range and don't conflict with your existing network.

Step 3: Bring up the Virtual Machines

Now that we have our Vagrantfile, we can bring up the virtual machines. Open a terminal, navigate to the directory containing the Vagrantfile, and run the following command:

vagrant up

This command will download the specified Ubuntu box image (if you don't already have it), create the virtual machines in VirtualBox, and run the provisioning scripts defined in the Vagrantfile. This process can take some time, depending on your internet connection and system resources. Grab a coffee and be patient!

Step 4: Retrieve Join Command from Master Node

After vagrant up completes (and the master node provisioning script has finished), Vagrant should drop you back to your terminal. Now you need to SSH into the master node to get the join command for the worker nodes.

vagrant ssh master

Once you're logged in, run this command:

sudo kubeadm token create --print-join-command

This will output a kubeadm join command that looks something like this:

kubeadm join 192.168.56.10:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Copy this entire command. This is what you need to paste into your Vagrantfile to replace the <YOUR_TOKEN> and <YOUR_HASH> placeholders.

Exit the master node SSH session:

exit

Now, edit your Vagrantfile and replace <YOUR_TOKEN> and <YOUR_HASH> with the values from the command you just copied.

Finally, run:

vagrant reload

This will restart the VMs and run the updated provisioning scripts, joining the worker nodes to the master.

Step 5: Verify the Cluster

Once the provisioning is complete, you can verify that your Kubernetes cluster is up and running. SSH into the master node again:

vagrant ssh master

Then, run the following command:

kubectl get nodes

You should see the master node and the two worker nodes listed, with their status as Ready.

NAME         STATUS   ROLES                  AGE   VERSION
k8s-master   Ready    control-plane,master   20m   v1.28.0
k8s-worker-1 Ready    <none>                 15m   v1.28.0
k8s-worker-2 Ready    <none>                 15m   v1.28.0

If all nodes are showing as Ready, congratulations! You have successfully set up a Kubernetes cluster on VirtualBox.

Step 6: Deploy a Sample Application

Now that your cluster is up and running, let's deploy a sample application to test it out. We'll use a simple Nginx deployment.

Create a file named nginx-deployment.yaml with the following content:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: NodePort

This YAML file defines a Deployment that creates two replicas of the Nginx container and a Service that exposes the deployment on a NodePort.

Apply the deployment and service:

kubectl apply -f nginx-deployment.yaml

Check the status of the deployment:

kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   2/2     2            2           5m

Check the status of the service:

kubectl get services
NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes      ClusterIP   10.96.0.1       <none>        443/TCP        30m
nginx-service   NodePort    10.108.14.123   <none>        80:31742/TCP   5m

To access the Nginx application, open a web browser and navigate to the IP address of one of your worker nodes, followed by the NodePort (in this example, it's 31742). For example, if your worker node's IP address is 192.168.56.11, you would go to http://192.168.56.11:31742.

You should see the default Nginx welcome page! Congratulations, you've successfully deployed an application on your Kubernetes cluster!

Step 7: Cleaning Up

When you're finished with your Kubernetes cluster, you can shut down the virtual machines by running the following command in the directory containing the Vagrantfile:

vagrant halt

This will gracefully shut down the virtual machines. To completely remove the virtual machines, run:

vagrant destroy -f

Conclusion

Setting up a Kubernetes cluster on VirtualBox is a great way to learn about Kubernetes and experiment with different deployments. This guide has provided you with a step-by-step approach to creating a basic cluster with a master node and two worker nodes. From here, you can explore more advanced Kubernetes concepts, such as namespaces, deployments, services, and more. Have fun exploring the world of Kubernetes, and remember to keep learning and experimenting! Happy clustering, guys!