You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker部署Node.js全栈应用Exit Code 137问题求助

问题描述

我正在开发基于Node.js、React-Native、Expo和Docker的全栈应用,执行docker-compose down或docker-compose stop命令时,前端与后端容器的退出状态为Exited(137),但数据库容器正常退出。我希望三个容器均能以状态0正常结束,已尝试使用init:true、tini以及信号处理方案,本地环境运行正常但Docker环境下问题依旧。

相关配置文件及代码

docker-compose.yml

version: '3.8'

services:
  back:
    build: ./backend # 告诉Docker Compose在哪里找到Dockerfile(当前目录)
    ports:
      - "3000:3000" # 将容器的3000端口映射到本地的3000端口
    environment:
      - NODE_ENV=development # 可添加其他需要的环境变量
    volumes:
      - ./backend:/app
      - /app/node_modules
    depends_on:
      database:
        condition: service_healthy

  database:
      image: mysql:8.0.36
      volumes:
      - ./backend/data/create_table.sql:/docker-entrypoint-initdb.d/create_table.sql
      ports:
        - 3306:3306
        - 33060:33060
      environment:
        - MYSQL_ROOT_PASSWORD=root
        - MYSQL_DATABASE=prueba
        - MYSQL_USER=user
        - MYSQL_PASSWORD=user
      healthcheck:
        test: ["CMD-SHELL", "mysql --user=user --password=user --database=prueba -e 'SELECT 1'"]
        interval: 10s
        timeout: 5s
        retries: 5
        start_period: 10s
  
  front:
    build: ./frontend
    volumes:
      - ./frontend:/app
      - /app/node_modules
    stdin_open: true # 等价于docker run的-i参数
    tty: true        # 等价于docker run的-t参数
    ports:
      - "8081:8081"
      - "19000:19000"
      - "19001:19001"
      - "19002:19002"
    environment:
      - NODE_ENV=development
      - EXPO_DEVTOOLS_LISTEN_ADDRESS=0.0.0.0
      - CHOKIDAR_USEPOLLING=true
    depends_on:
      - back

后端Dockerfile

# 选择要使用的Node.js版本
FROM node:18-alpine3.19

# 设置容器内的工作目录
WORKDIR /app

# 将项目配置文件(package.json和可选的package-lock.json)复制到工作目录
COPY package*.json ./

# 安装项目依赖
RUN npm install

# 将项目剩余文件复制到工作目录
COPY . .

# 暴露应用运行的端口
EXPOSE 3000

# 启动应用
CMD ["npm", "start"]

前端Dockerfile

# 使用Node.js基础镜像
FROM node:18-alpine3.19

# 配置容器内的工作目录
WORKDIR /app

# 复制package.json和package-lock.json(如果存在)
COPY package*.json ./

# 安装项目依赖
RUN npm install

# 将项目文件复制到容器内
COPY . .

# Expo CLI默认使用19000端口
EXPOSE 8081
EXPOSE 19000
EXPOSE 19001
EXPOSE 19002

# 启动Expo应用的命令
CMD ["npx", "expo", "start", "--tunnel"]

后端代码

const initDatabase = require('./data/sincro');
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.send("Hola Mundoooo!");
});

// 处理程序终止信号
process.on('SIGTERM', () => {
  console.log('SIGTERM signal received. Exiting.');
  server.close();
  process.exit(0);
});

process.on('SIGINT', () => {
  console.log('SIGINT signal received. Exiting.');
  server.close();
  process.exit(0);
});

// 初始化数据库后启动服务器
initDatabase().then(() => {
  server = app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
  });
});
解决方案

1. 后端容器修复

退出码137通常表示进程被强制杀死(内存不足或收到SIGKILL信号)。核心问题是npm start会启动子进程,导致信号无法直接传递给Node.js主进程。

具体操作:

  • 修改后端Dockerfile的启动命令,直接用node启动入口文件,绕过npm的信号拦截:
    CMD ["node", "app.js"]  # 替换为你的实际入口文件名
    
  • 优化信号处理逻辑,等待服务器关闭完成后再退出,避免强制终止:
    process.on('SIGTERM', () => {
      console.log('收到SIGTERM信号,正在关闭服务器');
      server.close((err) => {
        if (err) {
          console.error('服务器关闭失败:', err);
          process.exit(1);
        }
        console.log('服务器已关闭,退出进程');
        process.exit(0);
      });
    });
    
    process.on('SIGINT', () => {
      console.log('收到SIGINT信号,正在关闭服务器');
      server.close((err) => {
        if (err) {
          console.error('服务器关闭失败:', err);
          process.exit(1);
        }
        console.log('服务器已关闭,退出进程');
        process.exit(0);
      });
    });
    

2. 前端Expo容器修复

Expo CLI同样会创建子进程,加上tty: true和stdin_open: true的配置,可能干扰信号传递。

具体操作:

  • 在docker-compose.yml的front服务中添加init: true,让tini作为PID 1管理信号转发:
    front:
      build: ./frontend
      volumes:
        - ./frontend:/app
        - /app/node_modules
      stdin_open: true
      tty: true
      init: true  # 新增该行
      ports:
        - "8081:8081"
        - "19000:19000"
        - "19001:19001"
        - "19002:19002"
      environment:
        - NODE_ENV=development
        - EXPO_DEVTOOLS_LISTEN_ADDRESS=0.0.0.0
        - CHOKIDAR_USEPOLLING=true
      depends_on:
        - back
    
  • 修改启动命令为exec模式,确保信号直接传递给Expo进程:
    CMD ["sh", "-c", "exec npx expo start --tunnel"]
    

3. 通用优化

  • 给所有Node.js服务(back和front)都添加init: true,确保PID 1进程正确转发信号
  • 如果不需要交互式终端,可去掉stdin_open: true和tty: true配置,减少信号干扰

内容的提问来源于stack exchange,提问作者Martinikoh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 19:35:54