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

GitHub Action执行结束后PM2启动的应用自动停止问题排查

问题描述

我编写了deploy.sh脚本,将其作为.github/deploy.yml工作流中的一个执行步骤。

以下是yaml文件中执行该shell脚本的配置片段:

- name: Execute script
     uses: appleboy/ssh-action@master
     with: 
       host: ${{ secrets.HOST_DNS }}
       username: ${{ secrets.USERNAME }}
       key: ${{ secrets.EC2_SSH_KEY }}
       script: |
         cd server/
         chmod 755 deploy.sh
         ./deploy.sh

对应的shell脚本内容如下:

echo "Kill pm2"
sudo pm2 kill


echo "Install app dependencies"
sudo rm -rf node_modules package-lock.json
sudo npm run get

echo "Start app with pm2"
sudo pm2 start index.js -i max
sudo pm2 list

在GitHub Action的日志中,可以清晰看到PM2已成功启动我的应用:

out: [PM2] Spawning PM2 daemon with pm2_home=/root/.pm2
out: [PM2] PM2 Successfully daemonized
out: [PM2] Starting /home/***/server/index.js in cluster_mode (0 instance)
out: [PM2] Done.
out: ┌─────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
out: │ id  │ name     │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
out: ├─────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
out: │ 0   │ index    │ default     │ 1.0.1   │ cluster │ 4807     │ 0s     │ 0    │ online    │ 0%       │ 35.1mb   │ root     │ disabled │
out: └─────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
out: ┌─────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
out: │ id  │ name     │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
out: ├─────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
out: │ 0   │ index    │ default     │ 1.0.1   │ cluster │ 4807     │ 0s     │ 0    │ online    │ 0%       │ 52.2mb   │ root     │ disabled │
out: └─────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
==============================================
✅ Successfully executed commands to all host.
==============================================

但工作流执行完成后,我通过SSH登录服务器执行pm2 list命令,却看不到任何运行中的PM2进程。

问题原因

这是appleboy/ssh-action的默认行为导致的:该Action执行远程命令时,会在SSH会话结束后主动杀掉该会话启动的所有关联子进程,你在脚本里用sudo启动的PM2进程属于当前SSH会话的子进程,会话断开就会被直接清理,所以Action日志里能看到启动成功,等手动登上去的时候进程已经被杀掉了。
另外还有一个容易忽略的权限问题:如果你手动SSH登录用的是非root用户,直接执行pm2 list查看的是当前普通用户的PM2实例列表,而你脚本里用sudo启动的是root用户的PM2实例,就算进程没被杀,不加sudo执行pm2 list也看不到root启动的进程。

解决方法
  • 给SSH Action加参数,禁用会话结束后杀关联子进程的行为,在with配置块里加一行kill_ssh_agent: false即可。
  • 固定PM2的运行用户,不要随意切换sudo:要么全程用同一个普通用户部署、启动PM2,所有命令都不加sudo;如果必须用root启动,手动登录查看的时候也要执行sudo pm2 list才能看到对应进程。
  • 更稳妥的做法是配置PM2持久化,第一次部署时执行sudo pm2 startup生成开机自启配置,每次启动应用后执行sudo pm2 save保存进程列表,就算服务器重启PM2也会自动拉起应用,不会因为SSH会话断开丢失进程。

修改后的Workflow配置片段参考:

- name: Execute script
     uses: appleboy/ssh-action@master
     with: 
       host: ${{ secrets.HOST_DNS }}
       username: ${{ secrets.USERNAME }}
       key: ${{ secrets.EC2_SSH_KEY }}
       kill_ssh_agent: false # 新增该行禁用会话结束杀子进程逻辑
       script: |
         cd server/
         chmod 755 deploy.sh
         ./deploy.sh

配置持久化后的deploy.sh参考:

echo "Kill pm2"
sudo pm2 kill

echo "Install app dependencies"
sudo rm -rf node_modules package-lock.json
sudo npm run get

echo "Start app with pm2"
sudo pm2 start index.js -i max
sudo pm2 save # 新增该行保存当前PM2进程列表
sudo pm2 list

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 18:57:48