从Docker SDK中获取容器的输出

huangapple go评论78阅读模式
英文:

Grab output from container in Docker SDK

问题

我正在尝试使用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
}

这段代码看起来没有明显的错误。它创建了一个容器,并将stdout和stderr附加到容器上。然后,它启动容器并将输出复制到提供的io.Writer接口。你可以检查一下你的代码是否正确调用了这个Run函数,并且确保你传递了正确的io.Writer对象作为参数。如果问题仍然存在,你可以尝试打印一些调试信息,以便更好地理解发生了什么。

英文:

I'm trying to run a container using Docker SDK for golang and I can't get the output from the container. I'm using the following code for that that actually runs the container, but doesn't sends back stderr and stdout of the application. Can you advice what I'm doing wrong?

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
}

答案1

得分: 1

问题是在2017年提出的,我在2022年回答。我知道API可能已经改变了,但我遇到了类似的问题。

我们不谈如何启动容器,因为你似乎已经做到了。这是我从给定容器中获取日志的代码:

// GetLogs 从容器中获取日志 io.ReadCloser。调用者的责任是执行 stdcopy.StdCopy。
// 使用其他方法可能会导致未知的 Unicode 字符,因为日志输出同时包含 stdout 和 stderr。
// 以该行是否为 stderr 或 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())
}

如果你还有疑问,请告诉我第二部分。我很乐意帮助,因为我曾经遇到过类似的问题。

英文:

The question was asked in 2017 and I'm answering it in 2022. I understand the APIs might have changed, but I have landed on a similar boat.

Let's not talk about how to start a container as you seem to have already done that. Here is my code to fetch the logs from a given container:

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

You can call this GetLogs from another routine. I am saving both of the stream in specific files. But you may want to use os.Stdout and os.Stderr if you just want to see them on your terminal:

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

Let me know the second part if you still have confusion. I'm happy to help as I had a similar problem.

huangapple
  • 本文由 发表于 2017年8月18日 20:29:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/45756681.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定