Install a local Kubernetes with MicroK8s

Key Value
Summary Get a local Kubernetes on your workstation or edge device with microk8s. Possibly the fastest path to this great open-source orchestration system, Kubernetes.
Categories containers
Difficulty 1
Author Konstantinos Tsakalozos kos.tsakalozos@canonical.com

Overview

What is Kubernetes

Kubernetes clusters host containerised applications in a reliable and scalable way. Having DevOps in mind, Kubernetes makes maintenance tasks such as upgrades simple.

What is MicroK8s

MicroK8s is a CNCF certified upstream Kubernetes deployment that runs entirely on your workstation or edge device. Being a snap it runs all Kubernetes services natively (i.e. no virtual machines) while packing the entire set of libraries and binaries needed. Installation is limited by how fast you can download a couple of hundred megabytes and the removal of MicroK8s leaves nothing behind.

In this tutorial you’ll learn how to…

  • Get your Kubernetes cluster up and running
  • Enable core Kubernetes addons such as dns and dashboard
  • Control your cluster from the kubectl CLI client
  • Deploy your first container workload

You will only need …

  • A machine with Linux

Deploying MicroK8s

Duration: 3:00

If you are using Ubuntu, the quickest way to get started is to install MicroK8s directly from the snap store by clicking the “Install” button.

However, you can also install MicroK8s from the command line:

sudo snap install microk8s --classic

If you are using a different Linux distribution, you will have to install snapd first. Refer to Snapd documentation for more information on installing snapd on your Linux distribution.

For other platforms (Windows, macOS, Raspberry Pi etc) and install methods, please see the MicroK8s documentation

MicroK8s is a snap and as such it is frequently updated to each release of Kubernetes. To follow a specific upstream release series it’s possible to select a channel during installation. For example, to follow the v1.25 series:

sudo snap install microk8s --classic --channel=1.25/stable

Channels are made up of a track and an expected level of MicroK8s’ stability. Try snap info microk8s to see what versions are currently published. At the time of this writing we have:

