Chef脚本资源用户上下文差异:nginx用户装pm2-logrotate报错原因
这两种写法的核心差异在于环境变量的继承与设置,尤其是HOME和PM2依赖的配置路径,咱们一步步拆解:
先理清前置背景
你先以root全局安装了pm2,然后通过pm2 startup -u nginx --hp /home/nginx systemd配置了systemd服务,让pm2以nginx用户运行。但pm2本身的行为是默认读取当前用户HOME目录下的.pm2文件夹作为配置/模块存储路径,这是关键。
两种执行方式的差异分析
1. 使用su nginx -c "pm2 install..."(成功的写法)
当root用户执行su nginx -c时,系统会切换到nginx用户的上下文,自动将HOME环境变量设置为/home/nginx。此时pm2启动后,会识别到这个HOME路径,自动使用/home/nginx/.pm2作为配置目录,安装pm2-logrotate时会在该目录下创建modules文件夹——nginx用户对自己的家目录有完全权限,所以安装顺利。
2. 使用Chef script指定user为nginx(失败的写法)
Chef的script资源在切换到指定用户时,不会自动初始化完整的用户登录环境,很多环境变量(包括HOME)依然保留着root用户的配置(也就是/root)。这就导致pm2误以为要使用/root/.pm2作为配置目录,但此时运行用户是nginx,没有权限写入root的家目录,于是抛出EACCES: permission denied错误。
你可以做个简单测试验证:在失败的script里加入echo $HOME,会输出/root,而不是/home/nginx。
修复方案
针对Chef script的写法,只需要手动指定PM2的配置目录即可,有两种方式:
方式一:手动设置PM2_HOME环境变量
直接在code块里导出PM2_HOME,指向nginx的.pm2目录:
script "pm2_logrotate" do interpreter 'bash' user "nginx" code <<-EOH export PM2_HOME="/home/nginx/.pm2" pm2 install pm2-logrotate@2.4.0 EOH end
方式二:模拟完整登录环境
如果想让nginx用户加载完整的登录环境,可以用su - nginx -c(注意-参数,代表模拟登录),不过这种写法和你最初的成功写法类似,适合在需要更多环境变量的场景下使用:
script "pm2_logrotate" do interpreter 'bash' code <<-EOH su - nginx -c "pm2 install pm2-logrotate@2.4.0" EOH end
总结
本质问题是Chef切换用户时未正确传递HOME环境变量,导致pm2找错了配置目录。只要让pm2指向nginx用户的.pm2目录,就能解决权限问题。
内容的提问来源于stack exchange,提问作者David

