Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 19 20 24 30 2

Charmed Kubernetes on KVM using MAAS and Juju

Coming to this solution was a journey. I was looking for a Kubernetes installation which was easy to deploy and cleanup on my own laptop (I didn’t want to have to pay for a hosted solution). I did want a solution which was more or less production-like because I wanted to be able to play with storage solutions and deal with cluster challenges / loadbalancers. Things I couldn’t do easily on environments like Minikube and Microk8s. Also, since I was running on a single piece of hardware, I needed a virtualization technology to deploy parts of Kubernetes to different hosts. Each virtualization technology comes with its own challenges. On some of them it is difficult to get storage solutions to work, for example LXC/LXD (a Linux container technology). Some of them are Windows specific like Hyper-V and some of them just don’t perform well like VirtualBox. I also needed a solution to provide some form of automation to create/destroy/access my virtual environments. A long list of requirements and this is what I ended up with. A production-like environment which is quick to create, destroy or reset, running on my laptop with easy management tools.

Tools

Charms

Charmed Kubernetes is a pure upstream distribution of Kubernetes by Canonical (you know, the people from Ubuntu). It can be deployed using so-called Charms with a tool called Juju. Read more here. Charms consist of a definition of applications and their required resources. Using juju you can deploy charms to various environments such as AWS, Azure, OpenStack and GCP. You can also deploy locally to LXC/LXD containers or to a MaaS (Metal as a Service) solution. Juju allows easy ssh access into nodes and provides several commands to easily manage the environments. In addition, it comes with a nice GUI.

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 19 17 10 44

Virtualization technology

During my first experiments I tried deploying locally to LXC/LXD. It looked nice at first since I was able to deploy an entire Kubernetes environment using very few commands and it was quick to start/stop/rebuild. When however I tried to do more complex things like deploying StorageOS, CephFS or OpenEBS, I failed miserably. After trying many things I found out I was mainly trying to get LXC/LXD do what I want. My focus wasn’t getting to know LXC/LXD indebt but playing with Kubernetes. Since LXC/LXD isn’t a full virtualization solution (it uses the same kernel as the host, similar to Docker) it was difficult to pull the required devices with the required privileges from the host into the LXC/LXD containers and from the containers into the containerd processes. This caused different issues with the storage solutions. I decided I needed a full virtualization solution which also virtualized the node OS, thus KVM or VirtualBox (I had no intention of running on Windows so dropped Hyper-V).

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 19 16 10 20 1 2

Deployment tooling

I already mentioned I wanted an easy way to manage the virtualized environments. I started out with Vagrant but the combination of getting a production-like environment out of the box using Vagrant scripts was hard to find. Also it would require me to define all the machines myself in Vagrant code. The Kubernetes distributions I would end up with were far from production like. They were automated mostly by developers who had similar requirements as my own but those solutions were not kept up to date by a big company and shared by many users. I wanted automation like juju but not LXC/LXD. What were my options without having to pay anything for it? MaaS, Metal as a Service, was something to try out. Juju could deploy to MaaS. I found that MaaS could be configured to create KVM machines on Juju’s request! Nice, let’s use it!

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 19 16 42 11 2

My main challenge was getting networking to work. MaaS can create virtual machines in KVM using virsh. The machines boot and then they have to be supplied with software to allow management and deployment of applications. MaaS does this by ‘catching’ machines on DHCP requests and then use PXE to provide the required software. This is all automated though. You only have to provide the networking part.

Bringing it all together

I started out with a clean Ubuntu 18.04 install (desktop, minimal GUI) on bare metal. I could also have chosen for 20.04 since that has also recently been released but I thought, let’s not take any chances with the available tutorials by choosing a distribution which might contain changes which would make the tutorials fail. I think this can also be applied to 20.04 since it is not really that different compared to 18.04 but I haven’t tried.

Some preparations

First I installed some packages required for the setup. I choose to use MaaS from packages instead of Snap since I couldn’t get the connection to KVM to work with the Snap installation. The package installation created a user maas which was used to connect to the libvirt daemon to create VMs.

 sudo apt-add-repository -yu ppa:maas/stable  
 sudo apt-get update  
 sudo apt-get -y install bridge-utils qemu-kvm qemu virt-manager net-tools openssh-server mlocate maas maas-region-controller maas-rack-controller  

Configure the network

