Overview
It’s been a goal of mine for a while to write a Kubernetes operator. I was playing with Kubeless and I didn’t like how they implemented their support for Golang so I decided to write my own.
Operators
Operators are a deployment of a Kubernetes controller and Custom Resource Definitions (CRDs). The controller watches in a loop for new custom resources created and then takes some action. The controller lets you extend the ability of Kubernetes without directly changing any Kubernetes code.
Serverless
Serverless allows you to run an application without caring about the underlying infrastructure. Examples are AWS Lambda, GCP Cloud Functions, Azure Functions, Vercel, etc.
Goless
Goless lets you define a Go based web handler as a CRD and deploy it into your cluster. It then creates a Kubernetes Deployment, Service, and Configmap based on that CRD. Goless uses a build image as an init container that injects your handler code into a Go application’s source code, and then builds the binary. It then copies that statically linked executable into a scratch container and runs the binary. It includes basic logging middleware and also Prometheus metrics out of the box. Updating your CRD in turn updates your serverless function and Goless will deploy the new version and terminate the old once the new is running.
Because the binary is built at run time, the cold start time is longer, around 20 seconds. However, since these are just native Kubernetes objects the pod would only be rebuilt on a failure. It does not automatically scale down.
Example
Here’s an example of how simple a Goless handler can be:
apiVersion: goless.io/v1beta1
kind: Function
metadata:
name: function-sample
spec:
service: "sample"
serverPort: 9000
function: |
package handlers
import (
"net/http"
)
func Handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("This works!"))
}
Conclusion
As I mentioned, writing an operator has been a goal of mine for a while. I sometimes struggle to write/learn things if I don’t have a real use case and this gave me a real life use case with which to work. I liked the real time build of Kubeless but didn’t like the way they implemented their Go support. This gave me the push I needed to write my own implementation. It was a great learning experience and I hope to add more features as time goes on.