Get started with Juju

Imagine your business requires a chat service, such as Mattermost (backed by PostgreSQL), or an identity service, such as Keystone (backed by MySQL). To deploy and operate all this by hand would take you a lot of know-how, work, and time. Not so with Juju! In this tutorial you will learn how to achieve this in no time.

Prerequisites: A working station, e.g., a laptop.

Contents:

  1. Create the test environment
  2. Prepare your cloud
  3. Install the Juju CLI client
  4. Register your cloud with Juju
  5. Install a Juju controller in your cloud
  6. Create a workspace on your cloud
  7. Deploy applications on your workspace
  8. Integrate your applications
  9. Test your deployment
  10. Destroy the test environment
  11. Next steps

Create the test environment

When you’re learning, it’s good to do it in an isolated environment. Let’s start by creating an Ubuntu virtual machine with Multipass.

First, install Multipass: Linux | macOS | Windows.

Then, open a terminal and use Multipass to launch an Ubuntu virtual machine and open a shell in it, as shown below. We’ve called ours tutorial-vm .

# Launch a VM  "tutorial-vm" with 8 GB RAM, 2 CPU cores, 
# 20 GB disk, and Ubuntu 20.04 LTS (Jammy Jellyfish):
$ multipass launch -n tutorial-vm -m 8g -c 2 -d 20G jammy
Launched: tutorial-vm

# Open a shell inside the VM:
$ multipass shell tutorial-vm
ubuntu@tutorial-vm:~$

Congratulations, your Ubuntu virtual machine is ready! Any command you type after the last terminal prompt will be inside of this virtual machine.

If for whatever reason you need to interrupt this tutorial, we recommend running multipass stop tutorial-vm to stop the instance. When you resume, run multipass start tutorial-vm.

Prepare your cloud

To continue this tutorial you’ll need a cloud. To keep things simple, in this tutorial we will use MicroK8s / LXD, a small Kubernetes / non-Kubernetes cloud that you can create on your local workstation.

Juju supports a wide range of clouds—public or private, Kubernetes or not. If you want to follow this tutorial with a different cloud, see Supported clouds.

Expand to see the instructions for MicroK8s

When strictly confined MicroK8s is released, the group you need to be a member of changes to snap_microk8s.

Execute the code below to install and configure MicroK8s:

# Install Microk8s from snap:
sudo snap install microk8s --channel 1.25-strict/stable

# Add the 'ubuntu' user to the MicroK8s group:
sudo usermod -a -G snap_microk8s ubuntu

# Give the 'ubuntu' user permissions to read the ~/.kube directory:
sudo chown -f -R ubuntu ~/.kube

# Create the 'microk8s' group:
newgrp snap_microk8s

# Enable the necessary MicroK8s addons:
sudo microk8s enable hostpath-storage dns

# Set up a short alias for the Kubernetes CLI:
sudo snap alias microk8s.kubectl kubectl
Expand to see the instructions for LXD

LXD should be already installed in your Ubuntu system. Execute the code below to configure it:

lxd init --auto
lxc network set lxdbr0 ipv6.address none

Install the Juju CLI client

We will now install the Juju CLI client via snap:

sudo snap install juju --channel 3.1/stable

If the installation was successful, you will see a message similar to the one below:

juju (3.1/stable) 3.1.5 from Canonical✓ installed

Since the Juju package is strictly confined, you also need to manually create a path:

mkdir -p ~/.local/share

Register your cloud with Juju

We have our cloud. Now, let’s register it with Juju!

This always involves the same basic logic:

  1. Add your cloud to Juju.
  2. Add your cloud credentials to Juju.

However, the process differs a little bit depending on whether the cloud is Kubernetes or not. And, depending on the cloud, at least one of these steps may be implicit.

Expand to see the process for MicroK8s

For a Kubernetes cloud, both these logical steps are done in one go, via juju add-k8s. However, for the MicroK8s cloud all of this happens implicitly, as detailed below.

