1

Hello to all I am using java to create docker containers, I have a problem. Once the container is created I would like to interact with it via stdin but I haven't found a way to do it via SDK java (I use this https://github.com/docker-java/docker-java). I found a code that hijacks the HTTP call to be able to send the commands, but the problem with this code is that it can only send the commands 1 time when it closes the output stream. The code used for the hijack is this here:

https://gist.github.com/missedone/76517e618486db746056

Classse HttpHijack: as you can see on line 120 it closes the stream: socket.shutdownOutput(); (without it would not send the command)

Here is a code example:

ExecCreateCmdResponse execCreateResp = dockerClient.execCreateCmd(CONTAINER_NAME).withCmd("bash")
                .withAttachStderr(true).withAttachStdout(true).withAttachStdin(true).withTty(false).exec();

        HashMap<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");

        HttpHijack ws = new HttpHijack(new URI("http://127.0.0.1:2375/exec/" + execCreateResp.getId() + "/start"));
        String payload = "{\"Detach\": false,\"Tty\": true}";
        ws.post(headers, payload);

        String response = IOUtils.toString(send(ws, "ls -alth"), StandardCharsets.UTF_8);
        System.out.println(response);
        Thread.sleep(3000);
        response = IOUtils.toString(send(ws, "ls -alth /"), StandardCharsets.UTF_8);
        System.out.println(response);

The first call works but the second doesn't.

Can anyone help me? Is there perhaps a way to interact with the stdin directly from the SDK? Or change the HttpHijack class so that it doesn't close the stream?

I would like to be able to interact with the container bash via the exec command.

I am open to different solutions or even to the use of SDKs of verses. Thank you, and I apologize if I may not have formatted the question well, I am new here. Thanks

1
  • 1
    What's the image you're trying to run? Can you set it up with something like an HTTP endpoint, so that you don't need this (complex and dangerous) approach to use it? Commented Oct 20, 2021 at 13:08

2 Answers 2

1

I found the solution to my question.

Using this code

try (PipedOutputStream out = new PipedOutputStream();
                PipedInputStream in = new PipedInputStream(out);
                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
                BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
            AttachContainerCmd attachContainerCmd = docker.attachContainerCmd(createContainerResponse.getId()).withStdIn(in)
                    .withStdOut(true).withStdErr(true).withFollowStream(true);
            attachContainerCmd.exec(new AttachContainerResultCallback());

            String line = "Hello World!";
            while (!"q".equals(line)) {
                writer.write(line + "\n");

                writer.flush();

                line = reader.readLine();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

taken from this link: https://github.com/docker-java/docker-java/issues/941#issuecomment-346377948

now i am able to get l stdin and be able to interact with both docker attach and exec. Having stdin and stdout I can redirect these streams via websocket and then be able to connect to xterm.js which was my main target.

Thanks everyone for the answers

Sign up to request clarification or add additional context in comments.

2 Comments

Still sounds awfully complicated and not very robust. I agree to the comment by David: you should rather expose a service on your docker container, and go through that path. Rest assured: if you are doing something that matters for more than you, for more than one week, then you might regret this approach soon. So, keep in mind: as soon as this approach stops working, consider to abandon it. Maybe it is enough today, but it doesn't sound like a robust base to build something large on top of it.
Having a dedicated app in the docker container is not for me. These are public docker containers and if I install an app on the docker container an attacker who could take control of his docker container could access all the other containers without any problems. With my solution my system will do a security filter and only then will it open xterm.js for you, just like Portainer or Proxmox does for lxc. From the Portainer source I see that they take stdin and stdout and expose it as WS with no other apps.
0

AFAIK docker will capture an enclosed process' stdout as log data. So what your java application that creates a container using docker run... will get is the container ID. Per design this is very suitable for server side processes that do not go interactive.

If you need something else it is questionable whether docker is the ideal solution.

6 Comments

I am creating an application to create minecraft servers, through the sdk I can send the commands and read the output but this only works for the attached window and not for the execute command, and I cannot connect it to xterm.js, as an image I am using a custom one with the minecraft server on top. I would like to be able to have a frontend page with Xterm.js and to be able to connect to the container or start a new execution, as for example Portainer does.
Is it right that your application is outside, the SDK inside a container? Why not place both of them in the same space? Then the interactive nature of the SDK does not have to be carried through docker.
In the container there is the application, so I can isolate the various processes. Then I'd like to have an administration site where I can interact with conateiners. I have no problems with creating new containers, stopping them, backups etc ... What I would like to do is allow to have an xterm.js window to attach to the container. I hope someone knows how to help me. Maybe some system that takes a container and exposes it via websocket? With all the security constraints with access via JWT token for example.
If you talk about xtermjs.org, then that is a siimple addon to be integrated into a website. Zou need a container running a webserver. The same container could offer to handle the requests (or websocket as you say). But this sounds entirely different from the question you raised.
thanks for the answer, the main problem is that for xterm.js I have to have a websocket connection so the question point is how to get this connection from the sdk. I was thinking of a way to take stdin and stdout from sdk and expose it through ws, but just couldn't get l stdin. now i found this code that is right for me. I can get stdin and stdout and then port them to expose as ws to link to xterm.js. github.com/docker-java/docker-java/issues/…
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.