Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ As a charm developer, your first job is to use this knowledge to create the basi

## Set the basic information, requirements, and workload for your charm

Create a file called `charmcraft.yaml`. This is a file that describes metadata such as the charm name, purpose, environment constraints, workload containers, etc., in short, all the information that tells Juju what it can do with your charm.
In your virtual machine, go into your project directory `~/fastapi-demo`, then create a file called `charmcraft.yaml`. This is a file that describes metadata such as the charm name, purpose, environment constraints, workload containers, etc., in short, all the information that tells Juju what it can do with your charm.

In this file, do all of the following:

Expand Down Expand Up @@ -303,7 +303,7 @@ Once you've mastered the basics, you can speed things up by navigating to your e
First, ensure that you are inside the Multipass Ubuntu VM, in the `~/fastapi-demo` folder:

```
multipass shell charm-dev
multipass shell juju-sandbox-k8s
cd ~/fastapi-demo
```

Expand All @@ -326,7 +326,7 @@ If packing failed - perhaps you forgot to make `charm.py` executable earlier - y

```

<!--ubuntu@charm-dev:~/fastapi-demo$ charmcraft pack-->
<!--ubuntu@juju-sandbox-k8s:~/fastapi-demo$ charmcraft pack-->

<!-- `charmcraft pack` just fetches the dependencies, compiles any modules, makes sure you have all the right pieces of metadata, and zips it up for easy distribution.
-->
Expand Down Expand Up @@ -362,8 +362,8 @@ juju status --watch 1s
When all units are settled down, you should see the output below, where `10.152.183.215` is the IP of the K8s Service and `10.1.157.73` is the IP of the pod.

```text
Model Controller Cloud/Region Version SLA Timestamp
welcome-k8s microk8s microk8s/localhost 3.6.8 unsupported 13:38:19+01:00
Model Controller Cloud/Region Version SLA Timestamp
testing concierge-microk8s microk8s/localhost 3.6.12 unsupported 13:38:19+01:00

App Version Status Scale Charm Channel Rev Address Exposed Message
demo-api-charm active 1 demo-api-charm 0 10.152.183.215 no
Expand Down Expand Up @@ -394,12 +394,12 @@ Congratulations, you've successfully created a minimal Kubernetes charm!
kubectl get namespaces
```

You should see that Juju has created a namespace called `welcome-k8s`.
You should see that Juju has created a namespace called `testing`.

2. Try:

```text
kubectl -n welcome-k8s get pods
kubectl -n testing get pods
```

You should see that your application has been deployed in a pod that has 2 containers running in it, one for the charm and one for the application. The containers talk to each other via the Pebble API using the UNIX socket.
Expand All @@ -413,7 +413,7 @@ demo-api-charm-0 2/2 Running 0 10m
3. Check also:

```text
kubectl -n welcome-k8s describe pod demo-api-charm-0
kubectl -n testing describe pod demo-api-charm-0
```

In the output you should see the definition for both containers. You'll be able to verify that the default command and arguments for our application container (`demo-server`) have been displaced by the Pebble service. You should be able to verify the same for the charm container (`charm`).
Expand Down Expand Up @@ -536,7 +536,7 @@ def test_pebble_layer():
In your Multipass Ubuntu VM shell, run your test:

```text
ubuntu@charm-dev:~/fastapi-demo$ tox -e unit
ubuntu@juju-sandbox-k8s:~/fastapi-demo$ tox -e unit
```

The result should be similar to the following output:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ Running operation 1 with 1 task
- task 2 on unit-demo-api-charm-0

Waiting for task 2...
db-host: postgresql-k8s-primary.welcome-k8s.svc.cluster.local
db-host: postgresql-k8s-primary.testing.svc.cluster.local
db-port: "5432"
```

Expand All @@ -144,7 +144,7 @@ Running operation 3 with 1 task
- task 4 on unit-demo-api-charm-0