Beginning with Juju v.3.0-beta1 and until MicroK8s releases a strictly confined snap, these steps will have to be done explicitly via juju add-k8s --client <microk8s cloud name> for MicroK8s too.

Juju recognizes your MicroK8s cloud automatically. You can already see it if you run:

juju clouds
Cloud      Regions  Default    Type  Credentials  Source    Description
microk8s   1        localhost  k8s   1            built-in  A Kubernetes Cluster

The credentials are also retrieved automatically. You’re ready to start managing your MicroK8s cloud with Juju!

Expand to see the process for LXD

For a non-Kubernetes cloud, these logical steps are achieved sequentially via juju add-cloud and juju add-credential / juju autoload-credentials. However, for the LXD cloud all of this happens implicitly, as described below.

Juju recognizes your LXD cloud automatically. You can already see it if you run:

juju clouds
Cloud      Regions  Default    Type  Credentials  Source    Description
localhost  1        localhost  lxd   1            built-in  LXD Container Hypervisor

In the juju clouds output, somewhat confusingly, both Cloud and Default are given as localhost. However, in the first case this refers to the name of your LXD cloud whereas in the second it refers to the default cloud region, which in this case is just your local host (just as for the MicroK8s cloud, in case you noticed).

The credentials are also retrieved automatically. You’re ready to start managing your LXD cloud with Juju!

At this point what you have there is just cloud infrastructure, an empty cloud. There are no resources being used yet.

Install a Juju controller in your cloud

Time for things to get real! Let’s bootstrap a controller named tutorial-controller into our cloud! The process is the same for any cloud—just make sure to put in the name of the cloud you want.

juju bootstrap <cloud name> tutorial-controller
Expand to see the code with the MicroK8s cloud name
juju bootstrap microk8s tutorial-controller
Expand to see the code with the LXD cloud name
juju bootstrap localhost tutorial-controller

At this point you are beginning to use resources.

Create a workspace on your cloud

The next step is to create a workspace on your cloud. We do this by creating a model, as shown below. We will name ours tutorial-model.

juju add-model tutorial-model

Deploy applications on your workspace

We’ve got our workspace. Let’s start deploying applications!

To deploy an application with Juju you need to:

  1. Find a suitable cham on Charmhub.

A charm is an operator - business logic encapsulated in reusable software packages that automate every aspect of an application’s life. Juju creates and manages the application based on the instructions contained in the charm. Charms are usually named after the application they represent. Charmhub is the official home of charms.

For a Kubernetes cloud, choose a Kubernetes charm, and for a non-Kubernetes cloud choose a non-Kubernetes charm.

Starting with juju v.3.0, charms that require xenial or bionic are no longer supported.

  1. Deploy the charm, as shown below. Juju will pull the charm from Charmhub and then install the application on your cloud.
juju deploy <charm name>
Expand to deploy Mattermost and PostgreSQL on MicroK8s

Let’s deploy mattermost-k8s, the Kubernetes charm for Mattermost, an application that provides a chat service:

juju deploy mattermost-k8s

When deployed, this outputs:

Located charm "mattermost-k8s" in charm-hub, revision 24
Deploying "mattermost-k8s" from charm-hub charm "mattermost-k8s", revision 24 in channel stable on ubuntu@20.04/stable

You can observe the deployment status with the following command:

juju status --watch 1s

But Mattermost requires a database service. Let’s deploy postgresql-k8s, the Kubernetes charm for PostgreSQL, also:

juju deploy postgresql-k8s

When deployed, this outputs:

Located charm "postgresql-k8s" in charm-hub, revision 73
Deploying "postgresql-k8s" from charm-hub charm "postgresql-k8s", revision 73 in channel 14/stable on ubuntu@22.04/stable

That’s it. Your applications are now deployed.

Expand to deploy Keystone and MySQL on LXD

