Writing events to pods using client-go

lucassha

Shannon

Posted on October 27, 2022

Writing events to pods using client-go

In the past, I've written controllers utilizing Kubebuilder, where the instantiation of an event recorder is basically done for you with a mgr.GetRecorder() method in the controller manager.

When writing a small binary with client-go, however, I found it surprisingly difficult. It took digging through kubernetes source code to find a couple examples, and I thought I'd document it here.


Scaffolding

Before running the code, let's spin up a pod in the default namespace kubectl run nginx --image=nginx --namespace default

We will be attaching sample events to this pod.

Code

Full code here since some of the packages are specifically named

package main

import (
    "context"
    "path/filepath"
    "time"

    log "github.com/sirupsen/logrus"
    corev1 "k8s.io/api/core/v1"
    v1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/client-go/kubernetes"
    typedv1core "k8s.io/client-go/kubernetes/typed/core/v1"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/tools/record"
    "k8s.io/client-go/util/homedir"
)

func main() {
    kubeconfig := filepath.Join(homedir.HomeDir(), ".kube", "config")
    config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
    if err != nil {
        log.Info("connecting with config in-cluster")
        config, err = rest.InClusterConfig()
        if err != nil {
            log.Fatal(err)
        }
    }
    if err != nil {
        log.Fatal(err)
    }

    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        log.Fatal(err)
    }

    pod, err := clientset.CoreV1().Pods("default").Get(context.TODO(), "nginx", metav1.GetOptions{})
    if err != nil {
        log.Fatal(err)
    }

    scheme := runtime.NewScheme()
    _ = corev1.AddToScheme(scheme)

    // all the good events stuff is here
    eventBroadcaster := record.NewBroadcaster()
    eventBroadcaster.StartStructuredLogging(4)
    eventBroadcaster.StartRecordingToSink(&typedv1core.EventSinkImpl{Interface: clientset.CoreV1().Events("")})
    eventRecorder := eventBroadcaster.NewRecorder(scheme, v1.EventSource{})
    eventRecorder.Event(pod, corev1.EventTypeNormal, "is this thing on", "is this thing on")
    eventBroadcaster.Shutdown()
    time.Sleep(2 * time.Second)
}

Enter fullscreen mode Exit fullscreen mode

Things worth noting:

  • You must add the corev1 scheme for the pod, as it is a corev1 object type. If you are using any other object type, make sure to add the appropriate scheme.
  • I added a time.Sleep() because of the asynchronous nature of this. Without some wait time, the process will exit too quickly and no events will populate.
  • eventRecorder.Eventf() is a lot more useful than my above example
  • If anyone understands the internal workings of k8s events better, please send some articles my way ;)

Seeing the events with kubectl

We can see it by querying events:

(⎈|kind-kind:default)learning/write-events-client-go » k get events -n default | grep "is this thing on"
71s         Normal   is this thing on   pod/nginx   is this thing on
Enter fullscreen mode Exit fullscreen mode

But more interestingly, we can also see them attached to the pod object itself:

(⎈|kind-kind:default)learning/write-events-client-go » k describe pod nginx | grep -A 10 Events
Events:
  Type    Reason            Age   From               Message
  ----    ------            ----  ----               -------
  Normal  Scheduled         37s   default-scheduler  Successfully assigned default/nginx to kind-control-plane
  Normal  Pulling           37s   kubelet            Pulling image "nginx"
  Normal  Pulled            36s   kubelet            Successfully pulled image "nginx" in 1.112899376s
  Normal  Created           36s   kubelet            Created container nginx
  Normal  Started           36s   kubelet            Started container nginx
  Normal  is this thing on  10s                      is this thing on
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
lucassha
Shannon

Posted on October 27, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Where GitOps Meets ClickOps
devops Where GitOps Meets ClickOps

November 29, 2024

Cloud Security for DevOps Teams
undefined Cloud Security for DevOps Teams

November 29, 2024

Installing Kubernetes using Kubeadm utility
kubernetes Installing Kubernetes using Kubeadm utility

November 29, 2024