DEV Community

Penn
Penn

Posted on • Edited on

How to run two nodejs modules in distroless docker image

Recently I tried to replace the Alpine docker image with Distroless to get more benifits. But I met an error said no shell available.
The CMD of the dockerfile is like:

CMD node dosomething.js & node server.js
Enter fullscreen mode Exit fullscreen mode

In this form(aka shell-form), it invokes a command shell to run the commands(node dosomething.js & node server.js).

If you use the shell form of the CMD, then the will execute in /bin/sh -c

Since Distroless doesn't have the builtin shell the error happens.

"Distroless" images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.

I started from the idea that to move the code of dosomething.js into server.js and finally found it's too complicated since the server.js was generated from the source code and it's difficult to insert something and wish it still works.

Then it came to the second idea that is let a runner to start the dosomething.js and server.js as child process. Its code was like:

runner.js

const { fork } = require('child_process')
const path = require('path')

fork(
  path.resolve('dosomething.js'),
  null,
  {
  detached: true
  }
)

fork(
  path.resolve('server.js'),
  null,
  {
    detached: true,
  }
)
Enter fullscreen mode Exit fullscreen mode

Fork will start a child process from the module(the first argument, e.g. path.resolve('server.js')) defined as the first argument.
The second argument is the list of the arguments for server.js. When the server.js accepts arguments to control its behavior then we may add something here. I make it as null since no extra arguments needs for this sample.
The last argument is the options and the detached:true indicates that the child process started from the module(e.g. server.js) run independently of its parent process. It has different behavior on differnt platform but in short you can think it makes the child process continue runing no matter the main dies or not. Suit my requirements.

So finally the CMD in docker file as:

CMD ["runner"]
Enter fullscreen mode Exit fullscreen mode

So above approuch fix the issue. But only when we needs both dosomthing.js and server.js runs it works. What if I want to server.js starts only when dosomthing.jsends with no error or with any error. It could be easily implemented using command shell with the operator && and ||. I will cover this in the next post.

Thanks for reading.

Top comments (0)