Operators and charmed operators
by Sohini Bianka Roy on 29 March 2021
If you’ve been working with Kubernetes, you will have run into operators. Operators are designed to automate typical maintenance tasks, from installation to back-ups and scaling. What might surprise you is that operators are capable of doing so much more… Enter the charmed operator.
Why you need operators
First, let’s take a step back and look at why operators exist and why they can be really helpful. Operators were designed to help manage application lifecycle complexity. Typically, organizations have engineers who are responsible for the lifecycle management of specific applications and services. Over time these trusted engineers become experts in these applications, what it takes to operate them, how they should be deployed within a system, and how they should react to different events.
The goal to capture the deep knowledge of human application managers is fundamentally important to building a future where clusters are both automated and reliable. Note that many of these tasks are more complex than they appear at first glance. The seminal CoreOS blog announcing Kubernetes Operators describes the following steps for adding a member to an etcd cluster:
“When scaling an etcd cluster manually, a user has to perform a number of steps: create a DNS name for the new etcd member, launch the new etcd instance, and then use the etcd administrative tools (etcdctl member add) to tell the existing cluster about this new member.”
Operations can be much more complex than this, especially when they are organisation specific; it’s easy to imagine in-depth flows for off-site back-ups or disaster recovery.
This sense of an operator embodying operational knowledge is exactly the same philosophy that underpins charmed operators. Charmed operators, or charms, take all the domain knowledge required to effectively operate software. They are open-source packaged ops code with developer tooling to aid sharing code across charms, and that empower a charm ecosystem.
How are operators and charmed operators different?
So where do operators and charmed operators diverge? Operators are considered to be an extension of Kubernetes that leverages custom resources to manage applications and their components. Operators follow Kubernetes principles, notably the control loop.
Some Kubernetes operators are built on top of custom resources (often called CRDs) which are Kubernetes primitives. These are “controlled” via a controller which typically runs as a pod in the cluster. The controller runs a “control loop”, which effectively means it is constantly looking at the current state of the system (and in particular its custom resources) and comparing it to the “wanted” state and making changes as appropriate. Each Operator will have its own controller.
By contrast, charmed operators do not rely on Kubernetes primitives. In fact, charmed operators support multiple platforms, such as OpenStack, AWS and GCP all in addition to Kubernetes. Rather than keeping state in CRDs, the Charmed Operator Lifecycle Manager (COLM) keeps track of the state of all charms within an environment, such as a Kubernetes cluster.
Additionally, though some operators are required to be written in Go, in contrast, the Charmed Operator SDK leverages standard Python structures to allow for clean, maintainable, and reusable code.
A Charming View
So what is it like to write charmed operators? If you’d like to see some example code, take a look at the documentation and guides. You can also head over to the Charmhub to see what other people have already created.
Once you have a working charm, you start to see some advantages over other operators. One of these is the ability to relate multiple charms together. In Kubernetes it would be common to find Helm charts and operators that bundle their own databases. Using charmed operators, this would instead be done by declaring a relation from an application charm to a database charm. This allows the exact implementation of the database charm to be changed without requiring changes to the operator code itself. A typical example of this would be replacing a MySQL charm with a MariaDB one, or even a charm that proxies to Amazon RDS. Beyond this, relations will also notify dependent charms of changes, allowing automatic reconfiguration and restarting of services as required.
Another advantage comes from COLM’s previously-mentioned support for multiple environments. This makes it easier to integrate multiple environments together — imagine a single COLM install managing charms running and interoperating on local VMs, a Kubernetes cluster and GCP or similar. This also provides a level of future-proofing; when future platforms are added to the COLM it should be straightforward to migrate to them.
One of the fundamental principles for charmed operators is to “do one thing and do it well.” As a result, charmed operators are designed to be composable and easily integrated with other charmed operators. You’ll find that as the applications and the ecosystem become more complex, the other operators get more complex. Instead, charmed operators are focused and easily integrate with one another to create a model that can be readily adapted to accommodate more complex environments and requirements. Through the definition of relations, applications can be seamlessly integrated by their operators. This is because charm developers do the heavy lifting to understand how to best integrate applications, how the charm they are writing needs to receive information, and how it typically needs to share information.
Additionally, charmed operators have standardised the UX and command line interfaces (CLI) regardless of the application. All of the configuration, integration, and complex Day-2 operation tasks are handled through the COLM, simplifying the user experience and making it easy to adopt many operators and models.
And finally, one of the latest investments in charmed operators was in optimizing the experience with Kubernetes through a sidecar pattern approach. Through this new approach, both the workload container and the charm run in the same pod. This augments workloads with additional capabilities and features, especially to manage and operate complex workloads. As a result, the charmed operator and the workload are co-located in the same network space, can communicate through SHM or sockets, readily share files, and can scale with the workload. Enhancing this approach is a new feature called Pebble. Pebble enables you to declaratively configure processes to run in a container, and control those processes throughout the workload lifecycle. As a result, users have fine-grained control of the application behaviour which is ideal for complex applications in Kubernetes.