Using Juju with MicroK8s
Zero-ops Kubernetes for workstations and edge / IoT
A single package of k8s for 42 flavours of Linux. Made for developers, and great for edge, IoT and appliances.
Install and set up MicroK8s
The easiest way to install MicroK8s and Juju is via their snap packages:
sudo snap install juju --classic sudo snap install microk8s --classic
We now need to add our account to the
microk8s group. This grants the account elevated privileges to the cluster, meaning that sudo will not be required to interact with
sudo usermod -a -G microk8s $USER
This command requires you to log out and log back in before the changes are applied. Exit the shell by executing
exit (or Ctrl + D) and restart your session.
Now let’s inspect the cluster with the
microk8s.kubectl get all --all-namespaces
You should see output similar to:
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE default service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 22s
It’s possible that you encounter an error message relating to permissions. If this happens, execute
sudo usermod -a -G microk8s $USER and restart.
Insufficient permissions to access MicroK8s. You can either try again with sudo or add the user ubuntu to the 'microk8s' group: sudo usermod -a -G microk8s $USER The new group will be available on the user's next login.
Enable DNS and storage addons
Now enable some MicroK8s addons that will provide DNS and storage class support:
microk8s.enable dns storage
This will bring about changes to the cluster. Re-invoking the
microk8s.kubectl get all --all-namespaces should eventually give you something like this:
NAMESPACE NAME READY STATUS RESTARTS AGE kube-system pod/hostpath-provisioner-6d744c4f7c-t9hgh 1/1 Running 0 2m50s kube-system pod/kube-dns-6bfbdd666c-rxnp9 3/3 Running 0 2m56s NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE default service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 3m55s kube-system service/kube-dns ClusterIP 10.152.183.10 <none> 53/UDP,53/TCP 2m56s NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE kube-system deployment.apps/hostpath-provisioner 1/1 1 1 2m50s kube-system deployment.apps/kube-dns 1/1 1 1 2m56s NAMESPACE NAME DESIRED CURRENT READY AGE kube-system replicaset.apps/hostpath-provisioner-6d744c4f7c 1 1 1 2m50s kube-system replicaset.apps/kube-dns-6bfbdd666c 1 1 1 2m56s
Creating a controller
Juju recognises when MicroK8s is installed and automatically sets up a cloud called ‘microk8s’. There is no need to manually add the cluster to Juju (verify this with
juju clouds --local). A controller can then be created just like a normal cloud. Here we’ve called it ‘micro’:
juju bootstrap microk8s micro
Important term - cloud: Within the Juju community, the term cloud has a specific meaning. A cloud is a target that Juju knows how to manage workloads for. Kubernetes clusters, including MicroK8s, are often referred to as “k8s clouds”.
Using a version of Juju earlier than v2.6.0:
Earlier versions of Juju did not have built-in support for MicroK8s. You should upgrade your version of Juju to the current stable release. If that’s not possible, you can use
juju add-k8s to register your MicroK8s cluster with Juju.
Verify the bootstrap process
Confirm the microk8s cloud is live by running
juju clouds. It should be visible within the controller and client sections.
$ juju clouds Only clouds with registered credentials are shown. There are more clouds, use --all to see them. Clouds available on the controller: Cloud Regions Default Type microk8s 1 localhost k8s Clouds available on the client: Cloud Regions Default Type Credentials Source Description [...] microk8s 1 localhost k8s 1 built-in A Kubernetes Cluster [...]
Important concept - clouds registered on the controller vs the client:
Clouds are deployment targets. They include credential information. Your controller can be notified of new clouds, allowing
In Juju, you interact with the client. It connects to controllers. The controller is hosted on a cloud.
Adding a model
A model is a container for a set of related applications. That model represents resources needed for the applications within it, including compute, storage and network.
juju add-model testing
Difference from traditional clouds: There is no ‘default’ model provided on k8s clouds. Creating a model implies creating a Kubernetes namespace. Rather than pollute your cluster’s namespaces, Juju favours an explicit approach.
Verifying that the model has been added
juju models command to list models hosted on the cloud. It will look very similar to:
$ juju models Controller: micro Model Cloud/Region Type Status Access Last connection controller microk8s/localhost kubernetes available admin just now testing* microk8s kubernetes available admin never connected
Deploying a Kubernetes charm
We can now deploy a Kubernetes charm. For example, here we deploy a charm by requesting the use of the ‘mariadb-pv’ workload storage pool we just set up:
juju deploy cs:~juju/mariadb-k8s --storage database=10M
The output to
juju status should soon look like the following:
Model Controller Cloud/Region Version SLA Timestamp k8s-model mk8s microk8s 2.6-beta2 unsupported 14:47:20Z App Version Status Scale Charm Store Rev OS Address Notes mariadb-k8s active 1 mariadb-k8s jujucharms 1 kubernetes 10.152.183.153 Unit Workload Agent Address Ports Message mariadb-k8s/0* active idle 10.1.1.15 3306/TCP
In contrast to standard Juju behaviour, there are no machines listed here. Let’s see what has happened within the cluster:
microk8s.kubectl get all --all-namespaces
New sample output:
NAMESPACE NAME READY STATUS RESTARTS AGE controller-mk8s pod/controller-0 2/2 Running 1 6m6s k8s-model pod/mariadb-k8s-0 1/1 Running 0 77s k8s-model pod/mariadb-k8s-operator-0 1/1 Running 0 93s kube-system pod/hostpath-provisioner-6d744c4f7c-t9hgh 1/1 Running 0 9m39s kube-system pod/kube-dns-6bfbdd666c-rxnp9 3/3 Running 0 9m45s NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE controller-mk8s service/controller-service ClusterIP 10.152.183.168 <none> 17070/TCP 6m7s default service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 10m testing service/mariadb-k8s ClusterIP 10.152.183.153 <none> 3306/TCP 76s kube-system service/kube-dns ClusterIP 10.152.183.10 <none> 53/UDP,53/TCP 9m45s NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE kube-system deployment.apps/hostpath-provisioner 1/1 1 1 9m39s kube-system deployment.apps/kube-dns 1/1 1 1 9m45s NAMESPACE NAME DESIRED CURRENT READY AGE kube-system replicaset.apps/hostpath-provisioner-6d744c4f7c 1 1 1 9m39s kube-system replicaset.apps/kube-dns-6bfbdd666c 1 1 1 9m45s NAMESPACE NAME READY AGE controller-mk8s statefulset.apps/controller 1/1 6m6s testing statefulset.apps/mariadb-k8s 1/1 77s testing statefulset.apps/mariadb-k8s-operator 1/1 93s
You can easily identify the changes, as compared to the initial output, by scanning the left hand side for our model name ‘k8s-model’, which runs in a Kubernetes namespace of the same name. The operator/controller pod runs in a namespace whose name is based on our controller name (‘mk8s’): ‘controller-mk8s’.
To get information on pod ‘mariadb-k8s-0’ you need to refer to the namespace (since it’s not the ‘default’ namespace) in this way:
microk8s.kubectl describe pods -n testing mariadb-k8s-0
The output is too voluminous to include here. See the upstream documentation on different ways of viewing cluster information.
Removing configuration and software
To remove all traces of what we’ve done in this tutorial, use the following commands:
juju kill-controller -y -t 0 mk8s microk8s.reset sudo snap remove microk8s sudo snap remove juju
That’s the end of this tutorial!
- Learn more about using Kubernetes with Juju