从Docker SDK中的容器获取输出

yzuktlbb  于 2022-11-02  发布在  Docker
关注(0)|答案(1)|浏览(255)

我尝试使用Docker SDK for golang运行一个容器,但无法从容器中获得输出。我使用以下代码来运行容器,但不会将stderr和stdout发送回应用程序。您能告诉我我哪里做错了吗?

type dckr struct {
    cli      *client.Client
    username string
    password string
    addr     string
    ctx      context.Context
}

func (d *dckr) Run(containername string, image string, command []string, bind []string, stdout io.Writer, stderr io.Writer) error {
    log.Printf("[Create] %s -> %s \n", image, containername)

    res, err := d.cli.ContainerCreate(
        d.ctx,
        &container.Config{
            User:         "root",
            AttachStdout: true,
            AttachStderr: true,
            Image:        image,
            Cmd:          command,
        },
        &container.HostConfig{
            AutoRemove: true,
            Binds:      bind,
        },
        &network.NetworkingConfig{},
        containername,
    )

    if err != nil {
        log.Println("[Create] Failed. %s", err)
        return err
    }
    defer d.cli.ContainerRemove(d.ctx, res.ID, types.ContainerRemoveOptions{Force: true})

    log.Printf("[Create] id: %s \n", res.ID)
    for wrn := range res.Warnings {
        log.Printf("[Create] %s \n", wrn)
    }

    rsp, err := d.cli.ContainerAttach(d.ctx, containername, types.ContainerAttachOptions{
        Stream: false,
        Stdout: true,
        Stderr: true,
        Logs:   true,
    })

    if err != nil {
        log.Printf("[Attach] Fail. %s \n", err)
        return err
    }
    log.Printf("[Attach] %s", res.ID)
    defer rsp.Close()

    err = d.cli.ContainerStart(d.ctx, res.ID, types.ContainerStartOptions{})
    if err != nil {
        log.Printf("[Run] Fail. %s \n", err)
        return err
    }

    _, err = stdcopy.StdCopy(stdout, stderr, rsp.Reader)
    return err
}
qcbq4gxm

qcbq4gxm1#

这个问题是在2017年提出的,我在2022年回答了这个问题。我知道API可能已经改变了,但我已经登上了一艘类似的船。
让我们不讨论如何启动容器,因为您似乎已经这样做了。下面是我的代码,用于从给定容器中获取日志:

// GetLogs return logs from the container io.ReadCloser. It's the caller duty
// duty to do a stdcopy.StdCopy. Any other method might render unknown
// unicode character as log output has both stdout and stderr. That starting
// has info if that line is stderr or stdout.
func GetLogs(ctx context.Context, cli *client.Client, contName string) (logOutput io.ReadCloser) {
    options := types.ContainerLogsOptions{ShowStdout: true}

    out, err := cli.ContainerLogs(ctx, contName, options)
    if err != nil {
        panic(err)
    }

    return out
}

你可以从另一个例程中调用这个GetLogs。我把这两个流都保存在特定的文件中。但是如果你只是想在终端上看到它们,你可能需要使用os.Stdoutos.Stderr

func main() {
    stdoutLog, _ := os.Create("yourContainerName.log")
    defer stdoutLog.Close()
    stderrLog, _ := os.Create("yourContainerName.err")
    defer stderrLog.Close()

    var stdout bytes.Buffer
    var stderr bytes.Buffer

    containerLog := docker.GetLogs(ctx, dc, "yourContainerName")
    stdcopy.StdCopy(&stdout, &stderr, containerLog)
    stdoutLog.Write(stdout.Bytes())
    stderrLog.Write(stderr.Bytes())
}

让我知道第二部分,如果你仍然有困惑。我很乐意帮助,因为我有一个类似的问题。

相关问题