DEV Community

Muaaz Saleem
Muaaz Saleem

Posted on • Originally published at muaazsaleem.com

Creating a Go Kubernetes client with client-go

I mostly use client-go to talk to the Kubernetes API in my go applications.

Whenever I'm starting a new project I inevitably have to figure out the setup steps. I thought I'll just document these for myself here.

A client-go "Hello, World!"

Creating a client that implements kubernetes.Interface is just kubernetes.NewForConfig()

import "k8s.io/client-go/kubernetes"

client, err := kubernetes.NewForConfig(kubeconfig)
if err != nil {
    return nil, fmt.Errorf("unable to create a client: %v", err)
}
Enter fullscreen mode Exit fullscreen mode

Creating Client Config

Creating the config defers for go clients within and outside of the clients. I think this is mostly because access tokens need to be read to from a mounted file rather than the kubeconfig file.

Creating out of cluster config

import "k8s.io/client-go/tools/clientcmd"

config, err := clientcmd.BuildConfigFromFlags(
    "", kubeconfigPath,
)
if err != nil {
    return nil, fmt.Errorf(
        "unable to load kubeconfig from %s: %v", 
        kubeconfigPath, err,
        )
}
Enter fullscreen mode Exit fullscreen mode

Creating in cluster config

import "k8s.io/client-go/rest"

config, err := rest.InClusterConfig()
if err != nil {
    return nil, fmt.Errorf("unable to load in-cluster config: %v", err)
}
Enter fullscreen mode Exit fullscreen mode

Putting it all together

import (
    "fmt"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/clientcmd"
)

func createClient(kubeconfigPath string) (kubernetes.Interface, error) {
    var kubeconfig *rest.Config

    if kubeconfigPath != "" {
        config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
        if err != nil {
            return nil, fmt.Errorf("unable to load kubeconfig from %s: %v", kubeconfigPath, err)
        }
        kubeconfig = config
    } else {
        config, err := rest.InClusterConfig()
        if err != nil {
            return nil, fmt.Errorf("unable to load in-cluster config: %v", err)
        }
        kubeconfig = config
    }

    client, err := kubernetes.NewForConfig(kubeconfig)
    if err != nil {
        return nil, fmt.Errorf("unable to create a client: %v", err)
    }

    return client, nil
}
Enter fullscreen mode Exit fullscreen mode

Testing with Fake Client

When testing client-go code it's useful to use the built-in fake client. Here's a short example:

import (
    "context"
    "testing"

    "k8s.io/client-go/kubernetes/fake"
    appsv1 "k8s.io/api/apps/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "github.com/stretchr/testify/require"
)

func TestKubeClient(t *testing.T) {
    fc := fake.NewSimpleClientset(&exampleDeploy)

    deploy, err := fc.AppsV1().Deployments("ns").Get(
        context.Background(),
        "deployment",
        metav1.GetOptions{},
    )

    require.NoError(t, err)
Enter fullscreen mode Exit fullscreen mode

Managing package dependencies

client-go version needs to match that of the cluster we're using. I have sometimes had trouble with importing the right k8s.io/api and k8s.io/apimachinery dependencies so here's a example for that as well.

go.mod


module github.com/muaazsaleem/example

go 1.13

require (
// we only really need client-go here the right `api` and 
// `apimachinery` versions "should" get picked up
    k8s.io/client-go v0.19.0
    k8s.io/api v0.19.0
    k8s.io/apimachinery v0.19.0
// stuff I use in pretty much all my projects
    github.com/sirupsen/logrus v1.7.0
    github.com/stretchr/testify v1.6.1
)
Enter fullscreen mode Exit fullscreen mode

Further Resources

If you'd like to learn more about building things with the Kubernetes API, Vladimir Vivien has a whole series on it.

The client-go docs have also improved. There are examples now!

Top comments (0)