CentOS下PM2托管Node.js服务重启后无法访问文件系统问题
我之前也碰到过类似的情况,咱们先拆解下你遇到的问题根源:
你看到的错误{"errno":-2,"code":"ENOENT","syscall":"open","path":"/run/user/0/drivelist-ecc75a..."},核心是要访问的路径不存在。这里的/run/user/0是root用户的用户会话临时目录——这个目录是系统在root用户登录时由systemd-logind自动创建的,一旦系统重启、用户注销,这个目录就会被销毁。
而你的PM2服务是通过pm2 startup设置成系统级服务的,它会在系统启动初期就运行,这时候root用户还没登录,/run/user/0自然还没被创建,所以你的Node.js服务调用fs模块访问这个路径时就会触发500错误。
下面给你几个实用的解决办法,你可以根据自己的需求选:
办法1:改用系统级临时目录(最推荐)
既然/run/user/0是依赖用户会话的不稳定目录,咱们直接换成系统全局的临时目录/tmp——这个目录系统一启动就存在,完全不受用户登录状态影响。
如果你的代码是自己指定了临时路径,直接把路径改成/tmp/xxx就行;如果是用了drivelist模块(从错误路径里的drivelist字样推测),可以通过环境变量指定临时目录:
pm2 start your-app.js --env TMPDIR=/tmp
这样Node.js的os.tmpdir()会返回/tmp,依赖临时目录的模块就会自动在/tmp下生成文件,不会再去碰/run/user/0了。
办法2:把PM2改成用户级服务(适合必须依赖用户会话的场景)
如果你的服务必须用到用户会话里的资源,那可以把PM2设置成root用户的用户级服务,这样只有当root用户登录后,PM2才会启动服务,此时/run/user/0已经存在了。
操作步骤:
- 先移除之前的系统级PM2服务:
pm2 unstartup systemd
- 切换到root用户,设置用户级启动:
pm2 startup systemd -u root --hp /root
不过要注意:这种方式下,如果root用户不登录,服务就不会启动,你得根据自己的需求权衡。
办法3:手动预创建/run/user/0目录
如果必须用系统级PM2服务,又离不开/run/user/0这个路径,那咱们可以在PM2启动前手动创建这个目录并设置正确权限。
操作步骤:
- 找到PM2的systemd服务文件,一般在
/etc/systemd/system/pm2-root.service - 编辑这个文件,在
ExecStart行的前面加上两行ExecStartPre指令:
ExecStartPre=/usr/bin/mkdir -p /run/user/0 ExecStartPre=/usr/bin/chmod 700 /run/user/0
- 重新加载systemd配置并重启PM2服务:
systemctl daemon-reload systemctl restart pm2-root
这样系统启动时,PM2服务启动前会先建好/run/user/0目录并设置好权限,服务就能正常访问这个路径了。
总的来说,第一种办法是最稳妥的,毕竟系统级临时目录的稳定性更高,不用依赖用户登录状态。
内容的提问来源于stack exchange,提问作者Mahmood Kohansal

