Reputation: 421
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
}
Upvotes: 0
Views: 1225
Reputation: 27875
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.
Upvotes: 2