The problem with npm start to start the node app in docker

Viewed 179

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.

1 Answers

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

Related