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)
}
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,
)
}
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)
}
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
}
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)
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
)
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)