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

使用CodeDeploy部署Node.js至AWS EC2遇3000端口占用部署失败

问题描述

通过AWS CodeDeploy向EC2实例部署基础Node.js应用时触发部署失败:应用设计为监听3000端口,但部署启动阶段该端口已被运行中的Node.js进程占用。手动登录实例终止占用3000端口的进程后,对应进程会自动重启,端口始终无法释放。

错误信息
[stderr]+ return 1
[stderr]+ '[' -n 'Now using node v16.15.0 (npm v8.5.5)' ']'
[stderr]+ '[' 0 -ne 1 ']'
[stderr]+ nvm_echo 'Now using node v16.15.0 (npm v8.5.5)'
[stderr]+ command printf '%s\n' 'Now using node v16.15.0 (npm v8.5.5)'
[stdout]Now using node v16.15.0 (npm v8.5.5)
[stderr]+ EXIT_CODE=0
[stderr]+ set -e
[stderr]+ return 0
[stderr]+ npm ci
[stdout]
[stdout]added 183 packages, and audited 184 packages in 1s
[stdout]
[stdout]16 packages are looking for funding
[stdout] run `npm fund` for details
[stdout]
[stdout]1 critical severity vulnerability
[stdout]
[stdout]To address all issues (including breaking changes), run:
[stdout] npm audit fix --force
[stdout]
[stdout]Run `npm audit` for details.
[stderr]+ npm start
[stdout]
[stdout]> web@0.0.1 start
[stdout]> node server.js
[stdout]
[stderr]node:events:505
[stderr] throw er; // Unhandled 'error' event
[stderr] ^
[stderr]
[stderr]Error: listen EADDRINUSE: address already in use :::3000
[stderr] at Server.setupListenHandle [as _listen2] (node:net:1372:16)
[stderr] at listenInCluster (node:net:1420:12)
[stderr] at Server.listen (node:net:1508:7)
[stderr] at Object.<anonymous> (/home/ec2-user/Web/server.js:47:8)
[stderr] at Module._compile (node:internal/modules/cjs/loader:1105:14)
[stderr] at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
[stderr] at Module.load (node:internal/modules/cjs/loader:981:32)
[stderr] at Function.Module._load (node:internal/modules/cjs/loader:822:12)
[stderr] at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
[stderr] at node:internal/main/run_main_module:17:47
[stderr]Emitted 'error' event on Server instance at:
[stderr] at emitErrorNT (node:net:1399:8)
[stderr] at processTicksAndRejections (node:internal/process/task_queues:83:21) {
[stderr] code: 'EADDRINUSE',
[stderr] errno: -98,
[stderr] syscall: 'listen',
[stderr] address: '::',
[stderr] port: 3000
[stderr]}

报错核心为EADDRINUSE: address already in use :::3000,即启动时3000端口已被占用。手动杀进程后自动重启,说明当前占用端口的Node进程受进程守护机制管控,直接kill子进程会被守护进程重新拉起。

解决方案

第一步:定位并彻底停用旧的守护进程

先顺着进程链路找到拉起Node进程的上层守护程序,从守护层停服才能彻底释放端口:

  • 执行命令查询3000端口对应的进程PID:sudo lsof -i :3000 或者 sudo ss -tulpn | grep :3000
  • 拿到PID后查询父进程ID:ps -o ppid= -p <上一步拿到的PID>,顺着父进程链路向上排查,常见的守护场景和处理方式如下:
    • 若父进程为pm2:执行pm2 list查看托管的应用列表,执行pm2 delete <对应应用ID/名称>即可彻底停掉进程,关闭自动重启
    • 若父进程为PID=1的systemd:到/etc/systemd/system/目录下查找和Node、当前应用名相关的service配置文件,执行sudo systemctl stop <服务名>、sudo systemctl disable <服务名>即可停止服务并关闭开机自启
    • 若存在定时巡检拉起规则:执行crontab -l查看当前用户定时任务,同时检查/etc/cron.d/、/etc/crontab等系统定时任务配置,删除自动拉起Node进程的规则即可

第二步:优化CodeDeploy部署流程,避免后续重复出现端口冲突

在CodeDeploy的应用部署spec文件中,补充生命周期钩子逻辑,从流程上避免端口抢占:

  • 在ApplicationStop或BeforeInstall阶段增加停服逻辑:如果是pm2托管就执行对应pm2停服/重载命令,如果是systemd托管就先执行systemctl stop命令,确认旧进程完全退出、端口释放后再进入安装、启动新应用的阶段
  • 可在启动脚本前增加端口检测逻辑,启动前确认端口空闲,示例逻辑:
# 检测3000端口占用
PORT_OCCUPY_PID=$(lsof -t -i:3000)
if [ -n "$PORT_OCCUPY_PID" ]; then
  kill -9 $PORT_OCCUPY_PID
  # 等待2秒确认端口释放
  sleep 2
fi
# 后续再执行npm start启动应用

注意:端口检测杀进程逻辑必须配合守护进程停用操作使用,否则杀掉的子进程会被守护进程立刻拉起,依然会触发端口占用报错

第三步:验证修复

  • 手动在EC2实例上执行ss -tulpn | grep 3000,确认无进程占用3000端口
  • 重新触发CodeDeploy部署,查看部署日志,确认应用正常启动,无EADDRINUSE报错即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 07:03:17