How can I login(in golang using client-go) a k8s pod with multi-containers by webshell?

4/26/2019

Description:

There is no problem to login a container/pod by client-go/remotecommand.NewSPDYExecutor when there is only one container in a pod.

But when there are many containers in a pod, I cannot login by point a container id.

Can anyone help or give me a solution? Thanks in advance.


Nots:

I am using client-go to connect to k8s, and using remotecommand.NewSPDYExecutor to login container.


Code:

Here is the code I am using for login/connect to a pod/container

func (s *ShellService) BuildConnection(shellVo vo.ShellContainerVo) error {

    clu := cluster.GetCluster(shellVo.Cluster)

    if clu == nil {
        logs.Error("cannot find cluster: ", shellVo.Cluster)
        return errors.New("cannot find cluster: " + shellVo.Cluster)
    }

    if shellVo.Command == "" {
        shellVo.Command = "/bin/sh"
    }

    config := clu.Config
    groupversion := schema.GroupVersion{
        Group:   "",
        Version: "v1",
    }
    config.GroupVersion = &groupversion
    config.APIPath = "/api"
    config.ContentType = runtime.ContentTypeJSON
    config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
    restclient, err := rest.RESTClientFor(config)
    if err != nil {
        return err
    }
    fn := func() error {
        req := restclient.Post().
            Resource("pods").
            Name(shellVo.Container).
            Namespace(shellVo.Namespace).
            SubResource("exec").
            Param("container", shellVo.Container).
            Param("stdin", "true").
            Param("stdout", "true").
            Param("stderr", "true").
            Param("command", shellVo.Command).Param("tty", "true")
        c := make(chan *remotecommand.TerminalSize)
        t := &terminalsize{shellVo.Conn, c}
        req.VersionedParams(
            &v1.PodExecOptions{
                Container: shellVo.Container,
                Command:   []string{},
                Stdin:     true,
                Stdout:    true,
                Stderr:    true,
                TTY:       true,
            },
            scheme.ParameterCodec,
        )
        executor, err := remotecommand.NewSPDYExecutor(
            config, http.MethodPost, req.URL(),
        )
        if err != nil {
            return err
        }

        return executor.Stream(remotecommand.StreamOptions{
            //SupportedProtocols: remotecommandconsts.SupportedStreamingProtocols,
            Stdin:             t,
            Stdout:            shellVo.Conn,
            Stderr:            shellVo.Conn,
            Tty:               true,
            TerminalSizeQueue: t,
        })
        //return nil
    }

    inFd, isTerminal := term.GetFdInfo(shellVo.Conn)
    beego.Info(isTerminal)
    state, err := term.SaveState(inFd)
    return interrupt.Chain(nil, func() {
        term.RestoreTerminal(inFd, state)
    }).Run(fn)

    //kubeShell := &pod.Shell{}
    return nil

}

My pod is running with several sidecars. so there are multi containers in a pod. I hope I can login a specified container by provide the container id.

-- tony
client-go
kubernetes
remotecommand

0 Answers