How to install Kubernetes with microk8s and deploy apps on Debian/Mint/Ubuntu Linux

Kubernetes Easy Beginners Architecture Guide

Kubernetes is known as container orchestration and we should start at explaining the container part of it.

A Container is what runs the actual application and based on an Image, and are more comparable to something like an LXC Container, Virtuozzo/OpenVZ using the Linux Kernel Namespaces feature.  Containers run these images as independent, isolated operating environments under the OS's existing kernel.  Unlike full virtualization which emulates a real computer, images run under the existing OS kernel and do not have their own virtual hardware, which makes them perform and deploy faster.

An Image is like a pre-built template that has everything we need to run the application eg. nginx, Apache, MySQL and almost anything can be turned into a purpose built application inside an image file.

Multiple Containers run within Pods, and Multiple Pods can run on Nodes, and there can be Multiple Nodes in the Cluster, which is the general/basic hierarchy of Kubernetes.

Pods are basically just a grouping of Containers which are generally related or may need to have tighter coupling of storage and networking.

Nodes can be anything that runs the kubernetes services, and would most commonly be some sort of VM or even a physical server.


RAM: 4G minimum (8G and much higher recommended for any workloads)

HDD: 20G minium

Hostname: No capitals and no underscores

OS: Latest / newer Linux distro

This guide was written for Ubuntu 20/Mint 20 at the time.

At the time of update the latest microk8s classic is 1.26.3 and this worked fine on Ubuntu 22 and Debian 11.

Step 1 - Install snapd and microk8s

Note that Linux Mint disables snap, read this post to fix snapd install missing in Linux Mint.

snapd installation

sudo apt install snapd
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
0 upgraded, 1 newly installed, 0 to remove and 123 not upgraded.
Need to get 3,340 B of archives.
After this operation, 19.5 kB of additional disk space will be used.
Get:1 focal/universe amd64 kubernetes all 1.0 [3,340 B]
Fetched 3,340 B in 0s (9,475 B/s)      
Selecting previously unselected package kubernetes.
(Reading database ... 378576 files and directories currently installed.)
Preparing to unpack .../kubernetes_1.0_all.deb ...
Unpacking kubernetes (1.0) ...
Setting up kubernetes (1.0) ...
Processing triggers for man-db (2.9.1-1) ...

microk8s installation

#the channel version is very important.  At the original time of writing the default channel was 1.20 and today it is 1.26.3, there are often big changes in each channel/version that may cause things to break.  For example at the time of writing the default channel of 1.20 worked fine on Ubuntu 20/Mint 20, but today version 1.26.3 which is the default, is broken (although it works fine on Debian 11).

So you should specify a certain channel and be aware of which one you are working on to avoid surprises, changes and incompatibilities in the future.

snap install microk8s --classic --channel=1.19


Create our first app deployment using nginx

microk8s.kubectl create deployment nginx --image nginx
deployment.apps/nginx created

enable/expose it so it can start working

microk8s.kubectl expose deployment nginx --port 8000 --target-port 8000 --selector app=nginx --type ClusterIP --name rtttest
service/rtttest exposed

View all running services:

microk8s.kubectl get all
NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-6799fc88d8-sm5gd   1/1     Running   0          3m43s

NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
service/kubernetes   ClusterIP             443/TCP    25m
service/areebtest    ClusterIP           8000/TCP   2m49s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           3m43s

NAME                               DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-6799fc88d8   1         1         1       3m43s


Enable Dashboard

microk8s.enable dns dashboard
Enabling DNS
Applying manifest
serviceaccount/coredns created
configmap/coredns created
Warning: spec.template.metadata.annotations[]: non-functional in v1.16+; use the "priorityClassName" field instead
deployment.apps/coredns created
service/kube-dns created created created
Restarting kubelet
DNS is enabled

