Using Kubernetes with Juju

Kubernetes (“K8s”) provides a flexible architecture for cloud-native applications at scale. We believe that Juju is the simplest way to manage multi-container workloads on K8s. This guide takes you through the registration steps necessary to connect the two systems.

What is Juju?: Juju is the simplest DevOps tool for managing digital services built with inter-related applications. If you are unfamiliar with Juju, then we recommend following our Getting Started with Juju tutorial.

Need a Kubernetes cluster for experimentation?: Install MicroK8s to create a local Kubernetes cluster with zero effort.

Running Kubernetes workloads

To run workloads on Kubernetes with Juju, a small number of registration steps are required:

  1. Obtain a Kubernetes cluster
  2. Register the cluster with Juju
  3. Create a Juju controller
  4. Register storage resources

You’re now ready to deploy cloud-native workloads with charms:

  1. Add a model
  2. Deploy workloads

Obtain a Kubernetes cluster

There are many ways to obtain a Kubernetes cluster. If you are unsure which option to choose, then you should install MicroK8s.

Use Case Recommended Action(s)
Local development, testing and experimentation Install MicroK8s
Multi-node testing/production on a private cloud Install Charmed Kubernetes
Multi-node testing/production on the public cloud Install Charmed Kubernetes with the relevant integrator charm
Use a hosted Kubernetes distribution Enable the service via the provider

Alternative Kubernetes Options

Juju can work with other Kubernetes clusters in addition to those listed above, but there will likely be a little extra setup required to allow Juju to talk to services created in the cluster (such services include the Juju controller created at bootstrap). Ongoing investigation is taking place to automate these actions depending on the Kubernetes cluster used.

In the absence of anything else, service ingress can be achieved by configuring services as type “load balancer”. Juju does this automatically for supported clusters where load balancer services are known to be enabled. See Create a Juju controller below for available options.


To use Juju with Minikube, you need to enable tunnelling to connect to the load balancer.
In a separate terminal:

minikube tunnel

and then follow the cluster registration steps below:

juju add-k8s minikube
juju bootstrap --config controller-service-type=loadbalancer minikube

Register the Kubernetes cluster with Juju

Registering the cluster with Juju is known as “adding a cloud” in Juju’s terminology. A cloud is a deployment target. The exact process to register the cluster depends on how your system is configured.

When running MicroK8s

The cluster is registered with Juju automatically, but we have to enable some addons.

microk8s enable storage dns

Then move on to Create a Juju controller.

When you’re already able to interact with your cluster via kubectl

The registration process is a single command:

juju add-k8s

When you have used Juju to deploy Charmed Kubernetes

We can use Juju to extract its configuration file to save it locally with these commands:

mkdir ~/.kube
juju scp kubernetes-master/0:/home/ubuntu/config ~/.kube/config
juju add-k8s


Copy the cluster’s configuration file from the master node to your local machine and save it as $HOME/.kube/config, then run

juju add-k8s

Create a Juju controller

The Juju controller is a central software agent that oversees applications managed with Juju. It is created via the juju bootstrap command.

juju bootstrap <cloud-name> <controller-name>

There are 3 important bootstrap config options that may be needed, depending on how the Kubernetes cluster has been configured to provision services requiring ingress. These options are shown when running the following:

juju help bootstrap
Usage: juju bootstrap [options] [<cloud name>[/region] [<controller name>]]

Initializes a cloud environment.

  type: string
  description: Specifies a comma separated list of external IPs for a k8s controller
    of type external
  type: string
  description: Sets the external name for a k8s controller of type external
  type: string
  description: Controls the kubernetes service type for Juju controllers, see
    valid values are one of cluster, loadbalancer, external

In many cases, a Kubernetes cluster will have been configured by the cluster admin to provision load balancer services, so the only additional option needed for bootstrap is as follows:

juju bootstrap myk8s --config controller-service-type=loadbalancer

The out-of-the-box supported Kubernetes clusters mentioned at the start of this page do not require any additional configuration for most cases.

Register storage resources

