Home > Software engineering >  How to connect to a docker container from web?
How to connect to a docker container from web?

Time:06-07

I am working on a new project where I need to connect to a docker container from web? By connect I mean I will create a shell in the website and tat shell will be able to connect to the running container.

I am not able to figure out how to proceed with the project. Can anyone help me out?

CodePudding user response:

From what I know there is no out of the box solution, you should make your own api executing command on your container running docker exec <id> <command> and returning the output, mind escape the command.

However you should know that letting a user run commands inside a docker is dangerous as it could impact your host.

CodePudding user response:

You should be able to use Docker APIs for this (https://docs.docker.com/engine/api/) along with a framework that wraps the APIs. For example refer dockerode.

CodePudding user response:

You could combine some JavaScript modules. node-pty and xterm being the most important. Additionally, ws is useful, but could be replaced but something else.

Note: this is not a production ready example. In particular, you should take care of safety measurements, or better yet, let no one but yourself use it.

server.js

import { WebSocketServer, createWebSocketStream } from 'ws';
import pty from 'node-pty';

const wss = new WebSocketServer({ port: 3000 });

wss.on('connection', (ws) => {
    console.log('new connection');

    const duplex = createWebSocketStream(ws, { encoding: 'utf8' });

    const proc = pty.spawn('docker', ['run', "--rm", "-ti", "ubuntu", "bash"], {
        name: 'xterm-color',
        cwd: process.env.HOME,
        env: process.env,
    });

    const onData = proc.onData((data) => duplex.write(data));

    const exit = proc.onExit(() => {
        console.log("process exited");
        onData.dispose();
        exit.dispose();
    });

    duplex.on('data', (data) => proc.write(data.toString()));

    ws.on('close', function () {
        console.log('stream closed');
        proc.kill();
        duplex.destroy();
    });

});

index.html

<!doctype html>
<html>

<head>
    <link rel="stylesheet" href="node_modules/xterm/css/xterm.css" />
    <script src="node_modules/xterm/lib/xterm.js"></script>
</head>

<body>
    <div id="terminal"></div>
    <script type="module">
        const term = new Terminal();
        term.open(document.getElementById('terminal'));
        const ws = new WebSocket('ws://localhost:3000');
        ws.onmessage = async ({ data }) => term.write(await data.text());
        term.onData((data) => ws.send(data));
    </script>
</body>

</html>

Note: I am using the statics from the node modules folder, in your real code you probably want to use a bundler for this.

I am serving the entire project with nginx on port 8080 for simplicity. And then I start the server with node.

docker run -d --rm -p 8080:8080 -v "$PWD:/usr/share/nginx/html" nginxinc/nginx-unprivileged
node server.mjs

Afterwards, I can open http://localhost:8080 in my browser, and get a shell.

The dependencies in my package.json are these:

"dependencies": {
    "node-pty": "^0.10.1",
    "ws": "^8.7.0",
    "xterm": "^4.18.0"
  }

You can view the code in this repo: https://github.com/bluebrown/web-shell.

  • Related