Enabling Kubernetes Dashboard
Enabling Metrics-Server
serviceaccount/metrics-server created created created created created created
service/metrics-server created
deployment.apps/metrics-server created created created
Metrics-Server is enabled
Applying manifest
serviceaccount/kubernetes-dashboard created
service/kubernetes-dashboard created
secret/kubernetes-dashboard-certs created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created created created created created
Warning: spec.template.spec.nodeSelector[]: deprecated since v1.14; use "" instead
deployment.apps/kubernetes-dashboard created
service/dashboard-metrics-scraper created
deployment.apps/dashboard-metrics-scraper created

If RBAC is not enabled access the dashboard using 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

In an RBAC enabled setup (microk8s enable RBAC) you need to create a user with restricted
permissions as shown in:

microk8s.kubectl get all --all-namespaces
NAMESPACE     NAME                                             READY   STATUS              RESTARTS       AGE
default       pod/nginx-6799fc88d8-sm5gd                       1/1     Running             1 (134m ago)   147m
kube-system   pod/coredns-7f9c69c78c-jhhkq                     1/1     Running             0              2m25s
kube-system   pod/calico-node-2jnsp                            1/1     Running             1 (134m ago)   169m
kube-system   pod/calico-kube-controllers-58d7965c58-qpw8j     1/1     Running             1 (134m ago)   169m
kube-system   pod/dashboard-metrics-scraper-58d4977855-7dnzm   0/1     ContainerCreating   0              13s
kube-system   pod/kubernetes-dashboard-59699458b-7t52l         0/1     ContainerCreating   0              13s
kube-system   pod/metrics-server-85df567dd8-7rfsm              0/1     Running             0              13s

NAMESPACE     NAME                                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes                  ClusterIP             443/TCP                  169m
default       service/areebtest                   ClusterIP           8000/TCP                 146m
kube-system   service/kube-dns                    ClusterIP            53/UDP,53/TCP,9153/TCP   2m25s
kube-system   service/metrics-server              ClusterIP           443/TCP                  97s
kube-system   service/kubernetes-dashboard        ClusterIP           443/TCP                  77s
kube-system   service/dashboard-metrics-scraper   ClusterIP            8000/TCP                 77s

kube-system   daemonset.apps/calico-node   1         1         1       1            1    169m

NAMESPACE     NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/calico-kube-controllers     1/1     1            1           169m
default       deployment.apps/nginx                       1/1     1            1           147m
kube-system   deployment.apps/coredns                     1/1     1            1           2m26s
kube-system   deployment.apps/dashboard-metrics-scraper   0/1     1            0           77s
kube-system   deployment.apps/metrics-server              0/1     1            0           97s
kube-system   deployment.apps/kubernetes-dashboard        0/1     1            0           77s

NAMESPACE     NAME                                                   DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/calico-kube-controllers-58d7965c58     1         1         1       169m
default       replicaset.apps/nginx-6799fc88d8                       1         1         1       147m
kube-system   replicaset.apps/coredns-7f9c69c78c                     1         1         1       2m26s
kube-system   replicaset.apps/dashboard-metrics-scraper-58d4977855   1         1         0       13s
kube-system   replicaset.apps/metrics-server-85df567dd8              1         1         0       13s
kube-system   replicaset.apps/kubernetes-dashboard-59699458b         1         1         0       13s



How to Expose the Dashboard

microk8s.kubectl expose service kubernetes-dashboard -n kube-system --port 8000 --type=NodePort --name kubserv

service/kubserv exposed

This is an excellent intro to namespaces, as you will notice the dashboard belongs to the namespace "kube-system" so we have to use "-n" for namespace and specify kube-system or it will not work (without -n it defaults to the "default" namespace).  As when we exposed nginx previously, it was running in the "default" namespace.

kube-system   service/kubernetes-dashboard        ClusterIP           443/TCP                                         42h

default       service/areebtest                   ClusterIP           80/TCP  

We can also delete the "kubserv" exposed service:

microk8s.kubectl delete service -n kube-system kubserv
service "kubserv" deleted


If you get these sorts of errors right after installing, you have bad or incompatible version of microk8s and should get an older version.


Kubernetes microk8s / calico won't start, stuck on initializing after the install