When an application that you wish to deploy - a “workload” in Juju terms - makes uses of persistent storage, you may need to ensure that an appropriate storage pool has been added to your Kubernetes cluster.

Juju will initially have a storage pool called “kubernetes”.

Charmed Kubernetes users can use Juju to provide it with storage based on Ceph or NFS.

The create-storage-pool command can be used to add new storage pools. For example:

juju create-storage-pool my-new-pool kubernetes storage-class=microk8s-hostpath

See Persistent storage and Kubernetes for more detail.

Add a model

Before deploying applications with charms, Juju users create a “model”. The model is a workspace for inter-related applications. It is an abstraction over applications, machines hosting them and other components such as persistent storage.

To add a model, use the juju add-model command:

juju add-model <k8s-cloud-name>

Inside the cluster, adding a Juju model creates a Kubernetes namespace with the same name. The namespace hosts all of the pods and other resources, except global resources.

Deploy a Kubernetes charm

A Kubernetes-specific charm is deployed in standard fashion, with the deploy command. If the charm has storage requirements you will need to specify them, as you do with a normal charm.


The below table lists configuration keys supported by Kubernetes charms that are set at deploy time. The corresponding Kubernetes meaning can be obtained from the Kubernetes documentation for Services and Ingress.

Key Type Default
kubernetes-service-type string ClusterIP
kubernetes-service-external-ips string []
kubernetes-service-target-port string <container port>
kubernetes-service-loadbalancer-ip string ""
kubernetes-service-loadbalancer-sourceranges string "[]"
kubernetes-service-externalname string ""
kubernetes-ingress-class string nginx
kubernetes-ingress-ssl-redirect boolean false
kubernetes-ingress-ssl-passthrough boolean false
kubernetes-ingress-allow-http boolean false

For example:

juju deploy cs:~charmed-osm/mariadb-k8s \
  --config kubernetes-service-loadbalancer-ip= \
  --storage database=100M,kubernetes

There are two other keys that are not Kubernetes-specific:

Key Type Default
juju-external-hostname string ""
juju-application-path string "/"

Keys ‘juju-external-hostname’ and ‘juju-application-path’ control how the application is exposed externally using a Kubernetes Ingress Resource in conjunction with the configured ingress controller (default: nginx).

Workload images

When the charm is deployed, Juju does not download the actual OCI image. It fetches the image metadata which is stored as a charm resource; this info is used to set up the Kubernetes pod spec image metadata; it’s Kubernetes which actually pulls the image from the specified registry path. Public images do not use a username or password.

For dev/test, you may want to use a different image to the one published with the charm. And for local charms, there is no published image so the follow applies in that case also. You deploy the charm and use the --resource argument to specify the image path, eg

juju deploy cs:~charmed-osm/mariadb-k8s --resource mysql_image=mariadb:latest
juju deploy /path/to/mariadb-k8s --resource mysql_image=mariadb:latest

When upgrading a charm, --resource can also be used to specify a different workload image, eg

juju upgrade-charm mariadb-k8s --resource mysql_image=mariadb:9.0

Tutorials and in-depth guides

The following practical guides are available:

Looks like something was omitted here?

Should be:

We believe that Juju is the simplest way to manage multi-container workloads on K8s.

1 Like

Thanks; fixed it.

1 Like

This command results in ERROR missing k8s name. The help text indicates that the name is required. Perhaps this has changed since the docs were created?

Spelling mistake: Kuebernetes => Kubernetes

1 Like

juju deploy mariadb-k8s fails: ERROR cannot resolve URL "cs:mariadb-k8s": charm or bundle not found. Has the charm’s name changed? Or should another example be provided in its place?

1 Like

The documentation material refers to a mariadb-k8s charm publish to ~charmed-osm so you need to include that in your deploy, ie

juju deploy cs:~charmed-osm/mariadb-k8s

@wallyworld So to clarify, should the documentation be updated to reference cs:~charmed-osm/maria-k8s instead? Or did I miss a step somewhere to automatically include ~charmed-osm or similar?

It just looks like a step was missed. ie this command was run

juju deploy mariadb-k8s

instead of

juju deploy cs:~charmed-osm/mariadb-k8s