Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Docker exec command from golang api

Tags:

docker

go

Need help.I have code to exec command from docker container. Need corrently get stdout from exec command.

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)
}

From output i see interesting situation: Screen from gyazo

How corrently remove bytes ?

I send simply command := []string{"echo","-n", "hello word"}

like image 302
Ильдар Нурмухаметов Avatar asked Oct 12 '18 07:10

Ильдар Нурмухаметов


People also ask

How do I run a command in Docker exec?

Follow these steps: Use docker ps to get the name of the existing container. Use the command docker exec -it <container name> /bin/bash to get a bash shell in the container. Or directly use docker exec -it <container name> <command> to execute whatever command you specify in the container.

What is Docker EXEC command?

The docker exec command runs a new command in a running container. The command started using docker exec only runs while the container's primary process ( PID 1 ) is running, and it is not restarted if the container is restarted. COMMAND will run in the default directory of the container.

What is the difference between docker run and exec?

What's the Difference between Docker Run and Docker Exec? Docker Run vs Docker Exec! This is a fairly common question – but has a simple answer! In short, docker run is the command you use to create a new container from an image, whilst docker exec lets you run commands on an already running container!


1 Answers

I've faced with same issue, this is how stderr and stdout looks for me:

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"

I've cheched docker source code and found answer here:

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

looks like this leading bytes used especially for marking stdout and stderr bytes.

And there is a library "github.com/docker/docker/pkg/stdcopy" which can split stdout and stderr from stream reader:

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
}
like image 109
Oleg Neumyvakin Avatar answered Oct 11 '22 16:10

Oleg Neumyvakin