Wednesday, July 29, 2020

How to Execute a Command on a Kubernetes Pod using client-go



In this post we will present a short example of executing a command on a kubernetes pod using the kubernetes client-go library. The client-go library is great for usage, but specifically for the exec command, it is not strait-forward, so I believe an example is a good start for anyone who wishes to use the exec command.

To use the client-go library, wee first need to create a client. This is explained in more details in the post Access Kubernetes API from GoLang.


type K8s struct {
client *kubernetes.Clientset restConfig *rest.Config }

func Produce(insideK8sCluster bool) *K8s {
var err error var restConfig *rest.Config if insideK8sCluster {
restConfig, err = rest.InClusterConfig()
if err != nil {
panic(err)
}
} else {
configPath := filepath.Join(os.Getenv("HOME"), ".kube", "config")
restConfig, err = clientcmd.BuildConfigFromFlags("", configPath)
if err != nil {
panic(err)
}
}

client, err := kubernetes.NewForConfig(restConfig)
if err != nil {
panic(err)
}

return &K8s{
client: client,
restConfig: restConfig,
}
}


Once we have the client ready, we can use it to execute the command.
Notice that the command execution is actually implemented as a streaming HTTP request.


func (k *K8s) Exec(namespace string, pod string, container string, command []string) string {
attachOptions := &k8sApiCore.PodExecOptions{
Stdin: false,
Stdout: true,
Stderr: true,
TTY: false,
Container: container,
Command: command,
}

request := k.client.CoreV1().RESTClient().Post().
Resource("pods").
Name(pod).
Namespace(namespace).
SubResource("exec").
VersionedParams(attachOptions, scheme.ParameterCodec)

stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
streamOptions := remotecommand.StreamOptions{
Stdout: stdout,
Stderr: stderr,
}

exec, err := remotecommand.NewSPDYExecutor(k.restConfig, "POST", request.URL())
if err != nil {
panic(err)
}

err = exec.Stream(streamOptions)
if err != nil {
result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String())
result = strings.TrimSpace(result)
panic(err)
}

result := strings.TrimSpace(stdout.String()) + "\n" + strings.TrimSpace(stderr.String())
result = strings.TrimSpace(result)
return result}


Final Notes

It is not clear why did the kubernetes go-client group did not create a simplified version of the exec, as it is commonly used, but anyways, you can get your need here.

BTW: 
Make sure to have the same dependency version for the k8s API and the k8s client-go in your go.mod file. Otherwise, you will get compilation and/or runtime errors.


module k8s
go 1.14
require (
k8s.io/api v0.18.6 k8s.io/client-go v0.18.6 )

No comments:

Post a Comment