【问题标题】:NPM start script runs from local shell but fails inside Docker container commandNPM 启动脚本从本地 shell 运行,但在 Docker 容器命令中失败
【发布时间】:2019-11-15 02:03:07
【问题描述】:

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

"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",
...
}

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

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

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

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

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 run start-all 列为 Node 服务的命令。但是如果我像这样将它添加到 Dockerfile 中并没有什么区别:

RUN npm run start-all

可能会发生什么? pm2 日志只显示应用程序已启动的报告。

【问题讨论】:

    标签: node.js docker docker-compose pm2 concurrently


    【解决方案1】:

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

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

    Docker 集成

    使用容器?我们得到了你的支持。从今天开始使用 pm2-runtime,一个 在生产中充分利用 Node.js 的完美伴侣 环境。

    pm2-runtime 的目标是将您的应用程序包装成适当的 Node.js 生产环境。它解决了运行时的主要问题 容器内的 Node.js 应用程序,例如:

    高应用程序可靠性流程的第二个流程回退 控制自动应用程序监控以使其始终保持健全和 高性能的自动源地图发现和解析支持

    docker-pm2-nodejs

    第二个重要的事情,你应该把你所有的应用程序放在 pm2 配置文件中,因为 docker 只能从CMD 运行进程。

    生态系统文件

    PM2 增强了您的流程管理工作流程。它允许您 微调行为、选项、环境变量、日志文件 每个应用程序都通过一个进程文件。它特别适用于 基于微服务的应用程序。

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

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

    然后在 Dockerfile 中添加CMD

    CMD ["pm2-runtime", "process.yml"]
    

    从 docker-compose 中删除 command

    【讨论】:

      【解决方案2】:

      Docker 和 pm2 提供了重叠的功能:例如,两者都具有重新启动进程和管理日志的能力。在 Docker 中,仅在容器内运行一个进程通常被认为是一种最佳实践,如果这样做,则不一定需要 pm2。 what is the point of using pm2 and docker together? 对此进行了更详细的讨论。

      运行镜像时,您可以指定要运行的命令,并且可以从同一个镜像启动多个容器。鉴于您最初显示的 Dockerfile,您可以将它们启动为

      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 Compose;它的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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-28
        • 2011-10-03
        • 2019-07-17
        • 2015-03-30
        • 2015-10-13
        • 2015-09-11
        • 1970-01-01
        相关资源
        最近更新 更多