實驗目的:使用client-go進入任一pod執行命令,模擬終端.
比較簡單 直接上代碼
/*
模擬 ``ctl exec -it pods -n namespace -- /bin/sh `` 命令
# ctl get po -n a | grep client
elasticsearch-client-7bf748d697-bfd9p 1/1 Running 1 36d
*/
func ExecPodCom() {
config := config.KubeConfig()
clientSet,err := kubernetes.NewForConfig(config); if err != nil {
logrus.Println(err.Error())
}
// 初始化pod所在的corev1資源組,發送請求
// PodExecOptions struct 包括Container stdout stdout Command 等結構
// scheme.ParameterCodec 應該是pod 的GVK (GroupVersion & Kind)之類的
req := clientSet.CoreV1().RESTClient().Post().
Resource("pods").Name("elasticsearch-client-7bf748d697-bfd9p").
Namespace("a").
SubResource("exec").
VersionedParams(&coreV1.PodExecOptions{
Command: []string{"bash","-c","/bin/sh"},
Stdin: true,
Stdout: true,
Stderr: true,
TTY: true, // 打開linux終端
},scheme.ParameterCodec)
// remotecommand 主要實現了http 轉 SPDY 添加X-Stream-Protocol-Version相關header 並發送請求
exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
// 檢查是不是終端
if !terminal.IsTerminal(0) || !terminal.IsTerminal(1) {
fmt.Errorf("stdin/stdout should be terminal")
}
// 這個應該是處理Ctrl + C 這種特殊鍵位
oldState, err := terminal.MakeRaw(0); if err != nil {
fmt.Println(err.Error())
}
// 讀取當前狀態
fd := int(os.Stdin.Fd())
oldState, err = terminal.MakeRaw(fd); if err != nil {
fmt.Println(err.Error())
}
defer terminal.Restore(fd, oldState)
// 用IO讀寫替換 os stdout
screen := struct {
io.Reader
io.Writer
}{os.Stdin, os.Stdout}
// 建立鏈接之后從請求的sream中發送、讀取數據
if err = exec.Stream(remotecommand.StreamOptions{
Stdin: screen,
Stdout: screen,
Stderr: screen,
Tty: true,
}); err != nil {
fmt.Print(err)
}
}
執行
zisefeizhu@zisefeizhudeMacBook-Pro ~/linkun/goproject/operator go run main.go
INFO[0000] init root.go...
/Users/zisefeizhu/linkun/goproject/operator/config/config.yaml
kubeConfig /Users/zisefeizhu/.kube/config
sh-4.2# ls
LICENSE.txt README.asciidoc config jdk logs plugins
NOTICE.txt bin data lib modules repository-s3-7.8.0.zip
sh-4.2# cd logs/
sh-4.2# ls
gc.log gc.log.00