Let’s deploy keystone, the non-Kubernetes charm for Keystone, an application that provides OpenStack’s Identity service:

juju deploy keystone --base ubuntu@20.04

When deployed, this outputs:

Located charm "keystone" in charm-hub, revision 539
Deploying "keystone" from charm-hub charm "keystone", revision 539 in channel stable on ubuntu@20.04/stable

You can observe the deployment status with the following command:

juju status --watch 1s

But Keystone requires a database service. Let’s also install mysql, the non-Kubernetes charm for MySQL:

Keystone is normally deployed with mysql-innodb-cluster, but this requires a 3-unit cluster to be instantiated. For simplicity, we will deploy with mysql.

juju deploy mysql --channel edge

When deployed, this outputs:

Located charm "mysql" in charm-hub, revision 167
Deploying "mysql" from charm-hub charm "mysql", revision 167 in channel 8.0/edge on ubuntu@22.04/stable

That’s it. Your applications are now deployed.

Integrate your applications

We’ve deployed two applications that look like they need to work together. However, currently, they don’t; we need to integrate them. In Juju, integrating applications is a first class operation that can be done straightforwardly via:

juju integrate <charm 1> <charm 2>

Before juju v.3.0, integrate was relate. Remnants of this persist in some command names, options, and outputs.

Expand to integrate Mattermost and PostgreSQL on MicroK8s

Mattermost expects TLS-encrypted traffic from PostgreSQL. However, the PostgreSQL charm does not have that by default. According to the documentation of the charm, we can address this by enhancing the postgresql-k8s charm with the tls-certificates-operator charm, as below:

juju deploy tls-certificates-operator
juju config tls-certificates-operator generate-self-signed-certificates="true" ca-common-name="Test CA"
juju integrate postgresql-k8s tls-certificates-operator

See more:Charmhub | mattermost-k8s > Deploy and relate database

Now we can proceed to integrate Mattermost with PostgreSQL, as below:

juju integrate mattermost-k8s postgresql-k8s:db

The : after postgresql-k8s signifies the db endpoint.

You can again observe the deployment status with the following command:

juju status --watch 1s

That’s it. Your applications now know about each other and are ready to work together.

Expand to integrate Keystone and MySQL on LXD
juju integrate keystone mysql

You can again observe the deployment status with the following command:

juju status --watch 1s

Wait until the workload reaches active status.

That’s it. Your applications now know about each other and are ready to work together.

Test your deployment

You’ve integrated your applications. You now have a functional working system. Time to try it out!

Expand to test your Mattermost deployment on MicroK8s

Execute the code below to get the IP address of your Mattermost app:

juju status

Example output:

Model           Controller               Cloud/Region        Version  SLA          Timestamp
tutorial-model  tutorial-controller-k8s  microk8s/localhost  3.1.5    unsupported  14:53:15+02:00

App                        Version                         Status  Scale  Charm                      Channel    Rev  Address         Exposed  Message
mattermost-k8s             .../mattermost:v7.1.4-20.04...  active      1  mattermost-k8s             stable      25  10.152.183.194  no       
postgresql-k8s             14.7                            active      1  postgresql-k8s             14/stable   73  10.152.183.163  no       
tls-certificates-operator                                  active      1  tls-certificates-operator  stable      22  10.152.183.83   no       

Unit                          Workload  Agent  Address       Ports     Message
mattermost-k8s/4*             active    idle   10.1.170.145  8065/TCP  
postgresql-k8s/0*             active    idle   10.1.170.138            Primary
tls-certificates-operator/0*  active    idle   10.1.170.144            

Now, use the IP address and the port of mattermost-k8s to check that the application is running, on the template below:

curl <IP address>:<port>/api/v4/system/ping

Given our example output, this would be:

curl 10.1.170.145:8065/api/v4/system/ping

You should see the following:

{"AndroidLatestVersion":"","AndroidMinVersion":"","IosLatestVersion":"","IosMinVersion":"","status":"OK"}

