英文:
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.Stdout
和 os.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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论