Running remote command inside a container with Kubernetes API

Roaming Roadster
4 min readNov 18, 2023

--

Kubernetes provides a powerful API that allows you to interact with and manage your containerized applications. Running commands remotely inside a container in Kubernetes can be useful for various use cases, especially when you need to interact with and manage containers deployed in a Kubernetes cluster. Here are some common use cases:

Debugging and Troubleshooting

When an application deployed in a container is not behaving as expected, administrators and developers may need to inspect the container’s environment, logs, or configuration. Running commands remotely allows them to troubleshoot and diagnose issues without accessing the host machine directly.

Log Inspection

Checking and analyzing logs is a common task during debugging or when investigating issues. Running commands inside a container allows you to inspect log files and gather information on the container’s behavior.

Configuration Verification

Verifying configurations inside a container is crucial. Running commands remotely enables you to check the configuration files, environment variables, and other settings within the container to ensure they are correctly set.

Data Inspection

Sometimes it’s necessary to inspect data stored within a container. You might need to run commands to list files, check file contents, or perform other data-related tasks.

Custom Script Execution

You may have custom scripts or automation tasks that need to be executed inside containers. Running commands remotely allows you to automate these tasks as part of your deployment or operational procedures.

Temporary Access for Maintenance

In certain situations, administrators may need temporary access to containers for maintenance tasks. Running commands remotely provides a controlled way to perform maintenance without compromising the overall system.

Resource Monitoring

Running commands to monitor resource utilization, such as CPU and memory usage, can help administrators ensure that containers are running efficiently and within specified resource limits.

To run a command remotely, you can use kubectl exec command, but sometimes you may want to do this programmatically. In Go, the remotecommand package in the client-go library provides a convenient way to achieve this.

In this tech article, we’ll explore how to use remotecommand.NewSPDYExecutor to run commands inside a container remotely from a Go program.

Accessing the Kubernetes API

Before diving into remote container management, it’s crucial to understand how to access the Kubernetes API securely. Kubernetes supports authentication and authorization mechanisms, such as Service Accounts, Role-Based Access Control (RBAC), and client certificates. Ensure that your setup adheres to best security practices to protect sensitive information and maintain the integrity of your cluster.

Setting Up the Go Environment

Let’s start by setting up the Go environment for our project. Create a new Go file, e.g., main.go, and initialize the Go module:

go mod init remote-command-example

Writing the Code

package main

import (
"flag"
"os"
"path/filepath"
"strings"

corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/remotecommand"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/util/homedir"
)

func main() {
var kubeconfig *string
var podName, namespace, containerName, command string

flag.StringVar(&podName, "pod", "", "Name of the pod")
flag.StringVar(&namespace, "namespace", "", "Namespace of the pod")
flag.StringVar(&containerName, "container", "", "Name of the container")
flag.StringVar(&command, "command", "", "Command to execute in the container")

if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "location of your kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "location of your kubeconfig file")
}
flag.Parse()

config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}

// Create a Kubernetes client
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}

// Split the command string into individual arguments
commandArgs := strings.Fields(command)

req := clientset.CoreV1().RESTClient().
Post().
Resource("pods").
Name(podName).
Namespace(namespace).
SubResource("exec").
VersionedParams(&corev1.PodExecOptions{
Container: containerName,
Command: commandArgs,
Stdin: true,
Stdout: true,
Stderr: true,
TTY: false,
}, scheme.ParameterCodec)

executor, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
if err != nil {
panic(err.Error())
}

err = executor.Stream(remotecommand.StreamOptions{
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
Tty: false,
})
if err != nil {
panic(err.Error())
}
}

Command-Line Flags

  • The program accepts command-line flags for pod name (--pod), namespace (--namespace), container name (--container), and the command to be executed (--command).

Kubernetes Configuration

  • The code reads the Kubernetes configuration from the kubeconfig file provided or the default location.

Creating Exec Request

  • It constructs an exec request using clientset.CoreV1().RESTClient() and sets parameters such as pod name, namespace, container name, and command.

Use PodExecOptions to create command

  • we can simply pass command as a parameter to clientset:
req := clientset.CoreV1().RESTClient().
Post().
Resource("pods").
Name(podName).
Namespace(namespace).
SubResource("exec").
Param("container", containerName).
Param("stdin", "false").
Param("stdout", "true").
Param("stderr", "true").
Param("tty", "false").
Param("command", command)

But it does not accept parameters of the command, such as ls -al. So we use PodExecOptions to create command with parameters:

req := clientset.CoreV1().RESTClient().
Post().
Resource("pods").
Name(podName).
Namespace(namespace).
SubResource("exec").
VersionedParams(&corev1.PodExecOptions{
Container: containerName,
Command: commandArgs,
Stdin: true,
Stdout: true,
Stderr: true,
TTY: false,
}, scheme.ParameterCodec)

Creating Executor

  • The code creates an executor using remotecommand.NewSPDYExecutor with the specified HTTP method, URL, and Kubernetes configuration.

Running the Command

  • Finally, the program streams the command execution with executor.Stream using standard input, output, and error streams.

Running the Program

To run the program, use the following command:

$ go run main.go --pod your-pod-name --namespace your-namespace -container your-container-name --command "echo Hello"
Hello

Replace placeholders with your actual pod, namespace, container names, and the desired command. You should be able to see the output of the command.

Conclusions

Understanding how to run command remotely can empower developers to automate tasks, troubleshoot issues, and interact with containerized applications in a Kubernetes environment programmatically. Hopefully this guide can help you to get the concept of remote command.

--

--