Write your first Kubernetes charm for a FastAPI app on Ubuntu 26.04 LTS¶
Imagine you have a FastAPI app backed up by a database such as PostgreSQL and need to deploy it. In a traditional setup, this can be quite a challenge, but with Charmcraft you’ll find yourself packaging and deploying your FastAPI app in no time.
Introduction¶
In this tutorial we will build a Kubernetes charm for a FastAPI app using Charmcraft, so we can have a FastAPI app up and running with Juju. Let’s get started!
This tutorial should take 90 minutes for you to complete.
If you’re new to the charming world, FastAPI apps are specifically supported with a template to quickly generate a rock and a matching template to generate a charm. A rock is a special kind of OCI-compliant container image, while a charm is a software operator for cloud operations that use the Juju orchestration engine. The combined result is a FastAPI app that can be deployed, configured, scaled, integrated, and so on, on any Kubernetes cluster.
What you’ll need¶
A local system, e.g., a laptop, with AMD64 or ARM64 architecture which has sufficient resources to launch a virtual machine with 4 CPUs, 8 GB RAM, and a 60 GB disk.
Familiarity with Linux.
The RAM and disk space are necessary to set up all the required software and to facilitate the creation of the rock and charm. If your local system has less than the sufficient resources, the tutorial will take longer to complete.
What you’ll do¶
Create a FastAPI app.
Use that to create a rock with Rockcraft.
Use that to create a charm with Charmcraft.
Use that to test, deploy, configure, etc., your FastAPI app on a local Kubernetes cloud with Juju.
Repeat the process, mimicking a real development process.
Set things up¶
First, install Multipass.
Launch an Ubuntu 26.04 VM named charm-dev:
multipass launch --cpus 4 --disk 60G --memory 8G --name charm-dev 26.04 multipass shell charm-dev
Unless stated otherwise, work entirely within the VM from now on.
Install Rockcraft, Charmcraft, and uv¶
For the Ubuntu 26.04 extensions, use the candidate release of Rockcraft and the edge release of Charmcraft. Install these tools and uv, the charm’s Python dependency manager, with classic confinement, which grants them access to the whole file system:
sudo snap install rockcraft --channel latest/candidate --classic
sudo snap install charmcraft --channel latest/edge --classic
sudo snap install astral-uv --classic
Install LXD, Canonical Kubernetes, and Juju¶
LXD provides the build environment for the rock and charm. Make sure it is installed:
lxd --version
If LXD is not installed, install it with sudo snap install lxd.
Initialize LXD:
lxd init --auto
Canonical Kubernetes will host the FastAPI app and PostgreSQL. Install the Kubernetes and Juju snaps:
sudo snap install k8s --channel 1.34-classic/stable --classic
sudo snap install juju --channel 3.6/stable
Bootstrap a single-node cluster and enable local storage and Gateway API:
sudo k8s bootstrap --timeout 10m
sudo k8s status --wait-ready --timeout 10m
sudo k8s enable local-storage
sudo k8s enable gateway
The --wait-ready option waits for the cluster to become ready.
Local storage supplies the volumes needed by Juju, PostgreSQL, and the image registry.
Gateway API supplies the ingress controller used later in the tutorial.
Configure the load balancer to use the VM’s address, so the app will be accessible from outside the VM. Enable the load balancer:
sudo k8s enable load-balancer
sudo k8s kubectl wait --for=condition=Accepted gatewayclass/ck-gateway --timeout=5m
Save the node’s internal address in an environment variable and use it to set the address range for the load balancer:
export VM_IP=$(sudo k8s kubectl get nodes \
-o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
sudo k8s set load-balancer.cidrs="${VM_IP}/32"
printf 'VM address: %s\n' "$VM_IP"
Keep the printed VM address for any browser checks on your host machine.
Later, the gateway action will return the full deployed app URL for browser
and curl checks. The VM_IP variable is local to this VM terminal;
it is not available in terminals on your host machine.
Create a local image registry¶
Canonical Kubernetes doesn’t include a registry addon. We’ll deploy an OCI
registry in the cluster to store the rocks built during this tutorial.
Download the registry manifest from the paas-charm repository:
curl --fail --location --output registry.yaml \
https://raw.githubusercontent.com/canonical/paas-charm/main/docs/reuse/tutorial/registry_26_04.yaml
Apply the downloaded registry.yaml and wait for the registry to be ready:
sudo k8s kubectl apply -f registry.yaml
sudo k8s kubectl rollout status deployment/registry \
-n charm-tutorial-registry --timeout=5m
curl --fail --retry 30 --retry-connrefused --retry-delay 2 "http://localhost:32000/v2/"
You can access the registry at localhost:32000 from within the VM.
It uses a persistent volume so its images survive pod restarts.
The NodePort service also exposes port 32000 on the VM’s network interfaces.
Bootstrap Juju¶
Register Canonical Kubernetes as a Juju cloud, then bootstrap the development controller:
mkdir -p ~/.local/share
sudo k8s config | juju add-k8s k8s --client
juju bootstrap k8s dev-controller --config bootstrap-timeout=600
It can take a few minutes to download the controller images.
The Ubuntu 26.04 extensions are experimental. Enable them for both tools in the terminal where you’ll build the rock and charm:
export ROCKCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=1
export CHARMCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=1
Let’s create a directory for this tutorial and enter into it:
mkdir fastapi-hello-world
cd fastapi-hello-world
Finally, install python-venv and create a virtual environment:
sudo apt update && sudo apt install python3-venv -y
python3 -m venv .venv
source .venv/bin/activate
Create the FastAPI app¶
Start by creating the “Hello, world” FastAPI app that will be used for this tutorial.
Create a new requirements file with nano requirements.txt.
Then, copy the following text into it, and save:
fastapi[standard]==0.142.2
psycopg2-binary==2.9.13
Note
The psycopg2-binary package is needed so the FastAPI app can
connect to PostgreSQL, which we will do at the end of this tutorial.
Install the packages:
pip install -r requirements.txt
In the same directory, create a file called app.py.
Then copy and save the following code into the file:
from fastapi import FastAPI
from fastapi.responses import PlainTextResponse
app = FastAPI()
@app.get("/", response_class=PlainTextResponse)
async def root():
return "Hello world!"
Run the FastAPI app locally¶
Now that we have a virtual environment with all the dependencies, let’s run the FastAPI app to verify that it works:
fastapi dev app.py --port 8080
Verify the app¶
Test the FastAPI app by using curl to send a request to the root
endpoint. You will need a new terminal for this; use
multipass shell charm-dev to open a new terminal in Multipass:
curl localhost:8080
The FastAPI app should respond with Hello world!.
Close the app¶
The FastAPI app looks good, so we can stop for now from the original terminal using Ctrl + C.
Pack the FastAPI app into a rock¶
Now let’s create a container image for our FastAPI app. We’ll use a rock, which is an OCI-compliant container image based on Ubuntu.
First, we’ll need a rockcraft.yaml project file. We’ll take advantage of a
pre-defined extension in Rockcraft with the --profile flag that caters
initial rock files for specific web app frameworks. Using the
fastapi-framework profile, Rockcraft automates the creation of
rockcraft.yaml and tailors the file for a FastAPI app.
From the ~/fastapi-hello-world directory, initialize the rock:
rockcraft init --profile fastapi-framework --base ubuntu@26.04
The rockcraft.yaml file will be automatically created, with the name being
set based on your working directory.
The Ubuntu 26.04 profile uses a bare runtime base and Ubuntu 26.04 as its build environment. Keep these generated settings.
Let’s verify that the project file is compatible with your host machine. Check the architecture of your system:
dpkg --print-architecture
Check out the contents of rockcraft.yaml:
cat rockcraft.yaml
The top of the file should look similar to the following snippet:
# See https://documentation.ubuntu.com/rockcraft/1/reference/extensions/fastapi-framework
# For questions or help, visit https://matrix.to/#/#12-factor-charms:ubuntu.com
name: fastapi-hello-world
# see https://documentation.ubuntu.com/rockcraft/1/explanation/bases/
# for more information about bases and using 'bare' bases for chiselled rocks
base: bare # as an alternative, an ubuntu base can be used
build-base: ubuntu@26.04 # build-base is required when the base is bare
version: '0.1' # just for humans. Semantic versioning is recommended
summary: A summary of your FastAPI application # 79 char long summary
description: |
This is fastapi project's description. You have a paragraph or two to tell the
most important story about it. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the
container registries out there.
# the platforms this rock should be built on and run on.
# you can check your architecture with `dpkg --print-architecture`
platforms:
amd64:
# arm64:
# ppc64el:
# s390x:
Verify that the name is fastapi-hello-world.
The platforms key must match the architecture of your host.
Edit the platforms key in rockcraft.yaml if required.
Now let’s pack the rock:
rockcraft pack
Depending on your system and network, this step can take several minutes to finish.
Once Rockcraft has finished packing the FastAPI rock,
the terminal will respond with something similar to
Packed fastapi-hello-world_0.1_<architecture>.rock. The file name
reflects your system’s architecture. After the initial
pack, subsequent rock packings are faster.
The rock needs to be copied to the local OCI registry. This registry acts as a temporary Docker Hub, storing OCI archives so they can be downloaded and deployed in the Kubernetes cluster. Copy the rock:
rockcraft.skopeo copy \
--insecure-policy \
--dest-tls-verify=false \
oci-archive:fastapi-hello-world_0.1_$(dpkg --print-architecture).rock \
docker://localhost:32000/fastapi-hello-world:0.1
This command contains the following pieces:
--insecure-policy: adopts a permissive policy that removes the need for a dedicated policy file.--dest-tls-verify=false: disables the need for HTTPS and verify certificates while interacting with the local OCI registry.oci-archive: specifies the rock we created for our FastAPI app.docker: specifies the name of the image in the local OCI registry.
Create the charm¶
From the ~/fastapi-hello-world directory, let’s create a new directory
for the charm and go inside it:
mkdir charm
cd charm
Similar to the rock, we’ll take advantage of a pre-defined extension in
Charmcraft with the --profile flag that caters initial charm files for
specific web app frameworks. Using the fastapi-framework profile,
Charmcraft automates the creation of the files needed for our charm,
including a charmcraft.yaml project file, pyproject.toml and source
code for the charm. The source code contains the logic required to operate the
FastAPI app.
Initialize a charm named fastapi-hello-world:
charmcraft init --profile fastapi-framework --name fastapi-hello-world --base ubuntu@26.04
The files will automatically be created in your working directory.
The Ubuntu 26.04 profile uses the uv plugin and pyproject.toml for
the charm dependencies. These dependencies are separate from those of
your web app. Use uv, installed during setup, to create the lockfile before packing:
uv lock
The charm needs to know which port the app listens on. paas-config.yaml
contains settings that the charm uses to run your app. Charmcraft packages this
file with the charm, and the charm reads it when configuring the workload. Unlike
options set with juju config, these settings are part of the packaged charm;
changing them requires repacking and refreshing it.
Create paas-config.yaml beside charmcraft.yaml with the following content
to set the app’s runtime port:
port: 8000
The port key replaces the Juju app-port option.
Check out the contents of charmcraft.yaml:
cat charmcraft.yaml
The top of the file should look similar to the following snippet:
# This file configures Charmcraft.
# See https://documentation.ubuntu.com/charmcraft/stable/reference/files/charmcraft-yaml-file/ for guidance.
# For questions or help, visit https://matrix.to/#/#12-factor-charms:ubuntu.com
name: fastapi-hello-world
type: charm
base: ubuntu@26.04
charm-user: non-root
# the platforms this charm should be built on and run on.
# you can check your architecture with `dpkg --print-architecture`
platforms:
amd64:
# arm64:
# ppc64el:
# s390x:
# (Required)
summary: A very short one-line summary of the FastAPI application.
# (Required)
description: |
A comprehensive overview of your FastAPI application.
...
Verify that the name is fastapi-hello-world. Ensure that platforms
includes the architecture of your host. Edit the platforms key in the
project file if required.
Tip
Want to learn more about all the configurations in the
fastapi-framework profile? Run charmcraft expand-extensions
from the ~/fastapi-hello-world/charm/ directory.
Let’s pack the charm:
charmcraft pack
Depending on your system and network, this step may take several minutes to finish.
Once Charmcraft has finished packing the charm, the terminal will
respond with something similar to
Packed fastapi-hello-world_<architecture>.charm. The file name
reflects your system’s architecture. After the initial
pack, subsequent charm packings are faster.
Deploy the FastAPI app¶
So far, we’ve packed our FastAPI app into a rock and used that rock to create our corresponding charm. Now we have all the materials necessary to deploy the FastAPI app with Juju.
A Juju model is needed to handle Kubernetes resources while deploying the FastAPI app. The Juju model holds the app along with any supporting components. In this tutorial, our model will hold the FastAPI app, ingress, and a PostgreSQL database.
Let’s create a new model:
juju add-model fastapi-hello-world
Constrain the Juju model to your architecture:
juju set-model-constraints \
-m fastapi-hello-world arch=$(dpkg --print-architecture)
Now let’s use the OCI image we previously uploaded to deploy the FastAPI
app. Deploy using Juju by specifying the OCI image name with the
--resource option:
juju deploy \
./fastapi-hello-world_$(dpkg --print-architecture).charm \
fastapi-hello-world --resource \
app-image=localhost:32000/fastapi-hello-world:0.1
It will take a few minutes to deploy the FastAPI app. You can run juju status to monitor its progress:
juju status --watch 2s
It can take a couple of minutes for the app to finish the deployment.
Once the status of the App has gone to active, you can stop watching
using Ctrl + C. To monitor your deployment, keep a
juju status session active in a second terminal.
The FastAPI app should now be running. We can monitor the status of
the deployment using juju status, which should be similar to the following
output:
ubuntu@charm-dev:~/fastapi-hello-world/charm$ juju statusModel Controller Cloud/Region Version SLA Timestamp
fastapi-hello-world dev-controller k8s 3.6.2 unsupported 13:45:18+10:00
App Version Status Scale Charm Channel Rev Address Exposed Message
fastapi-hello-world active 1 fastapi-hello-world 0 10.152.183.53 no
Unit Workload Agent Address Ports Message
fastapi-hello-world/0* active idle 10.1.157.75
Let’s expose the app using ingress so that we can access it. Deploy the
gateway-api-integrator charm and integrate it with the FastAPI app:
juju deploy gateway-api-integrator --channel=1/edge --trust
juju integrate gateway-api-integrator fastapi-hello-world
Configure the Gateway API integrator to use Canonical Kubernetes’ ck-gateway
class and serve HTTP on its load-balancer IP address:
juju config gateway-api-integrator \
gateway-class=ck-gateway enforce-https=false
We’ll leave external-hostname
unset, and we won’t add a certificates relation for this isolated development VM.
Use a domain and TLS in production.
Monitor juju status until everything has a status of active.
In the VM terminal, ask the gateway for the published endpoints:
juju run gateway-api-integrator/leader get-proxied-endpoints
The proxied-endpoints result contains a JSON object, for example:
proxied-endpoints: '{"gateway-api-integrator": {"url": "http://10.115.29.100"}, "fastapi-hello-world": {"url": "http://10.115.29.100/fastapi-hello-world-fastapi-hello-world"}}'
Copy the complete url for your application, not the
gateway-api-integrator entry. The example address will differ on your VM.
The app URL already includes its routing prefix; the gateway strips this prefix
before forwarding requests to the app.
In the VM terminal, save that URL for the following commands, replacing
<app-url> with the value returned by the action:
export APP_URL='<app-url>'
Use the same complete URL directly in a browser on your host machine. No DNS
entry or custom Host header is needed. APP_URL exists only in the VM
terminal where you exported it; repeat the export with the same returned URL
if you open another VM terminal. If the gateway address changes, run the action
again and update APP_URL.
Test the deployment by opening the returned app URL in your host’s browser or sending a request in the VM terminal:
curl "$APP_URL"
It should return Hello world!.
The development cycle¶
So far, we have worked through the entire cycle, from creating an app to deploying it. But now – as in every real-world case – we will go through the experience of iterating to develop the app, and deploy each iteration.
Provide a configuration¶
To demonstrate how to provide a configuration to the FastAPI app,
we will make the greeting configurable. The app will read this configuration
from the GREETING_VAR environment variable. Return to the
~/fastapi-hello-world directory and replace the contents of app.py with:
import os
from fastapi import FastAPI
from fastapi.responses import PlainTextResponse
app = FastAPI()
@app.get("/", response_class=PlainTextResponse)
async def root():
return os.getenv("GREETING_VAR", "Hello, world!")
Update the rock¶
Increment the version in rockcraft.yaml to 0.2 such that the
top of the rockcraft.yaml file looks similar to the following:
# See https://documentation.ubuntu.com/rockcraft/1/reference/extensions/fastapi-framework
# For questions or help, visit https://matrix.to/#/#12-factor-charms:ubuntu.com
name: fastapi-hello-world
# see https://documentation.ubuntu.com/rockcraft/1/explanation/bases/
# for more information about bases and using 'bare' bases for chiselled rocks
base: bare # as an alternative, an ubuntu base can be used
build-base: ubuntu@26.04 # build-base is required when the base is bare
version: '0.2' # just for humans. Semantic versioning is recommended
summary: A summary of your FastAPI application # 79 char long summary
description: |
This is fastapi project's description. You have a paragraph or two to tell the
most important story about it. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the
container registries out there.
# the platforms this rock should be built on and run on.
# you can check your architecture with `dpkg --print-architecture`
platforms:
amd64:
# arm64:
# ppc64el:
# s390x:
Let’s pack and upload the new version of the rock:
rockcraft pack
rockcraft.skopeo --insecure-policy copy --dest-tls-verify=false \
oci-archive:fastapi-hello-world_0.2_$(dpkg --print-architecture).rock \
docker://localhost:32000/fastapi-hello-world:0.2
Update the charm¶
Return to the charm directory.
The fastapi-framework Charmcraft extension supports adding
configurations to charmcraft.yaml which will be passed as
environment variables to the FastAPI app. Add the
following to the end of the charmcraft.yaml file:
# configuration snippet for FastAPI application
config:
options:
greeting:
description: |
The greeting to be returned by the FastAPI application.
default: "Hello, world!"
type: string
Replace paas-config.yaml with the following content to map the new
greeting option to GREETING_VAR, matching the app code:
port: 8000
config:
options:
greeting:
env-var: GREETING_VAR
The option is declared in charmcraft.yaml. By default, greeting
would be exposed as APP_GREETING. Setting env-var overrides
that name with GREETING_VAR, without adding a framework prefix or
changing the option’s value.
Changing the packaged mapping requires repacking the charm; changing
the greeting value through Juju does not require rebuilding the rock.
The paas-config.yaml reference describes
the other packaged settings.
We can now pack and deploy the new version of the FastAPI app:
charmcraft pack
juju refresh fastapi-hello-world \
--path=./fastapi-hello-world_$(dpkg --print-architecture).charm \
--resource app-image=localhost:32000/fastapi-hello-world:0.2
Monitor juju status until the app goes
back to active again. Verify that the
new configuration has been added:
juju config fastapi-hello-world | grep -A 6 greeting:
Check that the response is now Hello, world! using:
curl "$APP_URL"
Now let’s change the greeting:
juju config fastapi-hello-world greeting='Hi!'
Wait for the app to restart, then check the response:
curl "$APP_URL"
The response should now return the updated Hi! greeting.
Integrate with a database¶
Now let’s keep track of how many visitors your app has received. This will require integration with a database to keep the visitor count. This will require a few changes:
We will need to create a database migration that creates the
visitorstable.We will need to keep track of how many times the root endpoint has been called in the database.
We will need to add a new endpoint to retrieve the number of visitors from the database.
Let’s start with the database migration to create the required tables.
The charm created by the fastapi-framework extension will execute the
migrate.py script if it exists. This script should ensure that the
database is initialized and ready to be used by the app. We will
create a migrate.py file containing this logic.
Return to the ~/fastapi-hello-world directory,
create the migrate.py file, open the file using a text editor
and paste the following code into it:
# Adds database to FastAPI application
import os
import psycopg2
DATABASE_URI = os.environ["POSTGRESQL_DB_CONNECT_STRING"]
def migrate():
with psycopg2.connect(DATABASE_URI) as conn, conn.cursor() as cur:
cur.execute("""
CREATE TABLE IF NOT EXISTS visitors (
timestamp TIMESTAMP NOT NULL,
user_agent TEXT NOT NULL
);
""")
conn.commit()
if __name__ == "__main__":
migrate()
Note
The charm will pass the Database connection string in the
POSTGRESQL_DB_CONNECT_STRING environment variable once PostgreSQL has
been integrated with the charm.
Regarding the migrate.sh file describes how to
use the migrate.sh file and run CLI tools for database migration in production. Alternatively,
use a different tooling for migration, for example Alembic.
Update the rock again¶
Increment the version in rockcraft.yaml to 0.3 such that the
top of the rockcraft.yaml file looks similar to the following:
# See https://documentation.ubuntu.com/rockcraft/1/reference/extensions/fastapi-framework
# For questions or help, visit https://matrix.to/#/#12-factor-charms:ubuntu.com
name: fastapi-hello-world
# see https://documentation.ubuntu.com/rockcraft/1/explanation/bases/
# for more information about bases and using 'bare' bases for chiselled rocks
base: bare # as an alternative, an ubuntu base can be used
build-base: ubuntu@26.04 # build-base is required when the base is bare
version: '0.3' # just for humans. Semantic versioning is recommended
summary: A summary of your FastAPI application # 79 char long summary
description: |
This is fastapi project's description. You have a paragraph or two to tell the
most important story about it. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the
container registries out there.
# the platforms this rock should be built on and run on.
# you can check your architecture with `dpkg --print-architecture`
platforms:
amd64:
# arm64:
# ppc64el:
# s390x:
The app code also needs to be updated to keep track of the number of visitors
and to include a new endpoint to retrieve the number of visitors to the
app. Open app.py in a text editor and replace its contents with the
following code:
~/fastapi-hello-world/app.py
# FastAPI application that keeps track of visitors using a database
import datetime
import os
from typing import Annotated
from fastapi import FastAPI, Header
from fastapi.responses import PlainTextResponse
import psycopg2
app = FastAPI()
DATABASE_URI = os.environ["POSTGRESQL_DB_CONNECT_STRING"]
@app.get("/", response_class=PlainTextResponse)
async def root(user_agent: Annotated[str | None, Header()] = None):
with psycopg2.connect(DATABASE_URI) as conn, conn.cursor() as cur:
timestamp = datetime.datetime.now()
cur.execute(
"INSERT INTO visitors (timestamp, user_agent) VALUES (%s, %s)",
(timestamp, user_agent)
)
conn.commit()
return os.getenv("GREETING_VAR", "Hello, world!")
@app.get("/visitors", response_class=PlainTextResponse)
async def visitors():
with psycopg2.connect(DATABASE_URI) as conn, conn.cursor() as cur:
cur.execute("SELECT COUNT(*) FROM visitors")
total_visitors = cur.fetchone()[0]
return f"Number of visitors {total_visitors}"
Let’s pack and upload the new version of the rock:
rockcraft pack
rockcraft.skopeo --insecure-policy copy --dest-tls-verify=false \
oci-archive:fastapi-hello-world_0.3_$(dpkg --print-architecture).rock \
docker://localhost:32000/fastapi-hello-world:0.3
Update the charm again¶
Return to the charm directory.
The FastAPI app now requires a database which needs to be declared in the
charmcraft.yaml file. Open charmcraft.yaml in a text editor and
add the following section to the end:
# requires snippet for FastAPI application with a database
requires:
postgresql:
interface: postgresql_client
optional: false
We can now pack and deploy the new version of the FastAPI app:
charmcraft pack
juju refresh fastapi-hello-world \
--path=./fastapi-hello-world_$(dpkg --print-architecture).charm \
--resource app-image=localhost:32000/fastapi-hello-world:0.3
Now let’s deploy PostgreSQL and integrate it with the FastAPI app:
juju deploy postgresql-k8s --trust --channel 14/stable
juju integrate fastapi-hello-world postgresql-k8s
Wait for juju status to show that the App is active again.
During this time, the FastAPI app may enter a blocked state as it
waits to become integrated with the PostgreSQL database. Due to the
optional: false key in the endpoint definition, the FastAPI app will not
start until the database is ready.
Send a request to the endpoint:
curl "$APP_URL"
It should still return the Hi! greeting.
Check the local visitors:
curl "${APP_URL%/}/visitors"
This request should return
Number of visitors 1 after the previous request to the root endpoint. This should
be incremented each time the root endpoint is requested. If we repeat
this process, the output should be as follows:
ubuntu@charm-dev:~/fastapi-hello-world/charm$ curl "$APP_URL"Hi!
ubuntu@charm-dev:~/fastapi-hello-world/charm$ curl "${APP_URL%/}/visitors"Number of visitors 2
Tear things down¶
If you’d like to quickly tear things down, start by exiting the Multipass VM:
exit
And then you can proceed with its deletion:
multipass delete charm-dev
multipass purge
If you’d like to manually reset your working environment, you can run the
following in the project directory ~/fastapi-hello-world/charm for the tutorial:
charmcraft clean
# Back out to main directory for cleanup
cd ..
rockcraft clean
# exit and delete the virtual environment
deactivate
rm -rf charm .venv __pycache__
# delete all the files created during the tutorial
rm fastapi-hello-world_0.1_$(dpkg --print-architecture).rock \
fastapi-hello-world_0.2_$(dpkg --print-architecture).rock \
fastapi-hello-world_0.3_$(dpkg --print-architecture).rock \
rockcraft.yaml app.py requirements.txt migrate.py
# Remove the juju model
juju destroy-model fastapi-hello-world --destroy-storage --no-prompt --force
You can also clean up your Multipass instance by exiting and deleting it using the same commands as above.
Conclusion and next steps¶
You’ve reached the end of this tutorial. You made it through the entire development process, including:
Creating a FastAPI app
Deploying the app locally
Packaging the app using Rockcraft
Building the app with Ops code using Charmcraft
Deploying the app using Juju
Exposing the app using an ingress
Configuring the app
Integrating the app with a database
Please provide feedback about your experience with this tutorial by completing the following Google form: 26.04 tutorial feedback
By the end of this tutorial, you built a charm and evolved it in a number of typical ways, but there is a lot more to explore:
If you are wondering… |
Visit… |
|---|---|
“How do I…?” |
|
“How do I debug?” |
|
“How do I get in touch?” |
|
“What is…?” |
fastapi-framework extension in Rockcraft |
“Why…?”, “So what?” |
12-Factor app principles and support in Charmcraft and Rockcraft |