Looking back on "Building Better Controllers" 2 years later

Over 2 years ago, I started working on some ideas to build better Kubernetes controllers. In this post, I wanted to give a bit of a retrospective on how things have gone since then. Over the years working on Istio and other projects, I observed a number of major issues with controllers: Most code was about error-prone event handling and state reconciliation, rather than business logic. Most tests, in turn, were about the same. This, in turn, made the code extremely complex, brittle, and often incorrect. This complexity lead to user facing compromise: incorrectness and performance issues. You might argue I should just write a better controller that is faster and without bugs. Maybe, but probably not. ...

November 3, 2024 · 7 min

Inline (YAML) Langauge Injection in JetBrains IDEs

JetBrains IDEs (IntelliJ, GoLand, etc) have a nifty feature called Language Injection that lets you get full language features when a language is embedded within another. For example, a SQL query within a string within a Go file. A few of these come out of the box, but they are pretty limited -- I only had some XML ones prior to enabling the Databases plugin which added a few SQL ones. Fortunately, there is the ability to add custom ones. Unfortunately, this is expressed in a proprietary language with, as far as I can tell, zero documentation. ...

September 27, 2024 · 1 min

Building a better Kubernetes Client

Like most other Kubernetes controllers in, Istio is written in Go and relies on the client-go library. While this provides an excellent low-level building block, usage in higher level code in Istio led to a variety of issues that led us to develop our own higher level, opinionated client for Istio. This post covers the issues we faced and how we incrementally solved them. Background knowledge At a high level, client-go provides a few layers for interactions with the API server: ...

March 23, 2024 · 7 min

Analyzing Go Binary Sizes

In Analyzing Go Build Times, I went over how to analyze and understand Go build times, and what factors impact build times. A close cousin to build times is build sizes. Large binaries can lead to a variety of issues such as: Generally, slower build times Increased costs of storage Increased costs and time to distribute Increased memory usage at runtime (more on this in another article, hopefully) So its generally nice to keep them small. ...

 · January 6, 2024 · 8 min

An optimal CI/CD system

Exploring an (unfortunately, hypothetical) CI/CD system for end to end tests on Kubernetes.

September 6, 2023 · 6 min

GOMAXPROCS and GOMEMLIMIT in Kubernetes

How and why to easily these fields

July 31, 2023 · 2 min

Zero allocations metrics with opentelemetry-go

In the past, Istio has suffered from performance issues from OpenCensus, which was used for metrics reporting. At extremes, we saw up to 20% of CPU spent just on incrementing various metrics. This was mitigated to some extent by batching metrics updates, optimizing OpenCensus itself, and caching parts of our OpenCensus usage. At best, we got down to roughly 600ns and 3 allocations per metric update. As OpenCensus is now deprecated, I have been looking into migration to OpenTelemetry - and hoping to avoid these issues this time around. ...

July 11, 2023 · 2 min

Analyzing Go Build Times

Go is often praised for its fast build times. While they are pretty quick, they are slow enough that I spend a lot of time waiting for them, enough that it prompted me to go down the rabbit hole of thoroughly analyzing them. This post covers all aspects of what makes Go builds fast or slow. Throughout this blog, we will use Istio as an example of real-world codebase. For reference on its size: ...

 · June 24, 2023 · 26 min

Ergonomic Map in Go

In many languages, on of the things I find myself doing is maping over a list to extract some field. For example, coverting a []Person to []Name. Most languages these days have ways to do this pretty easily: Kotlin: people.map { it.Name } JavaScript: people.map(p => p.Name) Rust: people.map(|p| p.Name) Scala: people.map(_.Name) With generics, Go finally can do this in a type safe manner: Map(people, func(t Person) string { return t.Name }) ... but we immediately stand out amongst other languages as having ugly, verbose syntax. ...

January 31, 2023 · 5 min