dotnet / Docker.DotNet

:whale: .NET (C#) Client Library for Docker API
https://www.nuget.org/packages/Docker.DotNet/
MIT License
2.23k stars 381 forks source link

How to start an interactive session with StartContainerExecAsync? #652

Closed EsZHONG closed 1 year ago

EsZHONG commented 1 year ago

Hi,

I'm trying to start an interactive session against container like what docker exec -i would do. However, with the following code I'm only able to get the first batch of output (from powershell.exe) and seems whatever I enter after that was not executed in container.

I've confirmed that inputs are wrote to the stream by setting a breakpoint at MultiplexedStream.WriteAsync(). But can't confirm if they're executed in container as no output can be seen and typing exit doesn't lead to anything.

    DockerClient dockerClient = new DockerClientConfiguration(
                       new Uri("npipe://./pipe/docker_engine"))
                 .CreateClient();
    ContainerExecCreateResponse response = await dockerClient.Exec.ExecCreateContainerAsync("<container id>", new 
        ContainerExecCreateParameters()
            {
                AttachStderr = true,
                AttachStdin = true,
                AttachStdout = true,
                Cmd = new List<string>() { "powershell.exe", "-noexit" },
                Detach = false, // Also tried true but getting exactly the same behavior
                Tty = true

    });

    Console.WriteLine(response.ID);

    MultiplexedStream multiplexedStream = await dockerClient.Exec.StartAndAttachContainerExecAsync(response.ID, true);

    var stdinTask = Task.Run(async () =>
    {
        await multiplexedStream.CopyFromAsync(Console.OpenStandardInput(), CancellationToken.None);
    });

    var stdoutTask = Task.Run(async () =>
    {
            await multiplexedStream.CopyOutputToAsync(
                     Console.OpenStandardInput(),
                     Console.OpenStandardOutput(),
                     Console.OpenStandardError(),
                     CancellationToken.None);
    });
    await Task.WhenAll(stdinTask, stdoutTask);

What version of Docker.DotNet?:

3.125.15

Can someone kindly share how to properly use the stream and start an interactive session? Or if it's simply not supported at all?

Thanks in advance!

EsZHONG commented 1 year ago
            ContainerExecCreateResponse response = await dockerClient.Exec.ExecCreateContainerAsync(container, new ContainerExecCreateParameters()
            {
                AttachStderr = true,
                AttachStdin = true,
                AttachStdout = true,
                Cmd = new List<string>() { "powershell.exe" },
                Detach = false,
                Tty = true

            });

            MultiplexedStream multiplexedStream = await dockerClient.Exec.StartAndAttachContainerExecAsync(response.ID, true);

            var stdinTask = Task.Run(async () =>
            {
                await multiplexedStream.CopyFromAsync(Console.OpenStandardInput(), CancellationToken.None);
            });

            var stdoutTask = Task.Run(async () =>
            {
                    await multiplexedStream.CopyOutputToAsync(
                            Console.OpenStandardInput(),
                            Console.OpenStandardOutput(),
                            Console.OpenStandardError(),
                            CancellationToken.None);
            });

            await Task.WhenAny(stdinTask, stdoutTask);
            multiplexedStream.Dispose();

Got the answer from GPT, which seems to be working with a small format issue.