开发kubernetes控制器中可能涉及到进入特定的container中执行命令的操作,或者拷贝文件等操作,此时我们可能会借助client-go提供的这个工具去实现:
"k8s.io/client-go/tools/remotecommand"
// 构建请求
req := client.RESTClient().Post().
Resource("pods").
Name(podName).
Namespace(namespace).
SubResource("exec")
req.VersionedParams(&v1.PodExecOptions{
Container: containerName,
Command: cmd,
Stdin: false,
Stdout: true,
Stderr: true,
TTY: true,
}, scheme.ParameterCodec)
// 创建执行器
exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
// 执行命令
exec.Stream(remotecommand.StreamOptions{
Stdin: nil,
Stdout: &buf,
Stderr: &buf,
Tty: true,
})
上面代码执行时会向apiserver发起一个请求,apiserver会通过代理机制将请求转发给相应节点上的kubelet服务,kubelet会通过cri接口调用runtime的接口发起流式接口中的Exec()接口进入到container执行。针对一般化的命令调用,输入参数和输出结果多数以文本为主,并不会占用带宽和apiserver的资源,但是当设计到文件拷贝的时候则会占用较多带宽,因此在实际使用时这种方式拷贝大文件来说可能并不是最优方案。
此处顺便描述一下如kubectl工具对cp命令的原理,其实也是调用的exec接口,然后执行tar命令进行文件的拷贝动作:
# 从容器向外拷贝,通过tar命令压缩将输出重定向到标准输出
tar cf - <srcFile# 从外面向容器内拷贝,将标准输入数据通过tar解压写入到container内的文件目录
tar --no-same-permissions --no-same-owner -xmf -
# 或
tar -xmf -
考虑到上面所说的带宽问题,在实际使用时也可向kubelet直接发起exec请求,只要通过client-go将pod所在节点实现查询一下即可,当然还会设计一些端口,证书问题,下面是一个直接向kubelet发起请求的示例代码。
package main
import…
探索client-go中的exec和cp的原理
发布于