channels:
  1.26/stable:           v1.26.1         2023-02-07 (4595) 176MB classic
  1.26/candidate:        v1.26.1         2023-01-28 (4595) 176MB classic
  1.26/beta:             v1.26.1         2023-01-28 (4595) 176MB classic
  1.26/edge:             v1.26.2         2023-03-01 (4812) 177MB classic
  latest/stable:         v1.26.1         2023-02-08 (4595) 176MB classic
  latest/candidate:      v1.26.1         2023-01-19 (4519) 180MB classic
  latest/beta:           v1.26.1         2023-01-19 (4519) 180MB classic
  latest/edge:           v1.26.2         2023-03-03 (4828) 181MB classic
  dqlite/stable:         –                                       
  dqlite/candidate:      –                                       
  dqlite/beta:           –                                       
  dqlite/edge:           v1.16.2         2019-11-07 (1038) 189MB classic
  1.27/stable:           –                                       
  1.27/candidate:        –                                       
  1.27/beta:             –                                       
  1.27/edge:             v1.27.0-alpha.3 2023-03-03 (4836) 181MB classic
  1.26-strict/stable:    v1.26.1         2023-02-23 (4596) 176MB -
  1.26-strict/candidate: v1.26.1         2023-01-29 (4596) 176MB -
  1.26-strict/beta:      v1.26.1         2023-01-29 (4596) 176MB -
  1.26-strict/edge:      v1.26.2         2023-03-01 (4811) 177MB -
  1.25-strict/stable:    v1.25.6         2023-01-29 (4504) 174MB -
  1.25-strict/candidate: v1.25.6         2023-01-28 (4504) 174MB -
  1.25-strict/beta:      v1.25.6         2023-01-28 (4504) 174MB -
  1.25-strict/edge:      v1.25.7         2023-02-28 (4801) 175MB -
  1.25/stable:           v1.25.6         2023-02-07 (4565) 174MB classic
  1.25/candidate:        v1.25.6         2023-01-28 (4565) 174MB classic
  1.25/beta:             v1.25.6         2023-01-28 (4565) 174MB classic
  1.25/edge:             v1.25.7         2023-02-28 (4802) 175MB classic
  1.24-eksd/stable:      v1.24-8         2023-02-07 (4594) 171MB classic
  1.24-eksd/candidate:   v1.24-11        2023-02-24 (4759) 171MB classic
  1.24-eksd/beta:        v1.24-11        2023-02-24 (4759) 171MB classic
  1.24-eksd/edge:        v1.24-11        2023-02-28 (4793) 171MB classic
  1.24/stable:           v1.24.10        2023-02-02 (4561) 224MB classic
  1.24/candidate:        v1.24.10        2023-01-27 (4561) 224MB classic
  1.24/beta:             v1.24.10        2023-01-27 (4561) 224MB classic
  1.24/edge:             v1.24.11        2023-02-28 (4785) 225MB classic
  1.23-eksd/stable:      v1.23-13        2023-02-05 (4580) 167MB classic
  1.23-eksd/candidate:   v1.23-16        2023-02-24 (4758) 167MB classic
  1.23-eksd/beta:        v1.23-16        2023-02-24 (4758) 167MB classic
  1.23-eksd/edge:        v1.23-16        2023-02-23 (4758) 167MB classic
  1.23/stable:           v1.23.16        2023-01-28 (4549) 212MB classic
  1.23/candidate:        v1.23.16        2023-01-23 (4549) 212MB classic
  1.23/beta:             v1.23.16        2023-01-23 (4549) 212MB classic
  1.23/edge:             v1.23.17        2023-02-28 (4788) 213MB classic
  1.22-eksd/stable:      v1.22-21        2023-03-05 (4756) 164MB classic
  1.22-eksd/candidate:   v1.22-21        2023-02-24 (4756) 164MB classic
  1.22-eksd/beta:        v1.22-21        2023-02-24 (4756) 164MB classic
  1.22-eksd/edge:        v1.22-21        2023-02-23 (4756) 164MB classic
  1.22/stable:           v1.22.17        2022-12-18 (4374) 187MB classic
  1.22/candidate:        v1.22.17        2022-12-10 (4374) 187MB classic
  1.22/beta:             v1.22.17        2022-12-10 (4374) 187MB classic
  1.22/edge:             v1.22.17        2023-02-16 (4705) 187MB classic
  1.21/stable:           v1.21.13        2022-07-20 (3410) 191MB classic
  1.21/candidate:        v1.21.13        2022-07-09 (3410) 191MB classic
  1.21/beta:             v1.21.13        2022-07-09 (3410) 191MB classic
  1.21/edge:             v1.21.13        2022-06-08 (3410) 191MB classic
  ...

ⓘ You may need to configure your firewall to allow pod-to-pod and pod-to-internet communication:

sudo ufw allow in on cni0 && sudo ufw allow out on cni0
sudo ufw default allow routed

Enable addons

Duration: 2:00

By default we get a barebones upstream Kubernetes. Additional services, such as dashboard, core-dns or local storage can be enabled by running the microk8s enable command:

microk8s enable dns 
microk8s enable dashboard
microk8s enable storage

These addons can be disabled at anytime by running the microk8s disable command:

microk8s disable dns 
microk8s disable dashboard
microk8s disable storage

With microk8s status you can see the list of available addons and the ones currently enabled.

List of the most important addons

  • dns: Deploy DNS. This addon may be required by others, thus we recommend you always enable it.
  • dashboard: Deploy kubernetes dashboard.
  • storage: Create a default storage class. This storage class makes use of the hostpath-provisioner pointing to a directory on the host.
  • ingress: Create an ingress controller.
  • gpu: Expose GPU(s) to MicroK8s by enabling the nvidia-docker runtime and nvidia-device-plugin-daemonset. Requires NVIDIA drivers to be already installed on the host system.
  • istio: Deploy the core Istio services. You can use the microk8s istioctl command to manage your deployments.
  • registry: Deploy a docker private registry and expose it on localhost:32000. The storage addon will be enabled as part of this addon.

