如何通过K8S API实现Pod内命令执行及无依赖文件查看?
问题解答
完全可以通过Kubernetes原生API实现kubectl exec的等效操作,你没在Pod核心API文档中找到对应接口,是因为exec属于Pod的子资源接口,不在核心的Pod增删改查接口列表中。
核心实现逻辑
kubectl exec本质调用的是/api/v1/namespaces/{命名空间}/pods/{Pod名称}/execPOST接口,接口入参包含要执行的命令、是否开启stdin/stdout/stderr、是否分配TTY、目标容器名等字段,对应你代码中的PodExecOptions结构体。- 因为命令执行是流式交互场景,该接口走SPDY或WebSocket协议实现数据传输,不能用普通HTTP请求处理,你找到的Go示例中使用的
remotecommand.NewSPDYExecutor就是官方封装好的SPDY协议处理工具,无需自行实现协议解析。
无额外依赖UI工具开发建议
- 若做带后端的Web UI,无需依赖本地kubectl,后端封装好exec接口调用逻辑,前端只需传入命名空间、Pod名、容器名、文件查看类命令(比如
ls、cat、pwd),后端拿到执行结果返回给前端渲染即可。 - 若做纯前端无后端工具,可直接调用K8s APIServer的WebSocket版本exec接口,路径格式为
/api/v1/namespaces/{ns}/pods/{name}/exec?command={命令}&container={容器名}&stderr=true&stdout=true&stdin=false&tty=false,只要前端有权限访问APIServer、携带正确的认证信息即可直接调用,无任何额外依赖。
kubectl exec命令对应API调用说明
你用到的kubectl exec -ti POD_NAME -- pwd,对应exec接口只需传入command: ["pwd"],同时开启stdin、stdout、tty参数即可实现等效效果。
你提供的Go实现代码优化提示
你贴出的代码已经是完整的exec调用实现,仅需修正一处小问题:原代码PodExecOptions结构体中的Container字段误写为podName,建议改为containerName变量,避免Pod多容器场景下调用报错,修正后代码如下:
package main import ( "bytes" "context" "flag" "fmt" "path/filepath" corev1 "k8s.io/api/core/v1" _ "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/remotecommand" "k8s.io/client-go/util/homedir" // // Uncomment to load all auth plugins // _ "k8s.io/client-go/plugin/pkg/client/auth" // // Or uncomment to load specific auth plugins // _ "k8s.io/client-go/plugin/pkg/client/auth/azure" // _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" // _ "k8s.io/client-go/plugin/pkg/client/auth/openstack" ) func main() { var kubeconfig *string if home := homedir.HomeDir(); home != "" { kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file") } else { kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file") } flag.Parse() // use the current context in kubeconfig config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) if err != nil { panic(err.Error()) } // create the clientset clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err.Error()) } namespace := "stage" pods, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { panic(err.Error()) } fmt.Printf("There are %d pods in the cluster\n", len(pods.Items)) podName := "ubs-job-qa-0" containerName := "ubs-job" req := clientset.CoreV1(). RESTClient(). Post(). Resource("pods"). Name(podName). Namespace(namespace). SubResource("exec"). Param("container", containerName) scheme := runtime.NewScheme() if err := corev1.AddToScheme(scheme); err != nil { panic("Cannot add scheme") } parameterCodec := runtime.NewParameterCodec(scheme) req.VersionedParams(&corev1.PodExecOptions{ Stdin: false, Stdout: true, Stderr: true, TTY: true, Container: containerName, // 修正为容器名 Command: []string{"ls", "-la", "--time-style=iso", "."}, }, parameterCodec) exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL()) if err != nil { panic(err) } var stdout, stderr bytes.Buffer err = exec.Stream(remotecommand.StreamOptions{ Stdin: nil, Stdout: &stdout, Stderr: &stderr, }) if err != nil { panic(err) } text := string(stdout.Bytes()) fmt.Println(text) }
内容的提问来源于stack exchange,提问作者Mr.Wang from Next Door
相关产品推荐
相关产品推荐