Probably the most difficult step. Part of the magic is done by using the following netplan configuration:

 sudo bash  
 cat << EOF > /etc/netplan/01-netcfg.yaml  
 network:  
  version: 2  
  renderer: NetworkManager  
  ethernets:  
   dummy:  
    dhcp4: false  
  bridges:  
   br0:  
    interfaces: [dummy]  
    dhcp4: false  
    addresses: [10.20.81.2/24]  
    gateway4: 10.20.81.254  
    nameservers:  
     addresses: [10.20.81.1]  
    parameters:  
     stp: false  
 EOF  
 netplan apply  
 exit  

This creates a bridge interface/subnet which allows the VMs to communicate with each other and with the host. The stp parameter is needed to allow PXE (the network boot solution MaaS uses) to work.

The below part creates an interface which is available in KVM for the VMs to use. It is a bridge interface to the subnet. The below commands replace the default KVM interface.

 sudo virsh net-destroy default   
 sudo virsh net-undefine default  
   
 cat << EOF > maas.xml  
 <network>   
   <name>default</name>   
   <forward mode="bridge"/>   
   <bridge name="br0"/>  
 </network>  
 EOF  
   
 virsh net-define maas.xml  
   
 virsh net-autostart default  
 virsh net-start default  

Since we’re at it, KVM also needs to have some storage defined:

 virsh pool-define-as default dir - - - - "/var/lib/libvirt/images"   
 virsh pool-autostart default   
 virsh pool-start default  

In order to allow the hosts on the subnet (your KVM virtual machines) to communicate with the internet, some iptable rules are required. In the below script replace enp4s0f1 with your interface which is connected to the internet (you can determine it from the ifconfig output)

 sudo iptables -t nat -A POSTROUTING -o enp4s0f1 -j MASQUERADE   
 sudo iptables -A FORWARD -i enp4s0f1 -o br0 -m state --state RELATED,ESTABLISHED -j ACCEPT   
 sudo iptables -A FORWARD -i br0 -o enp4s0f1 -j ACCEPT   
 echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf   
 echo 'net.ipv4.conf.br0.proxy_arp=1' | sudo tee -a /etc/sysctl.conf   
 echo 'net.ipv4.conf.br0.proxy_arp_pvlan' | sudo tee -a /etc/sysctl.conf  
   
 #For saving the iptables rules. After install the installer asks to save the current state  
 sudo apt-get install iptables-persistent  
   
 #If you want to save the state afterwards, do:  
 #sudo bash  
 #iptables-save > /etc/iptables/rules.v4  

It is a good idea to do a reboot now to make sure the state of your network is reproducible. The sysctl code is executed at boot before the br0 bridge becomes available so after a reboot, you’ll need to execute the below 3 lines. I do not have a solution for that yet.

 sudo sysctl -w net.ipv4.ip_forward=1  
 sudo sysctl -w net.ipv4.conf.br0.proxy_arp=1  
 sudo sysctl -w net.ipv4.conf.br0.proxy_arp_pvlan=1  

Also sometimes it helps (after you have already installed MAAS) to restart MAAS services such as:

 sudo service maas-rackd restart  

Maas

Next step is setting up Maas.

 sudo maas init  

This will ask you for an admin user and you can also supply an SSH key. After you’ve answered the questions, you can use the user you have created to login to:

 http://localhost:5240/MAAS  

You need to enable DHCP for the subnet you’ve created (10.20.81.0/24)

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 18 21 23 21 2
Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 18 21 24 47 1
Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 18 21 25 02 1

Also the maas OS user needs to be able to manage KVM. Add the maas user to the libvirt group:

 sudo usermod -a -G libvirt maas  

Create a public and private key for the user maas and add the public key to the maas user s authorized keys so the private key can be used to login to the maas user:

 sudo chsh -s /bin/bash maas  
 sudo su - maas  
 ssh-keygen -f ~/.ssh/id_rsa -N ''  
   
 cd .ssh  
 cat id_rsa.pub > authorized_keys  
 chmod 600 ~/.ssh/authorized_keys  

The public key needs to be registered in maas. Click on admin in the webinterface and add the SSH public key

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 19 20 49 29 3

Now maas needs to be configured to connect to KVM. Click pods and add the virsh URL: qemu+ssh://maas@127.0.0.1/system

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 18 21 26 11 2

You also installed virt-manager so you can manually create a VM and check it becomes available in MaaS (does the PXE boot and starts provisioning).

Juju

Now you have the network, KVM, MaaS configured and it’s time to move to the next step. Configure Juju.

 #Install juju  
 snap install juju --classic  
   
 #Add your MaaS cloud environment  
 juju add-cloud --local  

Use the following API endpoint:http://10.20.81.2:5240/MAAS. Do not use localhost or 127.0.0.1! This IP is also accessible from hosts on your subnet and allows Juju to manage the different hosts.

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 18 21 28 32 2

