This documents explains the processes and practices recommended for contributing enhancements to this operator.
- Generally, before developing enhancements to this charm, you should consider opening an issue explaining your use case.
- If you would like to chat with us about your use-cases or proposed implementation, you can reach us at Canonical Mattermost public channel or Discourse.
- Familiarising yourself with the Charmed Operator Framework library will help you a lot when working on new features or bug fixes.
- All enhancements require review before being merged. Code review typically examines:
- code quality
- test coverage
- user experience for Juju administrators this charm
- When evaluating design decisions, we optimize for the following personas, in descending order of priority:
- the Juju administrator
- charm authors that need to integrate with this charm through relations
- the contributors to this charm's codebase
- Please help us out in ensuring easy to review branches by rebasing your pull request branch onto the
main
branch. This also avoids merge commits and creates a linear Git commit history.
Traefik is a cluster-less proxy: each unit is performing its own routing decisions and keeping track of the health of upstreams (i.e., the addresses it routes requests for).
Each Traefik operator listens to changes in the ingress-per-unit
relations and generates their own configurations.
Only the leader unit of the Traefik operator, however, communicates "back" with the application on the other side of the relation by providing the URL at which the units are reachable.
Limitation: Since follower (i.e., "non-leader") units of a Juju application cannot access their application databag in the relation (see this Juju bug report), it can be the case that follower units starts routing to units that have not yet been notified by the leader unit of the Traefik operator, what their externally-reachable URL is.
In order to configure Traefik, we use its File provider, which uses inotify
mechanisms to know when new files are created or modified in the filesystem.
Unfortunately, inotify
does not work in the upstream Traefik image, which is why we resorted to:
- storing the unit configuration in a mounted volume
- run the Traefik process on a custom container image built on the
ubuntu
base image, see the Container image section.
You can use the environments created by tox
for development:
tox --notest -e unit
source .tox/unit/bin/activate
tox -e fmt # update your code according to linting rules
tox -e lint # code style
tox -e unit # unit tests
tox -e integration # integration tests
tox # runs 'lint' and 'unit' environments
These instructions assume you will run the charm on microk8s
, and relies on the dns
, storage
, registry
and metallb
plugins:
sudo snap install microk8s --classic
microk8s enable storage dns
microk8s enable metallb 192.168.0.10-192.168.0.100 # You will likely want to change these IP ranges
The storage
and dns
plugins are required machinery for most Juju charms running on K8s.
This charm is no different.
The metallb
plugin is needed so that the Traefik ingress will receive on its service, which is of type LoadBalancer
, an external IP it can propagate to the proxied applications.
The setup for Juju consists as follows:
sudo snap install juju --classic
juju bootstrap microk8s development
Build the charm in this git repository using:
charmcraft pack
We are using an Ubuntu-based image built from this repository.
The reason not to use the upstream Traefik image, is that the File provider the charm uses (see [Notable design decisions](#notable design-decisions) section) does not seem to work in the upstream, busybox-based Traefik image.
# Create a model
juju add-model dev
# Enable DEBUG logging
juju model-config logging-config="<root>=INFO;unit=DEBUG"
juju deploy ./traefik-k8s_ubuntu-20.04-amd64.charm traefik-ingress --trust --resource traefik-image=docker.io/jnsgruk/traefik:2.6.1