Skip to content
Kubernetes Operator SDK written in Elixir. Extend the Kubernetes API and implement CustomResourceDefinitions in Elixir.
Branch: master
Clone or download
Latest commit 58bb83e Jun 3, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github Update main.workflow Dec 28, 2018
config Integrated telemetry library Mar 12, 2019
lib add additional printer columns Jun 2, 2019
logo Generator and CRD/Controller naming refactor Dec 21, 2018
priv/templates/bonny.gen add additional printer columns Jun 2, 2019
test add additional printer columns Jun 2, 2019
.formatter.exs initial commit Dec 11, 2018
.gitignore initial commit Dec 11, 2018
.travis.yml Initial release Dec 20, 2018 add additional printer columns Jun 2, 2019
Dockerfile Adding a dockerfile for gh actions testing Dec 28, 2018 provide a template for github issues (copy from elixir) Jan 4, 2019
LICENSE Initial release Dec 20, 2018
Makefile wip Mar 10, 2019 Added event tag to watcher Apr 17, 2019
banner.png hexdocs fixes Dec 22, 2018
mix.exs Add'l telemetry metrics Apr 15, 2019


Build Status Coverage Status

Bonny: Kubernetes Operator Framework

Extend the Kubernetes API and implement CustomResourceDefinitions lifecycles in Elixir.

If Kubernetes CRDs and controllers are new to you, read up on the terminology.

Tutorials and Examples:


If available in Hex, the package can be installed by adding bonny to your list of dependencies in mix.exs:

def deps do
    {:bonny, "~> 0.3"}


Bonny uses the k8s client under the hood.

The only configuration parameters required are :bonny controllers and a :k8s cluster:

config :k8s,
  clusters: %{
    default: %{ # `default` here must match `cluster_name` below
      conf: "~/.kube/config"

config :bonny,
  # Add each CRD Controller module for this operator to load here
  # Defaults to none. This *must* be set.
  controllers: [

  # K8s.Cluster to use, defaults to :default
  cluster_name: :default,

  # How often to run the reconciler for all controllers in milliseconds.
  # Default: 300000ms (5 minutes)
  reconcile_every: 10 * 60 * 1000,

  # Batch size of HTTP request; maps to the Kubernetes `limit` API parameter.
  # If `continue` is returned additional HTTP requests will be made to fetch all batches of items
  # Default: 50
  reconcile_batch_size: 100,

  # Set the Kubernetes API group for this operator.
  # This can be overwritten using the @group attribute of a controller
  group: "",

  # Name must only consist of only lowercase letters and hyphens.
  # Defaults to hyphenated mix app name
  operator_name: "your-operator",

  # Name must only consist of only lowercase letters and hyphens.
  # Defaults to hyphenated mix app name
  service_account_name: "your-operator",

  # Labels to apply to the operator's resources.
  labels: %{
    "kewl": "true"

  # Operator deployment resources. These are the defaults.
  resources: %{
    limits: %{cpu: "200m", memory: "200Mi"},
    requests: %{cpu: "200m", memory: "200Mi"}

When configuring bonny to run in your cluster the mix bonny.gen.manifest command will generate a service account for you. To use that service account configure the k8s library like the following:

config :k8s,
  clusters: %{
    default: %{}

This will add a cluster named default. When no configuration information is provided, the k8s library will use the service account of the pod.

Example Operators built with Bonny

  • Hello Operator - this was built with bonny v 0.2, there have been significant changes since.

Bonny Generators

There are a number of generators to help create a kubernetes operator.

mix help | grep bonny

Generating an operator controller

An operator can have multiple controllers. Each controller handles the lifecycle of a custom resource.

By default controllers are generated in the V1 version scope.

mix bonny.gen.controller Widget widgets

You can specify the version flag to create a new version of a controller. Bonny will dispatch the controller for the given version. So old versions of resources can live alongside new versions.

mix bonny.gen.controller Widget widgets --version v2alpha1

Note: The one restriction with versions is that they will be camelized into a module name.

Open up your controller and add functionality for your resource's lifecycles:

  • Add
  • Modify
  • Delete
  • Reconcile; periodically called with each every instance of a CRD's resources

Each controller can create multiple resources.

For example, a todo app controller could deploy a Deployment and a Service.

Your operator can also have multiple controllers if you want to support multiple resources in your operator!

Check out the two test controllers:

Generating a dockerfile

The following command will generate a dockerfile for your operator. This will need to be pushed to a docker repository that your kubernetes cluster can access.

Again, this Dockerfile is for your operator, not for the pods your operator may deploy.

You can skip this step when developing by running your operator external to the cluster.

mix bonny.gen.dockerfile

docker build -t ${BONNY_IMAGE} .
docker push ${BONNY_IMAGE}:latest

Generating Kubernetes manifest for operator

This will generate the entire manifest for this operator including:

  • CRD manifests
  • RBAC
  • Service Account
  • Operator Deployment

The operator manifest generator requires the image flag to be passed if you plan to deploy the operator in your cluster. This is the docker image URL of your operators docker image created by mix bonny.gen.docker above.

mix bonny.gen.manifest --image ${BONNY_IMAGE}

You may omit the --image flag if you want to generate a manifest without the deployment so that you can develop locally running the operator outside of the cluster.

Note: YAML output is JSON formatted YAML. Sorry, elixirland isn't fond of YAML :D

By default the manifest will generate the service account and deployment in the "default" namespace.

To set the namespace explicitly:

mix bonny.gen.manifest --out - -n test

Alternatively you can apply it directly to kubectl:

mix bonny.gen.manifest --out - -n test | kubectl apply -f - -n test

Generating a resource

TODO: Need to support validation / OpenAPI.


Bonny uses the telemetry library to emit event metrics.

Emmited events:

  [:bonny, :reconciler, :genserver_initialized],
  [:bonny, :reconciler, :started],
  [:bonny, :reconciler, :scheduled],
  [:bonny, :reconciler, :get_items_succeeded],
  [:bonny, :reconciler, :get_items_failed],
  [:bonny, :reconciler, :item_succeeded],
  [:bonny, :reconciler, :item_failed],
  [:bonny, :watcher, :genserver_initialized],
  [:bonny, :watcher, :genserver_down],
  [:bonny, :watcher, :started],
  [:bonny, :watcher, :chunk_received],
  [:bonny, :watcher, :expired],
  [:bonny, :watcher, :finished],
  [:bonny, :watcher, :http_request_failed],
  [:bonny, :watcher, :http_request_succeeded],
  [:bonny, :watcher, :dispatch_succeeded],
  [:bonny, :watcher, :dispatch_failed]


Custom Resource:

A custom resource is an extension of the Kubernetes API that is not necessarily available on every Kubernetes cluster. In other words, it represents a customization of a particular Kubernetes installation.

CRD Custom Resource Definition:

The CustomResourceDefinition API resource allows you to define custom resources. Defining a CRD object creates a new custom resource with a name and schema that you specify. The Kubernetes API serves and handles the storage of your custom resource.


A custom controller is a controller that users can deploy and update on a running cluster, independently of the cluster’s own lifecycle. Custom controllers can work with any kind of resource, but they are especially effective when combined with custom resources. The Operator pattern is one example of such a combination. It allows developers to encode domain knowledge for specific applications into an extension of the Kubernetes API.


A set of application specific controllers deployed on Kubernetes and managed via kubectl and the Kubernetes API.


Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at


mix test

Operator Blog Posts

You can’t perform that action at this time.