NPM 启动脚本从本地 shell 运行但在 Docker 容器命令中失败

NPM start script runs from local shell but fails inside Docker container command

我有一个 Node 应用程序,它由三个独立的 Node 服务器组成,每个服务器 运行 pm2 start。我用concurrently到运行这三台服务器,作为start-all的脚本在package.json:

"scripts": {
    ...
    "start-all": "concurrently \" pm2 start ./dist/foo.js \" \"pm2 start ./dist/bar.js \" \"pm2 start ./dist/baz.js\"",
    "stop-all": "pm2 stop all",
    "reload-all": "pm2 reload all",
...
}

当从本地主机上的命令行 运行ning 时,这一切 运行 都很好,但是当我 运行 它作为 docker-compose 命令时 - 或者作为我的 Docker 文件中的 RUN 命令 - 只有一个服务器脚本(我每次尝试时随机一个!)将启动,但随后立即退出。在我的 --verbose docker-compose 输出中,我可以看到 pm2 面板(列表名称、版本、模式、pid 等),但随后显示此错误消息:

pm2 start ./dist/foo.js exited with code 0.

N.B:这都是在 Docker 运行 本地进行的(在具有 16GB RAM 的 Mac Mini 上), 不在远程服务器上。

如果我 docker exec -it <container_name> /bin/bash 进入容器和 运行 npm run start-all 手动从 src 目录的顶层(我 COPY 在我的 Docker文件)一切正常。这是我的 Docker 文件:

FROM node:latest

# Create the workdir
RUN mkdir /myapp
WORKDIR /myapp

# Install packages
COPY package*.json ./
RUN npm install

# Install pm2 and concurrently globally.
RUN npm install -g pm2
RUN npm install -g concurrently

# Copy source code to the container
COPY . ./

在我的 docker-compose 文件中,我只是将 npm 运行 start-all 列为节点服务的命令。但是如果我像这样将它添加到 Docker 文件中没有什么区别:

RUN npm run start-all

可能发生了什么? pm2 日志只显示应用已启动。

第一个原因是 pm2 start app.js 在后台启动应用程序,这就是为什么您的容器在 运行s pm2 start.

后立即停止的原因

您需要使用pm2_runtime启动一个应用程序,它会在前台启动一个应用程序。你也不需要 concurrently,pm2 process.yml 将完成这项工作。

Docker 整合

Using Containers? We got your back. Start today using pm2-runtime, a perfect companion to get the most out of Node.js in production environment.

The goal of pm2-runtime is to wrap your applications into a proper Node.js production environment. It solves major issues when running Node.js applications inside a container like:

Second Process Fallback for High Application Reliability Process Flow Control Automatic Application Monitoring to keep it always sane and high performing Automatic Source Map Discovery and Resolving Support

docker-pm2-nodejs

第二个重要的事情,你应该把你所有的应用程序都放在pm2配置文件中,因为docker只能运行来自[=16的进程=].

生态系统文件

PM2 empowers your process management workflow. It allows you to fine-tune the behavior, options, environment variables, logs files of each application via a process file. It’s particularly useful for micro-service based applications.

pm2 config application-declaration 创建文件 process.yml

apps:
  - script   : ./dist/bar.js
    name     : 'bar'
  - script : ./dist/foo.js
    name   : 'worker'
    env    :
      NODE_ENV: development

然后在Docker文件

中添加CMD
CMD ["pm2-runtime", "process.yml"]

从 docker-compose 中删除 command

Docker 和 pm2 提供重叠的功能:例如,两者都具有重启进程和管理日志的能力。在 Docker 中,通常认为容器中只有 运行 一个进程是最佳实践,如果这样做,则不一定需要 pm2。 同时使用 pm2 和 docker 有什么意义? 对此进行了更详细的讨论。

当您 运行 您的映像时,您可以指定 运行 命令,并且您可以从同一个映像启动多个容器。根据您最初显示的 Docker 文件,您可以将它们作为

启动
docker run --name foo myimage node ./dist/foo.js
docker run --name bar myimage node ./dist/bar.js
docker run --name baz myimage node ./dist/baz.js

这样您就可以执行一些操作,例如在代码更改时仅重启其中一个容器,同时保持其余容器不变。

您暗示 Docker 撰写;它的 command: 指令设置相同的 属性.

version: '3'
services:
  foo:
    build: .
    command: node ./dist/foo.js
  bar:
    build: .
    command: node ./dist/bar.js
  baz:
    build: .
    command: node ./dist/baz.js