Responsive

GitHub Issues Reporter for failing K8s Apps

Feb 1, 2023
11 min
read
Mateusz Szostok
Software Engineer
Botkube

Botkube 0.17 introduces plugin support. In this guide you will learn how to create your own Botkube executor plugin to build a GitHub issues reporter for Kubernetes apps that are failing.

Share on Twitter
Share on LinkedIn
Share on Reddit
Share on HackerNews
Copy URL

Table of Contents

Botkube gives you fast and simple access to your clusters right from your communication platform. It does that by sending [actionable notifications](https://docs.botkube.io/configuration/action) (via [sources](https://docs.botkube.io/architecture/#source)) and allowing you to run kubectl and helm commands (via [executors](https://docs.botkube.io/architecture/#executor)) straight from the platform (Slack, Discord, Microsoft Teams and Mattermost).

In the recent Botkube 0.17 release, we took it to the next level by giving you an easy way to bring your own tools to a chat window!

In this blog post, you will learn how to develop your own executor plugin to fill the gap in your daily workflow.

## Goal

To make it simple but functional, I will show you how to develop an executor that creates an issue for failing Kubernetes resources such as Job, Deployment, StatefulSet, and Pod.

Github reporter bot for updating Slack
GitHub executor demo

### Why it's worth it

With just a few lines of code, we will automate the process of creating a GitHub issue that out-of-the box contains Kubernetes-specific information useful for further debugging. All of that, directly from Slack, Discord, Mattermost, or MS Teams! No need for connecting to your cluster in your terminal, installing and running kubectl commands and copy-pasting fetched details into your browser.

Instead, you will be able to type **@Botkube gh create issue pod/foo** from any device that has access to your chat, including mobile apps.

## Prerequisites

- Access to a Kubernetes cluster

INFO

To create a local cluster for testing purposes using k3d, run:

k3d cluster create

- [Botkube installed and configured](https://docs.botkube.io)

- Basic understanding of the Go language

- [Go](https://go.dev/doc/install) at least 1.18

## What's under the hood

To understand better what we will develop, I want to give you a bigger picture of the Botkube plugin system. The animation below focuses only on the executor part, but it's almost the same for sources.

Custom built plugin system for Kubernetes tools
Botkube Plugin System

The new part is a plugin repository that we introduced in 0.17. Plugin repository is a place where you store your plugin binaries and index files. Any static file server can be used, and in this blog post we will use a GitHub release. It’s similar to what you know from the Helm ecosystem.

The plugin manager consumes user's configuration, and downloads and starts only enabled plugins from a given repository. Plugins are running directly on the Kubernetes cluster where the Botkube core was installed.

Such approach allows us to decouple the Botkube core and its extensions. Thanks to that, we can:

- Avoid having the Botkube core crash if a given plugin malfunctions

- Write extensions in any language as gRPC is used

From the end-user's perspective, you can:

- Specify and use multiple plugin repositories at the same time

- Enable different plugin versions within the same Botkube version

To learn more, see [Botkube architecture](https://docs.botkube.io/architecture/).

## Step-By-Step Instructions

To quickly onboard you to Botkube plugins, we maintain the [kubeshop/botkube-plugins-template](https://github.com/kubeshop/botkube-plugins-template) repository that has all batteries included. Our first step is to bootstrap your own GitHub repository.

To check out the entire code, visit the [Botkube GitHub repository](https://github.com/kubeshop/botkube/tree/main/cmd/executor/gh/main.go).

### Repository setup

1. Navigate to [botkube-plugins-template](https://github.com/kubeshop/botkube-plugins-template).

2. Click **Use this template**, and then **Create a new repository**.

github pull request automation
By doing so, you will create your own plugin repository with a single commit.

3. Clone your repository locally:

4. Create and push a new tag to perform the initial release:

After a few minutes, you should see a new GitHub release.

Voilà! You are already an owner of fully functional Botkube plugins. Now it's time to add your own brick by creating a GitHub executor.

INFO

In this blog post, we use only GitHub releases that work out-of-the-box. Releasing plugins on GitHub Pages requires additional setup. To support them too, see the use template document

### Develop GitHub executor

INFO

To make the code-snippets more readable, I skipped the error handling. However, it will be useful if you will add error handling for the final implementation. You can check the full gh source-code for the reference.

1. Create a `cmd/gh/main.go` file with the following template:

This template code imports required packages and registers GHExecutor as the gRPC plugin. Our GHExecutor service already implements the required Protocol Buffers contract. As you can see, we require only 2 methods.


- The Metadata method returns basic information about your plugin. This data is used when the plugin index is generated in an automated way.


- The Execute method is the heart of your executor plugin. This method runs your business logic and returns the output as plaintext. Next, the Botkube core sends back the response to a given communication platform.

2. To download the imported dependencies, in your terminal, run:

3. Great! At this stage, you already have a functional Botkube executor plugin. However, for now, it only responds with a hard-coded "Aloha!" greeting. But it can do that already on all supported communication platforms.

Getting GitHub reports in Slack about repo
Don't worry, in the next steps, we will implement our business logic.

4. Add support for user configuration:

For each Execute method call, Botkube attaches the list of associated configurations. The input parameters are defined by the user, when enabling a given plugin:

In our case, we need to have a GitHub token, a GitHub repository where the issue should be created, and an issue template. The remaining parameters can be hard-coded on the plugin side, however, your plugin will be more flexible if you allow your users to change it without rebuilding your plugins.It's up to the plugin author to merge the passed configurations. You can use our helper function from the plugin extension package (pluginx). To learn more, see Passing configuration to your plugin.

5. Let's implement command parsing to properly understand command syntax:

Our goal is to parse gh create issue KIND/NAME [-n, --namespace]

There are a lot of great libraries supporting command parsing. The most popular is probably cobra, but for our use case, we will just use the helper function from our plugin extension package.


Under the hood, the pluginx.ParseCommand method uses go-arg.


6. We are almost there! Now let's fetch the issue details:


Here, we fetch logs and the cluster version, but you can extend it to fetch other details about your cluster. To make it as simple as possible, we use the kubectl CLI and avoid reimplementing a bit more complicated logic for fetching logs from all different Kubernetes kinds.

7. Render issue description:


In this step, we use the issue template that the user specified in plugin configuration. I decided to use the Go template, as it fits perfectly into our template rendering flow.

8. Finally! Submitting an issue!


GitHub provides a great gh CLI, which we use to submit our issue. To learn more about the CLI syntax, see their manual.

INFO

The gh CLI doesn't accept fine-grained access tokens. As a workaround, you can use the Go SDK.

9. The last part is to download our dependencies.


We already improved this step and in the 0.18 version Botkube will download defined dependencies automatically. For now, you can use the pluginx.DownloadDependencies function to call our downloader explicitly. The syntax will remain the same.

Congrats! The *gh* plugin is finally implemented. Now, let's play a DevOps role! 😈 In the next section, I will show you how to build and release your brand-new executor plugin.

### Release the *gh* executor

It's time to build your plugin. For that purpose, we will use [GoReleaser](https://goreleaser.com/). It simplifies building Go binaries for different architectures. The important thing is to produce the binaries for the architecture of the host platform where Botkube is running. Adjust the **goos**, **goarch**, and **goarm** properties based on this architecture.


Add new build entry under *.goreleaser.yaml*:


Now, we need to distribute our plugins. As we mentioned earlier, a plugin repository can be any static file server. The [kubeshop/botkube-plugins-template](https://github.com/kubeshop/botkube-plugins-template) repository comes with two [GitHub Actions](https://github.com/features/actions):

1. The [.github/workflows/release.yml](https://github.com/kubeshop/botkube-plugins-template/blob/main/.github/workflows/release.yml) action, which builds the plugin binaries and index file each time a new tag is pushed.

2. The [.github/workflows/pages-release.yml](https://github.com/kubeshop/botkube-plugins-template/blob/main/.github/workflows/pages-release.yml) action, which updates GitHub Pages with plugin binaries and index file each time a new tag is pushed.


To cut a new release, you need to commit all your work and tag a new commit:

Next, let's push our changes and the new tag:


This triggers GitHub Action:


### What this automation does under the hood

This automation:

1. Installs the latest GoReleaser tool.

2. Builds all plugin binaries defined in the .goreleaser.yaml file.

3. Generates an index file using the [Botkube helper tool](https://docs.botkube.io/plugin/repo#generate-index-file).

4. Generates a release description.

5. Uses the [gh](https://cli.github.com) CLI to create a new GitHub release.

### Use the gh executor

In the description of a new GitHub release, you will see the repository URL that you can use within Botkube.

### Steps

1. Follow one of our [installation guides](https://docs.botkube.io/installation). Once you reach the Botkube deployment step, add flags specified in the steps below to *helm install*.

2. Export required environment variables:


Follow the official GitHub guide on how to create a personal access token. To be able to create GitHub issues, add the repo permission.

3. Add the *gh* executor related configuration:

4. Depending on the selected platform, add the plugin-based executor binding. For Slack, it looks like this:

If you follow all the steps above, you will have all the necessary flags allowing you to install Botkube with the gh executor!

Here's an example of a full command that you should have constructed for Slack installation:

### Testing

1. Navigate to your communication channel.

2. On a given channel, run: **@Botkube list executors**

It returns information about enabled gh executor

3. Create a failing Job:

After a few seconds, you should see a new alert on your channel

4. To create a GitHub issue for a given alert, run: @Botkube gh create issue job/oops

## Summary

Botkube executors are powerful because they can glue together three important parts: Kubernetes clusters, communicators, and tools of your choice. There would be nothing special about it if it wasn't, in fact, unburdening you of those implementation-specific details.

As you noticed, you can focus purely on your business logic. Without the need to use different chat libraries, know how to establish secure connection, or make your extension available only on specific channels. What's more, not only do you not have to learn it, but you don't have to support it either, as we do it for you.

Once Botkube is deployed, your extension will be available to you and your teammates in a given channel. There is no need to maintain your local setup. Thanks to that, you can also easily run executors on private clusters.

Botkube extensions can be used with other Botkube functionality too. It means that you can use them to create [automation](https://docs.botkube.io/configuration/action). We will shed more light on that in the next blog post. Stay tuned!

Implement once, access everywhere (Slack, Discord, Mattermost, MS Teams).

## How can I get involved?

The implemented plugin is as simple as possible. However, it is a great base for further extension based on your needs; for example: introduce your own Kubernetes annotation to route the notification to a specific repository, add a threshold to create issues only for constantly failing Pods, etc. The possibilities are endless, and we cannot wait to see what kind of great workflows you will create!

As always, we want to hear your feedback and ideas about Botkube. Help us plan the Botkube roadmap, get the features you’d like implemented.