skip to Main Content

I read some Docker and Node.js Best Practices articles, e.g. https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md or 10 best practices to containerize Node.js web applications with Docker or Dockerfile good practices for Node and NPM. All these article were written or updated at least in 2021, I don’t list the articles written before 2021 but there quite some.

They are all against CMD ["npm", "run", "start"]. The main reason is npm will swallow the exit signals such as SIGTERM and SIGINT, so the graceful shutdown code in my node app won’t run.

I guess it was the case for the old npm (although I didn’t test it), but I have tested node14+npm6 and node16+npm8 and I can verify that npm6/8 do NOT swallow those events and my graceful shutdown code is run. Not sure if that was because npm fixed it.

So the only problem remains is there is 1 more process, npm, to run, i.e. NPM run as PID 1. Some articles said the problem with that is "PID 1 will not respond to SIGINT" but as I have verified that is not the case.

Many articles (e.g. this nodejs doc) suggest just CMD [ "node", "server.js" ] but also in https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md#handling-kernel-signals said "Node.js process running as PID 1 will not respond to SIGINT (CTRL-C) and similar signals.", i.e. nodejs own documents contradict themselves (but I do see nodejs as PID 1 responds to SIGINT)

So I am confused with the problem with CMD ["npm", "run", "start"] or CMD [ "node", "server.js" ]

For my app there is 1 more consideration, my npm scripts has pre hook to make the app run correctly, I have prestart npm script to make npm start work. So currently I just use CMD ["npm", "run", "start"] but I am confused with the "best practice" of how to start my node app in docker.

— update —

I found this closed issue for npm lifecycle: propagate SIGTERM to child

So they did fix it but the latest comment in that issue was in 2017, which said "Yes, this isn’t working, at least with bash; npm runs its lifecycle processes in a shell, and bash doesn’t forward SIGTERM to its children."

I realize I only tested that on my mac and on our CentOS server, and the alpine based docker. It may also because I use exec form, not shell form in CMD so I got the exit signal.

Graceful shutdown with Node.js and Kubernetes said their alpine image didn’t get SIGTERM using npm start, while I test on alpine3.15 and I can get.

2

Answers


  1. To work around the swallow of SIGINT and SIGTERM, I do this:

    CMD [ "bash", "-c", "npm run db:migrate && node ./dist/server/index.js" ]
    

    where npm run db:migrate && node ./dist/server/index.js was the content of my npm start

    Login or Signup to reply.
  2. with NPM:

    CMD [ "npm", "run", "start" ]
    

    check the process graph on docker container

    $ ps ajxf
     PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
        0     1     1     1 pts/0        1 Ssl+     0   0:01 npm run start
        1    19     1     1 pts/0        1 S+       0   0:00 sh -c -- node server.js
       19    20     1     1 pts/0        1 Sl+      0   0:00  _ node server.js
    

    the npm process shawns a shell process, which then spawns the node process. This means that npm does not spawn the node process as a direct child.

    causes the npm process to fail to pass signals to the node process.

    this is different than how npm behaves locally, where it spawns the node process directly.

    with node

    CMD [ "node", "server.js" ]
    

    process graph

    $ ps ajxf
     PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
        0     1     1     1 pts/0        1 Ssl+     0   0:00 node server.js
    

    Node.js was not designed to run as PID 1 which leads to unexpected behaviour when running inside of Docker. For example, a Node.js process running as PID 1 will not respond to SIGINT (CTRL-C) and similar signals

    solution:

    CMD [ "bash", "-c", "node server.js" ]
    

    Or use the tini/s6 init system

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search