Let's Extend To an HA Kubernetes Cluster:

On the first node from above that you already created, run this command:

microk8s add-node
From the node you wish to join to this cluster, run the following:
microk8s join

If the node you are adding is not reachable through the default interface you can use one of the following:
 microk8s join


On the other nodes, use the join statement from above: microk8s join


microk8s cluster invalid token (500)

Be sure that you have connectivity to the master node in the join statement, that no firewall is blocking the connection, and that the join statement is copied and pasted correctly without any extra whitespace in the middle or typos.




Old Broken stuff


kubernetes install

Choose 1 for microk8s:






install, kubernetes, debian, mint, ubuntu, linuxhttps, io, docs, tasks, kubectl, linux, https, microk, sudo, apt, snapd, lists, dependency, packages, installed, upgraded, newly, archives, kb, additional, disk, http, archive, focal, amd, fetched, selecting, previously, unselected, database, directories, currently, preparing, unpack, kubernetes_, _all, deb, unpacking, processing, triggers, db, enable, ips, ufw, firewall, apps, cni, default, routed, app, deployment, nginx, images, selector, clusterip, rtttest, restarts, pod, fc, sm, gd, cluster, ip, external, tcp, areebtest, desired, replicaset, dashboard, dns, enabling, applying, manifest, serviceaccount, coredns, configmap, spec, template, metadata, annotations, scheduler, alpha, functional, quot, priorityclassname, kube, clusterrole, rbac, authorization, clusterrolebinding, restarting, kubelet, enabled, metrics, server, aggregated, reader, rolebinding, auth, delegator, apiservice, apiregistration, beta, admin, certs, csrf, holder, settings, nodeselector, os, deprecated, scraper, token, retrieved, grep, user, restricted, permissions, github, blob, creating, md, namespaces, namespace, jhhkq, calico, node, jnsp, controllers, qpw, dnzm, containercreating, df, dd, rfsm, udp, daemonset, echo, nodeport, nic, microbot, vm, publicly,

Latest Articles

  • How To Stop DNSMasq from listening on all IPs/Interfaces and allow only localhost
  • du - VAS Billing Subscriptions Hack/Scam MLPremiumSub Invascom Astromart Issues Complaint
  • Docker Swarm vs Kubernetes Comparison Guide
  • When is it time to leave your VPS/VDS Cloud Hosting Provider?
  • 2024 Buyer's Guide: How to Choose and Buy the Best VPS/VDS for Your Needs - Tips and Strategies
  • Postfix / sendmail config for DKIM, SPF and DMARC Tutorial Guide E-mail Delivery for and More HowTo
  • Install Grafana on Linux Debian Ubuntu Tutorial Guide
  • How To Completely Disable ufw in Linux Ubuntu Mint Debian
  • System has not been booted with systemd as init system (PID 1). Can't operate. Failed to talk to init daemon. Ubuntu Debian Linux Solution Cannot reboot
  • Mint Ubuntu Linux Gnome Showing Home Directory on Desktop instead of Desktop Directory
  • vi vim not doing code highlighting E319: Sorry, the command is not available in this version solution
  • Proxmox How To Rename Node Hostname Fix Solution
  • Linux how to get list of all timezones on system Ubuntu
  • Proxmox install issue cannot see the buttons or install wrong / bad resolution cannot see the entire screen problem solution
  • error: possibly undefined macro: AC_PROG_LIBTOOL If this token and others are legitimate, please use m4_pattern_allow. See the Autoconf documentation. solution
  • Can't exec "aclocal": No such file or directory at /usr/share/autoconf/Autom4te/ line 326. autoreconf: failed to run aclocal: No such file or directory solution
  • /bin/sh: autoreconf: command not found solution
  • glib-2.0 required to compile QEMU solution
  • How To Upgrade Debian 8,9,10 to Debian 12 Bookworm
  • Linux dhcp dhclient Mint Redhat Ubuntu Debian How To Use Local Domain DNS Server Instead of ISPs