Add credentials (the MaaS user). First obtain an API key from the MaaS GUI.

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 19 20 49 29 4
 juju add-credential maas  

Bootstrap JuJu. This creates a controller environment. Juju issues its commands through this. If this step succeeds, installing Charmed Kubernetes will very likely also work. Should this fail, you can issue: juju kill-controller to start again. Do not forget to cleanup the VM in MaaS and KVM in such a case.

 juju bootstrap maas maas-controller  
Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 19 08 30 35 2

Installing Charmed Kubernetes

A full installation of Charmed Kubernetes requires quite some resources. Most likely you don have them available on your laptop. Resources like 16 cores and more than 32Gb of memory.

Charms contain a description of the applications and the resources required to run them so hosts can automatically be provisioned to accomodate for those applications. You can override the resource requirements by using a so-called overlay.

For example, the original Charm looks like this: https://api.jujucharms.com/charmstore/v5/bundle/canonical-kubernetes-899/archive/bundle.yaml

I reduced the number of workers, the number of cores available to the workers and the amount of memory used by the individual master and the worker nodes so the entire thing would fit on my laptop.

 cat << EOF > bundle.yaml  
 description: A highly-available, production-grade Kubernetes cluster.  
 series: bionic  
 applications:  
  kubernetes-master:  
   constraints: cores=1 mem=3G root-disk=16G  
   num_units: 2  
  kubernetes-worker:  
   constraints: cores=2 mem=6G root-disk=16G  
   num_units: 2  
 EOF  

Create a model to deploy Charmed Kubernetes in:

 juju add-model k8s  

Now execute the command which will take a while (~15 minutes on my laptop):

 juju deploy charmed-kubernetes --overlay bundle.yaml --trust  

This command provisions machines using MAAS and deploys Charmed Kubernetes on top.

Sometimes you end up with several machines in KVM which have not been provisioned and are turned off. You can remove these (all machines which are turned off including their storage) with a command like:

 for i in `virsh list --state-shutoff --name`; do virsh undefine $i --remove-all-storage; done  

Some housekeeping

In order to access the environment, you can do the following after the deployment has completed (you can check with juju status or juju gui)

 sudo snap install kubectl --classic  
 sudo snap install helm --classic  
   
 mkdir .kube  
 juju scp kubernetes-master/0:config ~/.kube/config  

The resulting environment

After juju is done deploying Charmed Kubernetes you will end up with an environment which consists of 8 hosts (+1 juju controller). Below is the output of juju status after the deployment has completed.

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 19 20 24 30 2

You can also browse the juju GUI. ‘juju gui’ gives you the URL and credentials required to login.

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 20 11 14 14 2

You can look in the MAAS UI to see how your cores and memory have been claimed

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 19 20 51 32 2

In virt-manager you can also see the different hosts

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 19 16 10 20 3

‘kubectl get nodes’ gives you the worker nodes.

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 20 11 11 55 2

You can enter a VM by for example ‘juju ssh kubernetes-master/0’

If this does not work because provisioning failed or the controller is not available, you can also use the juju private key directly.

 ssh -i /home/maarten/.local/share/juju/ssh/juju_id_rsa ubuntu@10.20.81.1  

You can execute commands against all nodes which provide an application:

 juju run "uname -a" kubernetes-master  
Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 20 11 27 08 2

Of course you can access the dashboard which is installed by default:

 kubectl proxy  

Next access http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/login

You can use the .kube/config to login

Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 20 11 31 05 2
Charmed Kubernetes on KVM using MAAS and Juju Screenshot from 2020 05 20 11 31 52 2

Cleaning up

If you need to cleanup, the best way to remove Charmed Kubernetes is:

 juju destroy-model k8s  

This will remove the application and the machines so you can start over if you have destroyed your Kubernetes environment. Reinstalling it can be done with the below two commands:

 juju add-model k8s   
 juju deploy charmed-kubernetes --overlay bundle.yaml --trust  

If you want to go back further and even remove juju, I recommend the following procedure:

 sudo snap remove juju --purge  
 sudo snap remove kubectl --purge  
 sudo snap remove helm --purge  
 rm -rf ~/.kube  
 rm -rf ~/.local  

References

I’ve mainly used the following sites to put the pieces of the puzzle together

https://maas.io/tutorials/create-kvm-pods-with-maas

https://ubuntu.com/kubernetes/docs/install-manual

https://oxyme.wordpress.com/2018/09/05/ubuntu-18-04-lts-maas-part-1-8/

https://juju.is/docs/maas-cloud

3 Comments

  1. Zia August 31, 2021
  2. Alp March 27, 2021
  3. Marcin October 14, 2020