Charm

In Juju, a charm is an operator – software that wraps an application and that contains all of the instructions necessary for deploying, configuring, scaling, integrating, etc., the applicationon any Juju-supported cloud <list-of-supported-clouds.

Charms are often published on Charmhub.

Charm taxonomy

By substrate

Kubernetes

A Kubernetes charm is a charm designed to run on a resource from a Kubernetes cloud – i.e., in a container in a pod.

Example Kubernetes charms:

Machine

A machine charm is a charm designed to run on a resource from a machine-cloud – i.e., a bare metal machine, a virtual machine, or a system container.

Example machine charms:

Infrastructure-agnostic

While charms are still very much either for Kubernetes or machines, some workloadless charms are in fact infrastructure-agnostic and can be deployed on both.

Note

That is because most of the difference between a machine charm and a Kubernetes charm comes from how the charm handles the workload. So, if a charm does not have a workload, and its metadata does not stipulate Kubernetes, and the charm does not do anything that would only make sense on machines / Kubernetes, it can run perfectly fine on both machines and Kubernetes – the details of the deployment will differ (the charm will be deployed on a machine vs. a container in a pod), but the deployment will be successful. Example workloadless charms that are cloud-agnostic: Azure Storage Integrator.

By function

While charms are fundamentally about codifying operations for a given workload, some have a slightly different function.

Workloadless

A workloadless charm is a charm that does not run any workload locally.

Because of their nature, workloadless charms are often infrastructure-agnostic.

Examples:

Configurator

A configurator charm is a workloadless charm that configures another charm, once they’re integrated.

Examples:

Proxy

A proxy charm is a configurator charm where the configuration is about how to interact with a non-charmed workload.

Examples:

Integrator

An integrator charm is a proxy charm where the non-charmed workload is some cloud-related functionality.

Examples:

By role

Principal

In machine charms, a principal charm is any charm that has a subordinate.

Subordinate

In machine charms, a subordinate charm is a charm designed to be deployed adjacent to another charm and to augment the functionality of that charm, known as its principal.

When a subordinate charm is deployed, no units are created; this happens only once a relation has been established between the principal and the subordinate.

Examples:

By architecture

Sidecar

This is the state-of-the-art way to develop Kubernetes charms. Both Charmcraft and Ops are designed to produce sidecar Kubernetes charms, where the way these charms manage the workload across their respective container boundaries is through Pebble.

In Kubernetes charms, a sidecar charm is a Kubernetes charm designed to be placed in a container that is in the same pod as container where the workload is, following the sidecar pattern. As in Juju a Kubernetes pod corresponds to a unit, that means that there is an operator inside each unit of the workload.

Examples:

(podspec-charm)

Podspec

Superseded by sidecar charms. Also deprecated in Juju 3+.

In Kubernetes charms, a podspec charm is a Kubernetes charm designed to create and manage Kubernetes resources that are used by other charms or applications running on the cloud. As this pattern was difficult to implement correctly and also sidestepped Juju’s model (the resources created by a podspec charm were not under Juju’s control), this pattern has been deprecated in favor of sidecar charms.

By generation

Charm development has been going on for years, so naturally many attempts have been made at making the development easier. The ‘raw’ API Juju exposes can be interacted with directly, but most people will want to use (at least) the Bash scripts that come by default with every charm deployment, called ‘hook commands’ (or ‘hook tools’). If your charm only uses those, then you’re writing a ‘bare’ charm. If you fancy using a higher-level, object-oriented Python library to interact with the juju model, then you should be using Ops. There exists another python framework that also wraps the hook tools but offers a different (less OOP, less idiomatic) interface, called reactive. This framework is deprecated and no longer maintained, mentioned here only for historical reasons.

Ops

This is the state-of-the-art way to develop a charm.

An Ops charm is a charm developed using the Ops (operator) framework.

Examples:

12-Factor app charm

A 12-Factor app charm is a charm that has been created using certain coordinated pairs of Rockcraft and Charmcraft profiles designed to give you most of the content you will need to generate a rock^ for a charm, and then the charm itself, for a particular type of workload (e.g., an application developed with Flask).

When you initialise a rock with a 12-Factor-app-charm-geared profile, the initialisation will generate all the basic structure and content you’ll need for the rock, including a rockcraft.yaml^ prepopulated with an extension matching the profile. Similarly, when you initialise a charm with a 12-Factor-app-charm-geared profile, that will generate all the basic structure content you’ll need for the charm, including a charmcraft.yaml pre-populated with an extension matching the profile as well as a src/charm.py pre-loaded with a library (paas_charm) with constructs matching the profile and the extension.

See more:

Reactive

Superseded by Ops.

A Reactive charm is a charm developed using the Reactive framework.

Examples:

Bare

Superseded by Ops.

A bare charm is a charm developed without the help of a framework, with all the hook invocations being coded manually (which is why such charms are sometimes also called ‘hooks-based’ or ‘hooks-only’).

Examples:

Charm anatomy

Charm revision

A charm revision is a number that uniquely identifies the version of the charm that a charm author has uploaded to Charmhub.

Caution

The revision increases with every new version of the charm being uploaded to Charmhub. This can lead to situations of mismatch between the semantic version of a charm and its revision number. That is, whether the changes are for a semantically newer or older version, the revision number always goes up.

A revision only becomes available for consumption once it’s been released into a channel. At that point, charm users will be able to see the revision at charmhub.io/<charm/channel> or access it via juju info <charm> or juju deploy <charm> --channel.

Charm channel

A charm channel is a charm release identifier built on the pattern <track>/<risk>/<branch> (e.g., juju deploy kafka --channel 3/stable).

Track

A <track> is a way to collect multiple supported releases of your charm under the same name. When deploying a charm, specifying a track is optional; if none is specified, the default option is the latest. To ensure consistency between tracks of the same charm, tracks must comply with a guardrail.

Track guardrail

A track guardrail is a regex generated by a Charmhub admin at the request of a charm author whose purpose is to ensure that any new track of the charm complies with the specific pattern selected by the charm author for the charm, usually in conformity with the pattern established by the upstream workload (e.g., no numbers, cf, e.g., OpenStack; numbers in the major.minor format; just integers; etc.)

Risk

The <risk> refers to one of the following risk levels:

  • stable: (default) This is the latest, tested, working stable version of the charm.- candidate: A release candidate. There is high confidence this will work fine, but there may be minor bugs.- beta: A beta testing milestone release.- edge: The very latest version - expect bugs!

Branch

Finally, the <branch> is an optional finer subdivision of a channel for a published charm that allows for the creation of short-lived sequences of charms (guaranteed for only 30 days without modification) that can be pushed on demand by charm authors to help with fixes or temporary experimentation. Note that, if you use --channel to specify a branch (e.g., during juju deploy or juju refresh), you must specify a track and a risk level as well.