Since the last post we have added support for Juju secrets and background tasks. Configurations can now be juju secrets and will be made available as flattened environment variables to the app. You can find an example below. Background tasks are supported by providing all the environment variables that are available to the web application (such as the database) to any pebble services in the rock that end with the -worker
or -scheduler
postfix. These are available on all the supported frameworks: Flask (stable), Django (soon to be stable) and Go and FastAPI (experimental).
We have also been busy with community work. In the last few months we had talks at PyCon Ohio and at Ubucon Latin America. We will also have 3 talks on the weekend of the 14th of November at PyCon Hong Kong (by @charlie4284), PyCon Ireland (by @jdkandersson) and PyCon Sweden (by @javierdelapuente).
We have published Django documentation now and the stable release will be soon:
- Build a Rock for a Django application
- Django-framework extension Rockcraft Reference Docs
- Write your first Kubernetes charm for a Django app
- Charm How-to Guides covering Flask and Django
- Django-framework extension Charmcraft Reference Docs
We are also working hard on the FastAPI and Go documentation, see our matrix channel for links to PRs and documents where we are working on new features or documentation! You can also ask any questions or get help from us there. Now onto a quick demonstration of how Juju secrets work with 12-factor web apps.
Juju Secrets
Juju secrets are a way of securely passing sensitive data to a charm. You can read more about them in how to manage secrets. In the context of a web application, these might be tokens for accessing a service, such as stripe to accept payments from users. These sensitive data can now be passed to your application as a Juju secret. To illustrate how this works, let’s create a simple Flask application to demonstrate how the secret will be passed. This feature is also available in Django, Go and FastAPI. If you would like to follow along, complete the setup instructions in the Hands-on approach portion of the Flask tutorial and create and change into a directory called juju-secret-app
. We will use the following Flask app for demonstration purposes:
import os
import flask
app = flask.Flask(__name__)
@app.route("/")
def index():
print(os.environ)
return "Hello, world!\n"
if __name__ == "__main__":
app.run()
The print(os.environ)
will show all the environment variables that are passed to the application, including the credentials we will pass as a secret. Don’t forget the requirements.txt
file with Flask
and then we can pack the rock and load it into MicroK8s:
rockcraft init --profile flask-framework
rockcraft pack
rockcraft.skopeo --insecure-policy copy \
--dest-tls-verify=false \
oci-archive:juju-secret-app_0.1_amd64.rock \
docker://localhost:32000/juju-secret-app:0.1
Next, we need to create the charm:
mkdir charm
cd charm
charmcraft init --profile flask-framework --name juju-secret-app
Open charmcraft.yaml and add the following secret as a configuration at the end:
config:
options:
credentials:
description: |
Sensitive credentials to a service.
type: secret
Pack the charm and deploy it:
charmcraft pack
juju add-model juju-secret-app
juju deploy ./juju-secret-app_ubuntu-22.04-amd64.charm \
juju-secret-app \
--resource flask-app-image=localhost:32000/juju-secret-app:0.1
We can keep an eye on the deployment progress using juju status --watch 5s
and wait for the application to become active. We can then create the credentials as a juju secret, which will have a username and password:
$ juju add-secret credentials username=api password=86298f988fe8d1e2794bf5fa6943fe58
secret:cs310dnmp25c7b1k73a0
$ juju grant-secret credentials juju-secret-app
$ juju config juju-secret-app credentials=secret:cs310dnmp25c7b1k73a0
Check the application has finished restarting using juju status
which should report it to be active again:
Model Controller Cloud/Region Version SLA Timestamp
juju-secret-app dev-controller microk8s/localhost 3.5.4 unsupported 16:11:57+11:00
App Version Status Scale Charm Channel Rev Address Exposed Message
juju-secret-app active 1 juju-secret-app 0 10.152.183.243 no
Unit Workload Agent Address Ports Message
juju-secret-app/0* active idle 10.1.157.75
Then we can send a request to the root endpoint using the IP address shown in the Unit section of juju status
for the juju-secret-app
(curl 10.1.157.75:8000
for the case above) which should respond with Hello, world!
. To see the environment variables that are set use microk8s.kubectl exec pod/juju-secret-app-0 -n juju-secret-app -c flask-app -- pebble logs
. You should see the output of the print(os.environ)
in the logs which should include the FLASK_CREDENTIALS_USERNAME
and FLASK_CREDENTIALS_PASSWORD
environment variables with the values from the juju secret.
The environment variable name is derived by combining the name of the configuration in charmcraft.yaml for the secret with the keys in the secret separated using _
, capitalising all characters and adding the usual FLASK_
prefix.
In this demo, we created a simple Flask application that logs the environment variables when the root endpoint is called. We deployed this application using a charm with the credentials configuration as a secret. Then we created a Juju secret, passed it to the app charm and saw that the secret was inserted into the environment variables when we called the root endpoint. Thank you for reading and stay in touch on the matrix channel!