Waiting for task 4...
db-host: postgresql-k8s-primary.welcome-k8s.svc.cluster.local
db-host: postgresql-k8s-primary.testing.svc.cluster.local
db-password: RGv80aF9WAJJtExn
db-port: "5432"
db-username: relation_id_4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ This tells Charmcraft that your charm requires the [`data_interfaces`](https://c
Next, run the following command to download the library:

```text
ubuntu@charm-dev:~/fastapi-demo$ charmcraft fetch-libs
ubuntu@juju-sandbox-k8s:~/fastapi-demo$ charmcraft fetch-libs
```

Your charm directory should now contain the structure below:
Expand Down Expand Up @@ -379,8 +379,8 @@ juju status --relations --watch 1s
You should see both applications get to the `active` status, and also that the `postgresql-k8s` charm has a relation to the `demo-api-charm` over the `postgresql_client` interface, as below:

```text
Model Controller Cloud/Region Version SLA Timestamp
welcome-k8s microk8s microk8s/localhost 3.6.8 unsupported 13:50:39+01:00
Model Controller Cloud/Region Version SLA Timestamp
testing concierge-microk8s microk8s/localhost 3.6.12 unsupported 13:50:39+01:00

App Version Status Scale Charm Channel Rev Address Exposed Message
demo-api-charm active 1 demo-api-charm 2 10.152.183.233 no
Expand Down Expand Up @@ -536,7 +536,7 @@ def test_database_integration(juju: jubilant.Juju):
In your Multipass Ubuntu VM, run the test again:

```text
ubuntu@charm-dev:~/fastapi-demo$ tox -e integration
ubuntu@juju-sandbox-k8s:~/fastapi-demo$ tox -e integration
```

The test may again take some time to run.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,8 @@ juju status
As expected, the application is indeed in the `blocked` state:

```text
Model Controller Cloud/Region Version SLA Timestamp
welcome-k8s microk8s microk8s/localhost 3.6.8 unsupported 18:19:24+01:00
Model Controller Cloud/Region Version SLA Timestamp
testing concierge-microk8s microk8s/localhost 3.6.12 unsupported 18:19:24+01:00

App Version Status Scale Charm Channel Rev Address Exposed Message
demo-api-charm blocked 1 demo-api-charm 1 10.152.183.215 no Invalid port number, 22 is reserved for SSH
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ charm-libs:
Next, run the following command to download the libraries:

```text
ubuntu@charm-dev:~/fastapi-demo$ charmcraft fetch-libs
ubuntu@juju-sandbox-k8s:~/fastapi-demo$ charmcraft fetch-libs
```

Your charm directory should now include the structure below:
Expand Down Expand Up @@ -282,14 +282,14 @@ microk8s admin/cos-lite.prometheus admin prometheus_scrape:metrics-endpoint
microk8s admin/cos-lite.grafana admin grafana_dashboard:grafana-dashboard
```

As you might notice from your knowledge of Juju, this is essentially preparing these endpoints, which exist in the `cos-lite` model, for a cross-model relation with your charm, which you've deployed to the `welcome-k8s` model.
As you might notice from your knowledge of Juju, this is essentially preparing these endpoints, which exist in the `cos-lite` model, for a cross-model relation with your charm, which you've deployed to the `testing` model.

## Integrate your charm with COS Lite

Now switch back to the charm model and integrate your charm with the exposed endpoints, as below. This effectively integrates your application with Prometheus, Loki, and Grafana.

```text
juju switch welcome-k8s
juju switch testing
juju integrate demo-api-charm admin/cos-lite.grafana
juju integrate demo-api-charm admin/cos-lite.loki
juju integrate demo-api-charm admin/cos-lite.prometheus
Expand All @@ -311,8 +311,8 @@ juju status -m cos-lite
This should result in an output similar to the one below:

```text
Model Controller Cloud/Region Version SLA Timestamp
cos-lite microk8s microk8s/localhost 3.6.8 unsupported 18:05:07+01:00
Model Controller Cloud/Region Version SLA Timestamp
cos-lite concierge-microk8s microk8s/localhost 3.6.12 unsupported 18:05:07+01:00

App Version Status Scale Charm Channel Rev Address Exposed Message
alertmanager 0.27.0 active 1 alertmanager-k8s 1/stable 160 10.152.183.70 no
Expand All @@ -333,13 +333,13 @@ Do not mix up Apps and Units -- Units represent Kubernetes pods while Apps repre
Now open a terminal on your host machine and run:

```text
multipass info charm-dev
multipass info juju-sandbox-k8s
```

This should result in an output similar to the one below:

```text
Name: charm-dev
Name: juju-sandbox-k8s
State: Running
IPv4: 10.112.13.157
10.49.132.1
Expand All @@ -349,7 +349,7 @@ Image hash: 1d24e397489d (Ubuntu 22.04 LTS)
Load: 0.31 0.25 0.28
Disk usage: 15.9G out of 19.2G
Memory usage: 2.1G out of 7.8G
Mounts: /home/maksim/fastapi-demo => ~/fastapi-demo
Mounts: /home/me/k8s-tutorial => ~/fastapi-demo
UID map: 1000:default
GID map: 1000:default
```
Expand Down Expand Up @@ -390,7 +390,7 @@ http://10.152.183.132:3000/?orgId=1&search=open
Click on `FastAPI Monitoring`
-->

Next, in the `Juju model` drop down field, select `welcome-k8s`.
Next, in the `Juju model` drop down field, select `testing`.

Now, call a couple of API points on the application, as below. To produce some successful requests and some requests with code 500 (internal server error), call several times, in any order.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,126 @@
>
> **See previous: {ref}`Study your application <study-your-application>`**
In this chapter of the tutorial you will set up your development environment.

You will need a charm directory, the various tools in the charm SDK, Juju, and a Kubernetes cloud. And it’s a good idea if you can do all your work in an isolated development environment.

To set all of this up, see {external+juju:ref}`Juju | Manage your deployment > Set up your deployment - local testing and development <set-things-up>`, with the following changes:

- At the directory step, call your directory `fastapi-demo`.
- At the VM setup step, call your VM `charm-dev`. Also set up Docker:
```text
sudo addgroup --system docker
sudo adduser $USER docker
newgrp docker
sudo snap install docker
```
- At the cloud selection step, choose `microk8s`.
- At the mount step, read the tips about how to edit files locally while running them inside the VM.
## Create a virtual machine

You'll deploy and test your charm inside an Ubuntu virtual machine that's running on your computer. Your virtual machine will provide an isolated environment that's safe for you to experiment in, without affecting your host machine. This is especially helpful for the charm's integration tests, which require a local Juju controller and Kubernetes cloud.

First, install Multipass for managing virtual machines. See the [installation instructions](https://canonical.com/multipass/install).

Next, open a terminal, then run:

```text
multipass launch --cpus 4 --memory 8G --disk 50G --name juju-sandbox-k8s
```

This creates a virtual machine called `juju-sandbox-k8s`.

Multipass allocates some of your computer's memory and disk space to your virtual machine. The options we've chosen for `multipass launch` ensure that your virtual machine will be powerful enough to run Juju and deploy medium-sized charms.

This step should take less than 10 minutes, but the time depends on your computer and network. When your virtual machine has been created, you'll see the message:

```text
Launched: juju-sandbox-k8s
```

Now run:

```text
multipass shell juju-sandbox-k8s
```

This switches the terminal so that you're working inside your virtual machine.

You'll see a message with information about your virtual machine. You'll also see a new prompt:

```text
ubuntu@juju-sandbox-k8s:~$
```

## Install Juju and charm development tools

Now that you have a virtual machine, you need to install the following tools on your virtual machine:

- **Charmcraft, Juju, and MicroK8s** - You'll use {external+charmcraft:doc}`Charmcraft <index>` to create the initial version of your charm and prepare your charm for deployment. When you deploy your charm, Juju will use MicroK8s to create a Kubernetes cloud for your charm.
- **uv** - Your charm will be a Python project. You'll use [uv](https://docs.astral.sh/uv/) to manage your charm's runtime and development dependencies.
- **tox** - You'll use [tox](https://tox.wiki/en/) to run your charm's checks and tests.

Instead of manually installing and configuring each tool, we recommend using [Concierge](https://github.com/canonical/concierge), Canonical's tool for setting up charm development environments.

In your virtual machine, run:

```text
sudo snap install --classic concierge
sudo concierge prepare -p microk8s --extra-snaps astral-uv
```

This first installs Concierge, then uses Concierge to install and configure the other tools (except tox). The option `-p microk8s` tells Concierge that we want tools for developing Kubernetes charms, with a local cloud managed by MicroK8s.

This step should take less than 15 minutes, but the time depends on your computer and network. When the tools have been installed, you'll see a message that ends with:

```text
msg="Bootstrapped Juju" provider=microk8s
```

To install tox, run:

```text
uv tool install tox --with tox-uv
```

When tox has been installed, you'll see a confirmation and a warning:

```text
Installed 1 executable: tox
warning: `/home/ubuntu/.local/bin` is not on your PATH. To use installed tools,
run `export PATH="/home/ubuntu/.local/bin:$PATH"` or `uv tool update-shell`.
```

Instead of following the warning, exit your virtual machine:

```text
exit
```

The terminal switches back to your host machine. Your virtual machine is still running.

Next, stop your virtual machine:

```text
multipass stop juju-sandbox-k8s
```

Then use the Multipass {external+multipass:ref}`snapshot <reference-command-line-interface-snapshot>` command to take a snapshot of your virtual machine:

```text
multipass snapshot juju-sandbox-k8s
```

If you have any problems with your virtual machine during or after completing the tutorial, use the Multipass {external+multipass:ref}`restore <reference-command-line-interface-restore>` command to restore your virtual machine to this point.

## Create a project directory

Although you'll deploy and test your charm inside your virtual machine, you'll probably find it more convenient to write your charm using your usual text editor or IDE.

Outside your virtual machine, create a project directory:

```text
mkdir ~/k8s-tutorial
```

You'll write your charm in this directory.

Next, use the Multipass {external+multipass:ref}`mount <reference-command-line-interface-mount>` command to make the directory available inside your virtual machine:

```text
multipass mount --type native ~/k8s-tutorial juju-sandbox-k8s:~/fastapi-demo
```

Finally, start your virtual machine and switch to your virtual machine:
Copy link

Copilot AI Dec 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The phrase "start your virtual machine and switch to your virtual machine" is redundant. Consider simplifying to "Finally, start and connect to your virtual machine:" or "Finally, start your virtual machine and open a shell:"

Suggested change
Finally, start your virtual machine and switch to your virtual machine:
Finally, start and connect to your virtual machine:

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm OK with the current wording, but agree this could be less clunky. I'll see whether anyone else has a preference.


```text
multipass shell juju-sandbox-k8s
```

Congratulations, your development environment is ready!

Expand Down
3 changes: 2 additions & 1 deletion docs/tutorial/write-your-first-machine-charm.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ ubuntu@juju-sandbox:~$
Now that you have a virtual machine, you need to install the following tools on your virtual machine:

- **Charmcraft, Juju, and LXD** - You'll use {external+charmcraft:doc}`Charmcraft <index>` to create the initial version of your charm and prepare your charm for deployment. When you deploy your charm, Juju will use LXD to manage the machine where your charm runs.
- **uv and tox** - You'll implement your charm using Python code. [uv](https://docs.astral.sh/uv/) is a Python project manager that will install dependencies for checks and tests. You'll use [tox](https://tox.wiki/en/) to select which checks or tests to run.
- **uv** - Your charm will be a Python project. You'll use [uv](https://docs.astral.sh/uv/) to manage your charm's runtime and development dependencies.
- **tox** - You'll use [tox](https://tox.wiki/en/) to run your charm's checks and tests.
Comment on lines -84 to +85
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this because "uv [...] install dependencies for checks and tests" was incomplete. In the tutorial, we use uv to install runtime dependencies too (charmlibs and pydantic).


Instead of manually installing and configuring each tool, we recommend using [Concierge](https://github.com/canonical/concierge), Canonical's tool for setting up charm development environments.

Expand Down