部署在AWS的Node.js API服务间歇性超时崩溃,日志报SIGTERM错误
问题概述
部署在AWS上的Node.js API服务间歇性出现超时,进而导致服务器崩溃,CloudWatch日志频繁出现以下错误:
npm ERR! path /app npm ERR! command failed npm ERR! signal SIGTERM npm ERR! command sh -c -- npm run build && node dist/server.js npm ERR! A complete log of this run can be found in: npm ERR! /root/.npm/_logs/2022-11-11T11_54_06_397Z-debug-0.log
相关配置信息:
- Dockerfile内容:
#!/bin/sh FROM node:16-bullseye-slim RUN apt-get update; \ apt-get install -y python3; \ apt-get install -y python2 make; \ apt-get install -y g++; \ ln -s /usr/bin/python2.7 /usr/bin/python; ARG app_env ARG DOPPLER_TOKEN ARG DOPPLER_PROJECT ARG DOPPLER_CONFIG ENV NODE_ENV=${app_env} ENV DOPPLER_TOKEN=${DOPPLER_TOKEN} ENV DOPPLER_PROJECT=${DOPPLER_PROJECT} ENV DOPPLER_CONFIG=${DOPPLER_CONFIG} WORKDIR /app COPY package*.json ./ RUN npm install RUN npm ci --only=production COPY . . CMD ["npm", "run", "start:server"] EXPOSE 3000
- package.json启动脚本:
"start:server": "npm run build && node dist/server.js"
- Node版本:
v16.13.2,Npm版本:8.19.0
排查方向及解决方案
1. 定位SIGTERM信号来源
SIGTERM是系统发送的终止信号,在AWS环境中常见触发原因:
- 容器健康检查失败,AWS自动终止并重启容器
- 容器内存/CPU资源超限,触发资源回收
- ECS/EKS等编排服务的任务调度(如扩缩容、任务更新)终止容器
- 应用自身未处理优雅关闭,导致强制终止
操作: 查看AWS对应服务的事件日志(如ECS任务事件、EKS Pod事件),确认是否有任务终止的明确原因记录。
2. 优化Docker构建与启动流程
当前启动脚本每次容器启动时都执行npm run build,会大幅增加启动时间,极易触发AWS健康检查超时,进而导致SIGTERM终止容器。同时Dockerfile存在依赖安装冗余问题。
优化方案:采用多阶段构建,将build步骤放在镜像构建阶段,而非容器启动阶段
修改后的Dockerfile示例:
# 构建阶段:完成代码编译 FROM node:16-bullseye-slim AS builder WORKDIR /app # 先复制依赖文件,利用Docker缓存 COPY package*.json ./ RUN npm ci # 复制源代码并执行构建 COPY . . RUN npm run build # 生产阶段:仅保留运行所需文件 FROM node:16-bullseye-slim WORKDIR /app ARG app_env ARG DOPPLER_TOKEN ARG DOPPLER_PROJECT ARG DOPPLER_CONFIG ENV NODE_ENV=${app_env} ENV DOPPLER_TOKEN=${DOPPLER_TOKEN} ENV DOPPLER_PROJECT=${DOPPLER_PROJECT} ENV DOPPLER_CONFIG=${DOPPLER_CONFIG} # 安装生产依赖 COPY package*.json ./ RUN npm ci --only=production # 从构建阶段复制编译后的产物 COPY --from=builder /app/dist ./dist # 直接启动服务,无需再build CMD ["node", "dist/server.js"] EXPOSE 3000
同时修改package.json启动脚本为:
"start:server": "node dist/server.js"
3. 检查应用的信号处理逻辑
Node.js进程默认收到SIGTERM会直接退出,若应用未处理优雅关闭逻辑,可能导致正在处理的请求中断,甚至触发崩溃。需在代码中添加SIGTERM信号监听,实现优雅关闭:
process.on('SIGTERM', () => { console.log('收到SIGTERM信号,开始优雅关闭'); // 停止接受新请求 server.close(() => { console.log('HTTP服务器已关闭'); // 关闭数据库连接等资源 process.exit(0); }); // 设置超时,强制退出 setTimeout(() => { console.error('优雅关闭超时,强制退出'); process.exit(1); }, 5000); });
4. 验证资源配置是否充足
检查AWS容器的内存/CPU配额,对比CloudWatch监控指标(内存使用率、CPU使用率),确认是否存在资源超限导致的容器终止。若资源不足,需调整容器的资源配置。
5. 调整健康检查配置
检查AWS健康检查的参数:
- 健康检查路径是否正确返回200状态码
- 调整健康检查的超时时间、间隔时间,适配应用启动速度(优化后启动速度会大幅提升,可适当缩短)
- 确保健康检查的端口与应用暴露端口一致
6. 分析npm debug日志
日志中提到的/root/.npm/_logs/2022-11-11T11_54_06_397Z-debug-0.log包含更详细的错误信息,可通过docker exec进入运行中的容器,或者在Dockerfile中添加日志复制逻辑,将该日志导出查看,确认build过程或服务启动时是否有具体错误。
内容的提问来源于stack exchange,提问作者Olusegun