Congratulations, your Mattermost application is ready to use!

Note: if you get 404 page, restart your Multipass VM and try again


(OPTIONAL) Access MicroK8s from the host machine

If you would like to reach your Mattermost instance from your host machine (e.g., in a web browser), you will need to set up IP routes.

By default, MicroK8s will set up a sub-network for the running apps. However, since we’re running MicroK8s on a VM, we need to expose this sub-network to the host.

First, let’s get the IP range of our service addresses. On your Multipass instance, run

juju status

See command output above

or else run

microk8s kubectl -n tutorial-model get svc

Example output:

NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
modeloperator              ClusterIP   10.152.183.131   <none>        17071/TCP        6d23h
mattermost-k8s-operator    ClusterIP   10.152.183.142   <none>        30666/TCP        6d23h
postgresql-k8s-operator    ClusterIP   10.152.183.240   <none>        30666/TCP        6d23h
postgresql-k8s-master      NodePort    10.152.183.37    <none>        5432:31056/TCP   6d23h
postgresql-k8s-standbys    NodePort    10.152.183.241   <none>        5432:32357/TCP   6d23h
postgresql-k8s             ClusterIP   10.152.183.103   <none>        5432/TCP         6d23h
postgresql-k8s-endpoints   ClusterIP   None             <none>        <none>           6d23h
mattermost-k8s             ClusterIP   10.152.183.185   <none>        8065/TCP         6d23h

From the example output above you can see that Mattermost is running as a Kubernetes service with IP 10.152.183.185 and that the MicroK8s network is 10.152.183.0/24 (10.152.183.XXX).

The next step will be to get the IP address of the VM. You can get it by either running inside of the Multipass instance:

ip -br address show scope global

or by running from your host

multipass info <vm name>

Example output, where the VM IP is 10.112.13.219:

Name:           vivid-kakapo
State:          Running
IPv4:           10.112.13.219
                10.1.179.128
Release:        Ubuntu 20.04.4 LTS
Image hash:     77f2f05e39e5 (Ubuntu 20.04 LTS)
Load:           0.36 0.51 0.45
Disk usage:     8.6G out of 19.2G
Memory usage:   1.3G out of 7.8G
Mounts:         --

Now, add a static route from our host to MicroK8s subnetwork using Multipass VM IP as a gateway. You can do that by running:

sudo ip route add <MicroK8s subnetwork> via <VM IP>

In our case:

sudo ip route add 10.152.183.0/24 via 10.112.13.219

Finally, in a web browser, open the Mattermost URL (see juju status for the Mattermost IP and port):

http://10.152.183.185:8065

Expand to test your Keystone deployment on LXD

Execute the code below to get the IP address of your Keystone instance:

juju status

Now, use the IP address as shown below to check that the application is running:

curl 'http://<IP address>:5000/'

You should see the following:

{"versions": {"values": [{"id": "v3.14", "status": "stable", "updated": "2020-04-07T00:00:00Z", "links": [{"rel": "self", "href": "http://10.251.113.159:5000/v3/"}], "media-types": [{"base": "application/json", "type": "application/vnd.openstack.identity-v3+json"}]}]}}%

Congratulations, your Keystone application is ready to use!

Destroy the test environment

Once you are done, you can run the code below to stop and delete your Multipass test environment.

# Stop your instance
multipass stop tutorial-vm

# Delete your instance permanently
multipass delete --purge tutorial-vm 

You can also uninstall Multipass to remove any trace of this guide.

Next steps

This tutorial has introduced you to the basic things you can do with Juju. But there is a lot more to explore:

If you are wondering… visit…
“How do I…?” Juju How-to docs
“What is…?” Juju Reference docs
“Why…?”, “So what?” Juju Explanation docs
“How do I build a charm?” SDK docs
“How do I contribute to Juju?” Dev docs

Last updated 2 months ago.