Accessing the Kubernetes dashboard

Duration: 8:00

Now that we have enabled the dns and dashboard addons we can access the available dashboard. To do so we first check the deployment progress of our addons with microk8s kubectl get all --all-namespaces. It only takes a few minutes to get all pods in the “Running” state:

NAMESPACE     NAME                                             READY   STATUS    RESTARTS   AGE
kube-system   pod/calico-kube-controllers-847c8c99d-fmbsl      1/1     Running   0          92s
kube-system   pod/metrics-server-8bbfb4bdb-gwbch               1/1     Running   0          14s
kube-system   pod/dashboard-metrics-scraper-6c4568dc68-5xpbb   1/1     Running   0          14s
kube-system   pod/calico-node-sc2pv                            1/1     Running   0          92s
kube-system   pod/coredns-86f78bb79c-lfjtr                     1/1     Running   0          23s
kube-system   pod/kubernetes-dashboard-7ffd448895-7n5j2        1/1     Running   0          14s

NAMESPACE     NAME                                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes                  ClusterIP   10.152.183.1     <none>        443/TCP                  100s
kube-system   service/kube-dns                    ClusterIP   10.152.183.10    <none>        53/UDP,53/TCP,9153/TCP   23s
kube-system   service/metrics-server              ClusterIP   10.152.183.158   <none>        443/TCP                  15s
kube-system   service/kubernetes-dashboard        ClusterIP   10.152.183.64   <none>        443/TCP                  14s
kube-system   service/dashboard-metrics-scraper   ClusterIP   10.152.183.223   <none>        8000/TCP                 14s

NAMESPACE     NAME                         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/calico-node   1         1         1       1            1           kubernetes.io/os=linux   95s

NAMESPACE     NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/calico-kube-controllers     1/1     1            1           95s
kube-system   deployment.apps/metrics-server              1/1     1            1           15s
kube-system   deployment.apps/dashboard-metrics-scraper   1/1     1            1           14s
kube-system   deployment.apps/coredns                     1/1     1            1           23s
kube-system   deployment.apps/kubernetes-dashboard        1/1     1            1           14s

NAMESPACE     NAME                                                   DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/calico-kube-controllers-847c8c99d      1         1         1       93s
kube-system   replicaset.apps/metrics-server-8bbfb4bdb               1         1         1       15s
kube-system   replicaset.apps/dashboard-metrics-scraper-6c4568dc68   1         1         1       14s
kube-system   replicaset.apps/coredns-86f78bb79c                     1         1         1       23s
kube-system   replicaset.apps/kubernetes-dashboard-7ffd448895        1         1         1       14s

Kubernetes dashboard

As we see above the kubernetes-dashboard service in the kube-system namespace has a ClusterIP of 10.152.183.64 and listens on TCP port 443. The ClusterIP is randomly assigned, so if you follow these steps on your host, make sure you check the IP adress you got. Point your browser to https://10.152.183.64:443 and you will see the kubernetes dashboard UI. To access the dashboard use the default token retrieved with:

token=$(microk8s kubectl -n kube-system get secret | grep default-token | cut -d " " -f1)
microk8s kubectl -n kube-system describe secret $token

Host your first service in Kubernetes

Duration: 7:00

We start by creating a microbot deployment with two pods via the kubectl cli:

microk8s kubectl create deployment microbot --image=dontrebootme/microbot:v1
microk8s kubectl scale deployment microbot --replicas=2

To expose our deployment we need to create a service:

microk8s kubectl expose deployment microbot --type=NodePort --port=80 --name=microbot-service

After a few minutes our cluster looks like this:

