controller runtime client basics

controller-runtime is a SIG project that makes building Controllers (or other native k8s apps) easier. But their client isn’t completely automagic like client-go. Below is an outline of the basic CRUD and useful links for finding the missing info faster.

Minimal client setup

All you need is a rest.Config. The simplest way to generate one is using config.GetConfigOrDie() which will traverse usual locations of kubeconfig files (i.e. $HOME/.kube).

import (
    "sigs.k8s.io/controller-runtime/pkg/client"
    "sigs.k8s.io/controller-runtime/pkg/client/config"
)

func main() {
    c, _ := client.New(config.GetConfigOrDie(), client.Options{})
}

Using the client

All CRUD operations are docuemnted on the client docs page. Depending on the call signature, we need up to three pieces:

Where do objects come from

The canonical reference is the api repo. The Objects are in the types.go file of their respective API group.

As an example. The Nodes object are in core/v1 group, so the Nodes struct is in core/v1/types.go. And can be used as:

import (
    corev1 "k8s.io/api/core/v1"
)

func main() {
    node := &corev1.Node{}
}

Using ObjectKey

Get() takes an ObjectKey object. The ObjectKey is an indirection to the types.NamespacedName Object. This object can be generated on the fly as there are only two keys: Namespace and Name.

_ := client.Get(context.TODO(), client.ObjectKey{
    Name: "Name",
}, node)

Generating ListOptions

controller-runtime has a convienant way to construct ListOptions objects using MatchingLabels or MatchingFields. Both are string maps to strings, and makes it very simple to list objects with specific label or field values.

package main

import (
    "fmt"
    "context"

    corev1 "k8s.io/api/core/v1"
    "sigs.k8s.io/controller-runtime/pkg/client"
    "sigs.k8s.io/controller-runtime/pkg/client/config"
)


func main() {

    c, _ := client.New(config.GetConfigOrDie(), client.Options{})
    nodes := &corev1.NodeList{}
    filter := client.MatchingLabels{
        "node-role.kubernetes.io/control-plane": ""
        }

    _ = c.List(context.TODO(), nodes, filter)

    for _, node := range nodes.Items {
        fmt.Println(node.ObjectMeta.GetName())
    }
}

Written on September 6, 2021