来自Golang API的Docker exec命令

时间:2018-10-12 07:53:37

标签: docker go

需要帮助。我有从Docker容器执行命令的代码。需要从exec命令正确获取stdout。

execConfig:= types.ExecConfig{Tty:false,AttachStdout:true,AttachStderr:false,Cmd:command}
    respIdExecCreate,err := cli.ContainerExecCreate(context.Background(),dockerName,execConfig)
    if err != nil {
        fmt.Println(err)
    }
    respId,err:=cli.ContainerExecAttach(context.Background(),respIdExecCreate.ID,types.ExecStartCheck{})
    if err != nil {
        fmt.Println(err)
    }
    scanner := bufio.NewScanner(respId.Reader)
    for scanner.Scan() {
       fmt.Println(output)
}

从输出中我看到了有趣的情况: Screen from gyazo

如何正确删除字节?

我只发送命令:= [] string {“ echo”,“-n”,“ hello word”}

1 个答案:

答案 0 :(得分:0)

我也遇到过同样的问题,这就是stderr和stdout找我的方式:

StdOut: "\x01\x00\x00\x00\x00\x00\x00\thello world\n"
StdErr: "\x01\x00\x00\x00\x00\x00\x00fError: Exec command has already run\r\n"

我已经检查了docker源代码并在此处找到答案

https://github.com/moby/moby/blob/8e610b2b55bfd1bfa9436ab110d311f5e8a74dcb/integration/internal/container/exec.go#L38

看起来像这样的前导字节,特别用于标记stdoutstderr字节。

有一个"github.com/docker/docker/pkg/stdcopy"库,可以从流阅读器中拆分stdoutstderr

type ExecResult struct {
    StdOut string
    StdErr string
    ExitCode int
}

func Exec(ctx context.Context, containerID string, command []string) (types.IDResponse, error) {
    docker, err := client.NewEnvClient()
    if err != nil {
        return types.IDResponse{}, err
    }
    defer closer(docker)

    config :=  types.ExecConfig{
        AttachStderr: true,
        AttachStdout: true,
        Cmd: command,
    }

    return docker.ContainerExecCreate(ctx, containerID, config)
}

func InspectExecResp(ctx context.Context, id string) (ExecResult, error) {
    var execResult ExecResult
    docker, err := client.NewEnvClient()
    if err != nil {
        return execResult, err
    }
    defer closer(docker)

    resp, err := docker.ContainerExecAttach(ctx, id, types.ExecConfig{})
    if err != nil {
        return execResult, err
    }
    defer resp.Close()

    // read the output
    var outBuf, errBuf bytes.Buffer
    outputDone := make(chan error)

    go func() {
        // StdCopy demultiplexes the stream into two buffers
        _, err = stdcopy.StdCopy(&outBuf, &errBuf, resp.Reader)
        outputDone <- err
    }()

    select {
    case err := <-outputDone:
        if err != nil {
            return execResult, err
        }
        break

    case <-ctx.Done():
        return execResult, ctx.Err()
    }

    stdout, err := ioutil.ReadAll(&outBuf)
    if err != nil {
        return execResult, err
    }
    stderr, err := ioutil.ReadAll(&errBuf)
    if err != nil {
        return execResult, err
    }

    res, err := docker.ContainerExecInspect(ctx, id)
    if err != nil {
        return execResult, err
    }

    execResult.ExitCode = res.ExitCode
    execResult.StdOut = string(stdout)
    execResult.StdErr = string(stderr)
    return execResult, nil
}