Discourse docs: Charm Architecture

Charm Architecture

At its core, Discourse is a Ruby on Rails application that integrates with PostgreSQL and Redis.

The charm design leverages the sidecar pattern to allow multiple containers in each pod with Pebble running as the workload container’s entrypoint.

Pebble is a lightweight, API-driven process supervisor that is responsible for configuring processes to run in a container and controlling those processes throughout the workload lifecycle.

Pebble services are configured through layers, and the following containers represent each one a layer forming the effective Pebble configuration, or plan:

  1. A Discourse container, consisting of a Unicorn server running the Discourse application along with the installed plugins.

As a result, if you run a kubectl get pods on a namespace named for the Juju model you’ve deployed the Discourse charm into, you’ll see something like the following:

NAME                            READY   STATUS    RESTARTS   AGE
discourse-k8s-0                 2/2     Running   0          65m

This shows there are 2 containers - the one named above, as well as a container for the charm code itself.

And if you run kubectl describe pod discourse-k8s-0, all the containers will have as Command /charm/bin/pebble. That’s because Pebble is responsible for the processes startup as explained above.

Containers

Configuration files for the containers can be found in the image directory of the charm repository.

Discourse

Discourse is a Ruby on Rails application deployed on top of the Unicorn server.

The server is started in HTTP mode (port 3000) serving all the content. Alongside it there’s a standalone process running the Prometheus Exporter Plugin for Discourse (port 9394).

The workload that this container is running is defined in the Discourse dockerfile in the charm repository.

Docker Images

The image defined in the Discourse dockerfile in the charm repository is published to Charmhub, the official repository of charms.

This is done by publishing a resource to Charmhub as described in the Juju SDK How-to guides.

Integrations

Ingress

The Discourse charm also supports being integrated with Ingress by using NGINX Ingress Integrator.

In this case, an existing Ingress controller is required. For more information, see Adding the Ingress Relation to a Charm.

PostgreSQL

PostgreSQL is an open-source object-relational database used by Discourse to store all the data needed.

Redis

Redis is an open-source in-memory data structure store used as a cache backend. Copies of frequently accessed data are stored and used if satisfy the request. Otherwise, the application will handle it. This configuration helps to reduce the number of queries and improve response latency.

Grafana

Grafana is an open-source visualization tools that allows to query, visualize, alert on, and visualize metrics from mixed datasources in configurable dashboards for observability. This charms is shipped with its own Grafana dashboard and supports integration with the Grafana Operator to simplify observability.

Loki

Loki is an open-source fully-featured logging system. This charms is shipped with support for the Loki Operator to collect the generated logs.

Prometheus

Prometheus is an open-source systems monitoring and alerting toolkit with a dimensional data model, flexible query language, efficient time series database and modern alerting approach. This charm is shipped with a Prometheus exporter, alerts and support for integrating with the Prometheus Operator to automatically scrape the targets.

Juju Events

Accordingly to the Juju SDK: “an event is a data structure that encapsulates part of the execution context of a charm”.

For this charm, the following events are observed:

  1. _pebble_ready: fired on Kubernetes charms when the requested container is ready. Action: wait for the integrations, and configure the containers.
  2. config_changed: usually fired in response to a configuration change using the GUI or CLI. Action: wait for the integrations, validate the configuration, update Ingress, and restart the containers.
  3. add_admin_user_action: fired when add-admin-user action is executed. Action: add an admin user with the provided email and password.
  4. database_relation_joined: PostgreSQLClient custom event for when the connection details to the master database on this relation joins. Action: initialize the database and enable the appropriate extensions.
  5. master_changed: PostgreSQLClient custom event for when the connection details to the master database on this relation change. Action: update the database connection string configuration and emit config_changed event.
  6. redis_relation_updated: Redis Operator custom event for when the relation details have been updated. Action: wait for the integrations and restart the containers.

Charm Code Overview

The src/charm.py is the default entry point for a charm and has the DiscourseCharm Python class which inherits from CharmBase.

CharmBase is the base class from which all Charms are formed, defined by Ops (Python framework for developing charms).

See more information in Charm.

The __init__ method guarantees that the charm observes all events relevant to its operation and handles them.