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:
- Create the test environment
- Prepare your cloud
- Install the Juju CLI client
- Register your cloud with Juju
- Install a Juju controller in your cloud
- Create a workspace on your cloud
- Deploy applications on your workspace
- Integrate your applications
- Test your deployment
- Destroy the test environment
- 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:
- Add your cloud to Juju.
- 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:
- 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.
- 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.