I Built a Kubernetes Controller That Notifies Github When a Kpack Image Build Completes
· 9 min read
After committing source code, it's hard to tell whether the Kpack image build finished! So I built a notification mechanism using a Kubernetes Controller.
Source code
The finished result is here:
https://github.com/mhoshi-vm/kpack-gh-status-updater
First, some terminology
Terms appearing in this article:
- kpack:
A tool that uses Cloud Native Buildpacks to build Stores and buildpacks via Kubernetes Custom Resource Definitions (CRDs). - Kubernetes Controller:
Something that can perform specific operations when an event occurs on a CRD in Kubernetes. This time I implemented it in Java with Spring Boot. - Github Commit Status:
Lets you attach checks to each Github commit and see their status. Usually it displays CI pipeline success/failure, but it can be updated directly via the REST API. Details here.
Of these, the Kubernetes Controller — especially implementing it with the Java framework Spring — is probably the hardest to understand.
I borrowed heavily from this SpringOne content, so watching it will deepen your understanding if you have time:
https://www.youtube.com/watch?v=5IROOj7sLKg
What did I want to solve?
Below is the picture of kpack without this project's deliverable. kpack itself is a wonderful tool, but when you commit source code, checking whether the image was built successfully required going to look at the Kubernetes resource status every single time.

For reference, the build status looks like this:

The information I wanted wasn't detailed — just success or failure. I could have written some polling script, but I wanted something event-driven, as close to real time as possible, so I decided to implement it as a Kubernetes Controller.
The update turns the picture into the one below: by watching Github alone, you can see whether the image completed.

The finished product
When a kpack build starts for a specific commit, you can see it building like this:

When the kpack image completes for a specific commit, it's reflected like this:

On failure it looks like this — the "ah, it failed, I'd better go look" moment:

Development walkthrough
Some of you may be thinking "a Kubernetes Controller in Spring Boot!?", so here's how it was developed.
1. Register the Kubernetes Client in pom.xml
It builds with maven, but the pom.xml is as simple as one generated by start.spring.io. Only the Kubernetes Client dependency is added manually.
2. Create the CRD YAML file
The first thing to develop when building a Kubernetes Controller is the Kubernetes CRD definition YAML. This time I developed it as follows:
https://github.com/mhoshi-vm/kpack-gh-status-updater/blob/main/k8s/crd/build.yaml
For reference, kpack's own CRD definition is here:
https://github.com/pivotal/kpack/blob/main/config/build.yaml
Comparing them, they're quite different. The original kpack doesn't define many values in its schema, which causes trouble in later steps, so I defined the parts I need myself.
3. Generate a Model from the CRD via CodeGen
After defining the CRD, set it up using Github Actions like below. The official guide is here.
I use the Github Actions approach, defined like this:
https://github.com/mhoshi-vm/kpack-gh-status-updater/blob/main/.github/workflows/generate-crd.yaml
Feeding the CRD from before as input produces a Zip file containing the Model. Extracting it pretty much as-is gives the following:
These files in this directory:

4. Define the Controller
This phase is almost pure "incantation". Built exactly as instructed:
One detail: parts of it must point at the Model created in step 3, but beyond that there is little that varies here.
5. Define the Reconciler
The Reconciler definition:
Basically you add your business logic in the @Override part. Watch out for the following:
- For the final result, on success you return
new Result(false)to signal the processing completed. ReturningResult(true)causes the event to be re-queued. - If the resource in the event doesn't exist, interpret it as "deleted". So add that handling.
- Every time you
geta resource, add an existence check.
6. Fill in the business logic (Github notification)
From here on it's plain Java code. Starting at this line, write the Github status update logic.
7. Deploy to the Kubernetes environment
After containerizing the finished code (using kpack for exactly this), deploy it to the Kubernetes environment. The YAML files are here.
Take care to configure Role permissions so the CRD can be accessed correctly. In my case, access to the Build Resource defined in step 2.
Conclusion
Briefly, this introduced Github notifications using a Kubernetes Controller. Being able to develop the Kubernetes Controller in familiar Spring made the barrier to entry feel much lower.
I intend to keep updating the code, and to use it for other applications too.