This post is for me to learn how to create a highly available Kubernetes cluster using the MicroK8s and multipass.
Kubernetes clusters host containerised applications in a reliable and scalable way. Having DevOps in mind, Kubernetes makes maintenance tasks such as upgrades and security patching simple.
MicroK8s is a zero-ops, CNCF certified lightweight Kubernetes distribution for workstations, clusters, edge and IoT devices.
Again, the prerequisite is  there must be a working copy multipass, and I'm using WSL. 😎 
Here are the setup configuration:
$ multipass launch --name kmaster -m 4G
$ multipass shell kmaster 
ubuntu@kmaster:~$ sudo snap install microk8s --classic
ubuntu@kmaster:~$ sudo usermod -a -G microk8s ubuntu
ubuntu@kmaster:~$ sudo chown -f -R ubuntu ~/.kube
ubuntu@kmaster:~$ exit
$ multipass shell kmaster
ubuntu@kmaster:~$ microk8s status --wait-ready
Next, let setup a second node:
$ multipass launch --name kworker1 -m 4G
$ multipass shell kworker1
ubuntu@kworker1:~$ sudo snap install microk8s --classic
ubuntu@kworker1:~$ sudo usermod -a -G microk8s ubuntu
ubuntu@kworker1:~$ sudo chown -f -R ubuntu ~/.kube
ubuntu@kworker1:~$ exit
$ multipass shell kworker1
ubuntu@kworker1:~$ microk8s status --wait-ready
Both nodes are ready, let's join them:
$ multipass exec kmaster -- microk8s add-node
From the node you wish to join to this cluster, run the following:
microk8s join 172.22.71.179:25000/daaad28e6febfbdaa5e228479e5f3f7c/8ee2423760f2
Use the '--worker' flag to join a node as a worker not running the control plane, eg:
microk8s join 172.22.71.179:25000/daaad28e6febfbdaa5e228479e5f3f7c/8ee2423760f2 --worker
If the node you are adding is not reachable through the default interface you can use one of the following:
microk8s join 172.22.71.179:25000/daaad28e6febfbdaa5e228479e5f3f7c/8ee2423760f2
Copy the line (in bold) and paste to the second node (kworker), and wait for a few minutes.
ubuntu@kworker1:~$ microk8s join 172.22.71.179:25000/daaad28e6febfbdaa5e228479e5f3f7c/8ee2423760f2
Contacting cluster at 172.22.71.179
Waiting for this node to finish joining the cluster. .. .. ..
ubuntu@kworker1:~$ microk8s kubectl get nodes
NAME       STATUS   ROLES    AGE     VERSION
kmaster    Ready    <none>   20m     v1.25.2
kworker1   Ready    <none>   2m32s   v1.25.2  
Last, let deploy some sample containerized application and test from host browser.
ubuntu@kworker1:~$ microk8s kubectl create deployment microbot --image=dontrebootme/microbot:v1
ubuntu@kworker1:~$ microk8s kubectl scale deployment microbot --replicas=3
ubuntu@kworker1:~$ microk8s kubectl expose deployment microbot --type=NodePort --port=80 --name=microbot-service
ubuntu@kworker1:~$ microk8s kubectl get all --all-namespaces
NAMESPACE     NAME                                             READY   STATUS    RESTARTS   AGE
kube-system   pod/calico-kube-controllers-75cc47cdf8-wnqx4     1/1     Running   0          31m
kube-system   pod/metrics-server-6b6844c455-cgxpg              1/1     Running   0          26m
kube-system   pod/kubernetes-dashboard-74b66d7f9c-5f7g8        1/1     Running   0          24m
kube-system   pod/dashboard-metrics-scraper-64bcc67c9c-5ghrz   1/1     Running   0          24m
kube-system   pod/calico-node-8k5bf                            1/1     Running   0          14m
kube-system   pod/calico-node-p78ws                            1/1     Running   0          13m
default       pod/microbot-5df46485d4-xc6m5                    1/1     Running   0          34s
default       pod/microbot-5df46485d4-hchk2                    1/1     Running   0          25s
default       pod/microbot-5df46485d4-52mhq                    1/1     Running   0          25s
NAMESPACE     NAME                                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
default       service/kubernetes                  ClusterIP   10.152.183.1     <none>        443/TCP        31m
kube-system   service/metrics-server              ClusterIP   10.152.183.24    <none>        443/TCP        26m
kube-system   service/kubernetes-dashboard        ClusterIP   10.152.183.143   <none>        443/TCP        25m
kube-system   service/dashboard-metrics-scraper   ClusterIP   10.152.183.48    <none>        8000/TCP       25m
default       service/microbot-service            NodePort    10.152.183.180   <none>        80:31396/TCP   10s
NAMESPACE     NAME                         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/calico-node   2         2         2       2            2           kubernetes.io/os=linux   31m
NAMESPACE     NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/calico-kube-controllers     1/1     1            1           31m
kube-system   deployment.apps/metrics-server              1/1     1            1           26m
kube-system   deployment.apps/kubernetes-dashboard        1/1     1            1           25m
kube-system   deployment.apps/dashboard-metrics-scraper   1/1     1            1           25m
default       deployment.apps/microbot                    3/3     3            3           35s
NAMESPACE     NAME                                                   DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/calico-kube-controllers-54c85446d4     0         0         0       31m
kube-system   replicaset.apps/calico-kube-controllers-75cc47cdf8     1         1         1       31m
kube-system   replicaset.apps/metrics-server-6b6844c455              1         1         1       26m
kube-system   replicaset.apps/kubernetes-dashboard-74b66d7f9c        1         1         1       24m
kube-system   replicaset.apps/dashboard-metrics-scraper-64bcc67c9c   1         1         1       24m
default       replicaset.apps/microbot-5df46485d4                    3         3         3       34s
From the output, we can see the port is exposed at port 31396. So just point the browser (at host) to http://kmaster.mshome.net:31396/
![]()  | 
| http://kmaster.mshome.net:31396/ | 
Links:
