Pros and Cons of Using client-go in Kubernetes controllers
Tags: kubernetes, go
Published: 2021-01-17 17:38:21

When writing a kubernetes controller I often use [client-go](https://github.com/kubernetes/client-go) to talk to the Kubernetes API. I'm beginning to realize though, that client-go isn't always the best approach, sometimes it can be simpler to use a hand rolled HTTP client, based on go's `net/http` package.

Today, I want to share some of the Pros & Cons of using client-go, as I understand them, in Kubernetes controllers or other go applications.

### Pros of using client-go

#### Helpful Utilities

client-go comes with helpful utilities e.g to create in-cluster or out-of-cluster kubeconfig and authenticate against the API Server i.e `kubernetes.NewForConfig` and `clientcmd.BuildConfigFromFlags` respectively. 

I end up using these in every Kubernetes app that I write.

### Implementations for all kubernetes API Objects

I find unmarshalling kubernetes resources from JSON to go, pretty cumbersome, particularly if I need to access a deeply nested field e.g reading the `replicas` from the `status` of a [Deployment](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#deployment-v1-apps) object.

client-go handles marhsalling/unmarshalling of all [compatible](https://github.com/kubernetes/client-go/#compatibility-your-code---client-go) Kubernetes resources out of the box. So that's a big help.

### Powerful abstractions for common use casses

Common use cases such as watching resources or testing API calls are well supported with abstractions like [Shared Informers](https://github.com/kubernetes/client-go/tree/master/examples/workqueue) and [fake-client](https://github.com/kubernetes/client-go/tree/master/examples/fake-client).

### Cons of using client-go

#### Cognitive Overload
This by far the biggest frustration I have when using client-go. Just figuring out the right `k8s.io/api` & `k8s.io/api-machinery` dependencies to match my `k8s.io/client-go` version used to be a struggle. Thankfully with go modules and the new [versioning scheme](https://github.com/kubernetes/client-go#versioning) that's really improved.

I still get lost in all the imports regularly, with the sheer no. of structs and interfaces, it's not always clear if I actually need everything I'm importing. Integration tests written with the fake client can also be daunting for a new person to understand. 

Sometimes this is just symptom of the scarce docs availble!

#### Scarce Docs
Even though there are now actually some hello-world examples in the client-go repo, docs for the go client are still pretty scarce. The first time I had to learn what Informers were, my choices? A random blog post or the actual code. 

This means that my usage of the library is only as good as the latest blogpost/book/code I've read. I can understand feeling that way about a more complicated tool, like a Database, but should I have to feel this way about an HTTP client?

### Not the most idiomatic go-code
Using client-go sometimes requires comitting generated code or dealing with `*string` types. The library isn't always an example of the most idomatic go code.

This might be totally OK for experience go devs, but as someone still learning how to write good go code. I find this confusing.  
  
### Further Resources

I still think client-go is worth using for full fledge controllers, especially when dealing with multiple Kubernetes objects. For simple scripts, I'd like to invest more in just using plain go.

If you'd like to learn more about client-go, I can't recommend [Programming Kubernetes](https://programming-kubernetes.info/) by Michael Hausenblas and Stefan Schimanski enough!

Some other places:
- [github.com/../client-go](https://github.com/kubernetes/client-go/)
- [5 Time saving things about client-go, I didn't know!](/blog/5-time-saving-things-about-client-go-i-didnt-know)
- [Creating a Go Kubernetes client with client-go](/blog/creating-a-go-kubernetes-client-with-client-go)