> microk8s kubectl get all --all-namespaces
NAMESPACE     NAME                                             READY   STATUS    RESTARTS   AGE
kube-system   pod/calico-kube-controllers-847c8c99d-fmbsl      1/1     Running   0          3m21s
kube-system   pod/metrics-server-8bbfb4bdb-gwbch               1/1     Running   0          2m3s
kube-system   pod/dashboard-metrics-scraper-6c4568dc68-5xpbb   1/1     Running   0          2m3s
kube-system   pod/calico-node-sc2pv                            1/1     Running   0          3m21s
kube-system   pod/coredns-86f78bb79c-lfjtr                     1/1     Running   0          2m12s
kube-system   pod/kubernetes-dashboard-7ffd448895-7n5j2        1/1     Running   0          2m3s
default       pod/microbot-5f5499d479-vznng                    1/1     Running   0          22s
default       pod/microbot-5f5499d479-6kq5r                    1/1     Running   0          22s

NAMESPACE     NAME                                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes                  ClusterIP   10.152.183.1     <none>        443/TCP                  3m29s
kube-system   service/kube-dns                    ClusterIP   10.152.183.10    <none>        53/UDP,53/TCP,9153/TCP   2m12s
kube-system   service/metrics-server              ClusterIP   10.152.183.158   <none>        443/TCP                  2m4s
kube-system   service/kubernetes-dashboard        ClusterIP   10.152.183.64   <none>        443/TCP                  2m3s
kube-system   service/dashboard-metrics-scraper   ClusterIP   10.152.183.223   <none>        8000/TCP                 2m3s
default       service/microbot-service            NodePort    10.152.183.69   <none>        80:32648/TCP             16s

NAMESPACE     NAME                         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE     SELECTOR            AGE
kube-system   daemonset.apps/calico-node   1         1         1       1            1           kubernetes.io/os=linux   3m24s

NAMESPACE     NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/calico-kube-controllers     1/1     1            1           3m24s
kube-system   deployment.apps/metrics-server              1/1     1            1           2m4s
kube-system   deployment.apps/dashboard-metrics-scraper   1/1     1            1           2m3s
kube-system   deployment.apps/coredns                     1/1     1            1           2m12s
kube-system   deployment.apps/kubernetes-dashboard        1/1     1            1           2m3s
default       deployment.apps/microbot                    2/2     2            2           22s

NAMESPACE     NAME                                                   DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/calico-kube-controllers-847c8c99d      1         1         1       3m22s
kube-system   replicaset.apps/metrics-server-8bbfb4bdb               1         1         1       2m4s
kube-system   replicaset.apps/dashboard-metrics-scraper-6c4568dc68   1         1         1       2m3s
kube-system   replicaset.apps/coredns-86f78bb79c                     1         1         1       2m12s
kube-system   replicaset.apps/kubernetes-dashboard-7ffd448895        1         1         1       2m3s
default       replicaset.apps/microbot-5f5499d479                    2         2         2       22s

We have now two microbot pods and the service/microbot-service is the last in the services list. Our service has a ClusterIP through which we can access it. Notice, however, that our service is of type NodePort. This means that our deployment is also available on a port on the host machine; that port is randomly selected and in this case it happens to be 32648. All we need to do is to point our browser to http://localhost:32648.

Integrated commands

Duration: 5:00

There are many commands that ship with MicroK8s. We’ve only seen the essential ones in this tutorial. Explore the others at your own convenience:

  • microk8s status: Provides an overview of the MicroK8s state (running / not running) as well as the set of enabled addons
  • microk8s enable: Enables an addon
  • microk8s disable: Disables an addon
  • microk8s kubectl: Interact with kubernetes
  • microk8s config: Shows the kubernetes config file
  • microk8s istioctl: Interact with the istio services; needs the istio addon to be enabled
  • microk8s inspect: Performs a quick inspection of the MicroK8s intallation
  • microk8s reset: Resets the infrastructure to a clean state
  • microk8s stop: Stops all kubernetes services
  • microk8s start: Starts MicroK8s after it is being stopped

That’s all folks!

Duration: 1:00

Congratulations! You have made it!

Until next time, stop all MicroK8s services:

microk8s stop

