I’m running a command line app from a Node.js process using spawn()
. The process is launched with extra pipes in the stdio option. Here’s a simplified code sample:
const stdio = ['ignore', 'pipe', 'pipe', 'pipe', 'pipe'];
const process = spawn('/path/to/command', [], { stdio });
// Later...
const { 3: pipeWrite, 4: pipeRead } = process.stdio;
pipeRead.on('data', (data) => {
if (String(data) === "PING?") {
pipeWrite.write("PONG!");
}
});
Now, this works fine but I want to run the command inside a docker container, using docker run
as the spawned executable:
const stdio = ['ignore', 'pipe', 'pipe', 'pipe', 'pipe'];
const process = spawn(
'/usr/bin/env', [
'docker',
'run',
'--rm',
'my-image',
'/path/to/command'
], { stdio }
);
This fails, the command line app inside the docker container says it cannot write to pipe. Is it possible to achieve this with docker run
?
I’ve set up a Github repo that demonstrates the problem, though I should make it clear that this is merely a demonstration and I do not have the means to change behaviour of the real child process (which is Chromium, in case anyone is interested!).
2
Answers
EDITED: It seems docker ignores extraneous pipes, and the approach above does not work. What you could do instead, is create a shared volume, in which a stream/pipe is generated, and use it like you would want to.
Be aware that it is generally advised to avoid piping large amounts of data in/out of docker, as this results in quite heavy log files. (Among other issues)
Consider using a TCP socket from the host into the container instead
The method you are trying isn’t achievable. A child process can share the file descriptors with parent however when running a process inside docker it is containerized first. You can achieve this using named pipes instead of pipes. Named pipes are like pipes but have the interface of a file.
According to this it is doable using named pipes:
This is the modified code of the Github repo you posted:
test.js
ponger.js
Before you run
npm test
while in the directory of the project execute the following :The previledges are only for test purposes, keep in mind that such a setting can ruin the security of your application.
PS. I can elaborate further on why your approach will not going to work in this setting.