Where to go from here?

1 Like

@toto aren’t these all supposed to be wiki pages so we can edit them?

@evilnick they should be all.

This one in particular is set as wiki.

@toto ah, I think I don’t have a high enough level on here to edit anything yet.

Following these directions I am left with an unconfigured grafana that requests I “Add data source”.

When I go to the IP address given for the dashboard, it times out. My situation is this:

  • microk8s is running on 192.168.10.20, an Ubuntu Server instance with no GUI.
  • The browser is running on 192.168.10.10, a Mac.

The instructions seem to assume that the browser is running on the same machine as microk8s, but that’s often not the case. Could the tutorial include instructions for displaying the dashboard in this situation, please?

(Also, after the snap install I had to add /snap/bin to my PATH myself. I suspect that it’s been added by default for bash users but not for users of other shells such as zsh, so it might be worth mentioning this to avoid people having to run find / -name \*microk8s\* in order to find where snap’s put the binaries : )

1 Like

Thanks for the feedback. Yes, this tutorial does make some assumptions it is not upfront about. I will test a solution for the case you mention and either update it here or add it to the MicroK8s docs and link from here

I can not get the dashboard running.
When I try to proxy port 10443 to 443, this is what I get:

microk8s kubectl port-forward --address 0.0.0.0 -n kube-system service/kubernetes-dashboard 10443:443
Forwarding from 0.0.0.0:10443 -> 8443

I seems to ignore the 443 and use 8443 instade. Why?

I ran into the same issue. I installed microk8s on a brand new ubuntu server and tried to access the dashboard from a browser on another host. The IP address is reported by
$ microk8s kubectl get all --all-namespaces
was 10.152.183.93, but obviously a browser running on another computer would have no entry in its routing table to even get to this address. What I ended up doing was running the dashboard-proxy on the microk8s box like this:

$ microk8s dashboard-proxy
Dashboard will be available at https://127.0.0.1:10443

dashboard-proxy is actually listening on *:10443 so you can use the normal static IP address of your server (192.168.1.87 in my case) to access the dashboard from the browser like this:
https://192.168.1.87:10443

Of course, the browser will complain about an invalid cert, but hey at least it can get there.

I try to access the dashboard via https://10.152.183.206/ but it fails with a security warning in chromium. Usually you can access the URL by accepting the risk, but in this case chromium gives me no way to access the page. It works with firefox, but my favorite browser is chromium.

There are a couple of ways to get Chrome to accept self-signed certificates [1]. My favorite is typing “thisisunsafe” after clicking anywhere on the page.

[1] https://stackoverflow.com/questions/7580508/getting-chrome-to-accept-self-signed-localhost-certificate

I was able to use the dashboard from a headless host using ssh tunneling.

On my laptop I ssh to the k8s host and tunnel to the dashboard ip address:

ssh -L 8080:10.152.183.98:443 user@k8s_host

I login and get a command line prompt.

Then on the laptop’s browser I go to https://127.0.0.1:8080 and I get the dashboard.
However, it is asking for a token, which I can’t find using the instructions on this page.
Seems that the token is no longer automatically generated.
I was able to get in with this info
which adds a “skip” button to the login page:

if you want to disable this, use this command for edit

microk8s.kubectl edit deployment/kubernetes-dashboard --namespace=kube-system

and add enable-skip-login as below:

spec:
      containers:
      - args:
        - --auto-generate-certificates
        - --enable-skip-login
        image: k8s.gcr.io/kubernetes-dashboard-amd64:v1.10.1
"/tmp/kubectl-edit-snu9z.yaml" 102L, 4077C  

Following the guide here, I cannot access the dashboard. The page seems to be outdated!

To get the dashboard token, simply run this:

microk8s.kubectl -n kube-system get secret microk8s-dashboard-token --template={{.data.token}} |base64 -d

Then open this page:

echo "https://$(microk8s.kubectl get svc -n kube-system kubernetes-dashboard --template={{.spec.clusterIP}})

And enter the token!