我在 Ubuntu(Amazon EC2)上创建了一个 nginx/unicorn/capistrato 设置,主要遵循以下方法本指南。我想一切都设置好了,但是当我启动 Unicorn 时,我在日志中收到(很多)这个错误:
E, [2012-09-08T08:57:20.658092 #12356] ERROR -- : Operation not permitted (Errno::EPERM)
/home/deployer/apps/bridgekalenderen.no/shared/bundle/ruby/1.9.1/gems/unicorn-4.3.1/lib/unicorn/worker.rb:82:in `initgroups'
我看到它与用户的权限有关,但我就是搞不清楚我遗漏了什么。如果我使用 sudo(或者,实际上是 rvmsudo)启动服务器,服务器就会顺利启动。
用户具有 sudo 权限,我已多次修改应用程序的 chmod,因此那里的文件权限应该没问题。/tmp 中的 unicorn 套接字归 deployer 用户所有,因此这也不是什么问题。
有人知道该看哪儿吗?
更新:
经过一番挖掘,我发现它归结为一个Process.initgroups
引发 EPERM 的调用。我已经在 irb 中验证了这一点。我不明白是什么导致了错误。用户可以读取/etc/group
。
答案1
如果我理解正确的话,您正在尝试在非普通用户的情况下启动服务sudo
。这将不起作用,并会出现您收到的错误不允许操作在大多数情况下(如果不是全部)情况都是如此,因为任何服务都需要以下一项或多项才能完成其工作:
- 绑定/监听端口 < 1024。
- 正在读取非 root 无法读取的文件。
- 正在写入非 root 无法写入的文件。
- 甚至可能更多(我不记得了)。
答案2
我终于搞明白了。问题在于部署者用户的主组是错误的。它应该是“staff”,但却是“deployer”。这意味着 unicorn 试图将新工作进程的所有权移交给它应该使用的组,但只有 root 才能做到这一点。
/etc/passwd
为了防止其他人需要知道,我通过如下编辑更改了主要组:
deployer:x:1002:50:,,,:/home/deployer:/bin/bash
'50' 是 'staff' 的 gid。它一开始是 1002。要获取 'staff' 组的 gid,请执行以下操作:
cat /etc/group | grep staff
它会说类似这样的话:
staff:x:50:<comma separated list of users in this group>
gid 是“x”后面的数字。
答案3
我遇到了同样的问题。最终对我有用的是在我的 unicorn 配置中的块中设置以下内容after_fork do |server, worker|
:(它来自 github unicorn 配置)
begin
uid, gid = Process.euid, Process.egid
user, group = 'deployer', 'staff'
target_uid = Etc.getpwnam(user).uid
target_gid = Etc.getgrnam(group).gid
worker.tmp.chown(target_uid, target_gid)
if uid != target_uid || gid != target_gid
Process.initgroups(user, target_gid)
Process::GID.change_privilege(target_gid)
Process::UID.change_privilege(target_uid)
end
rescue => e
if RAILS_ENV == 'development'
STDERR.puts "couldn't change user, oh well"
else
raise e
end
end
答案4
最近我为此损失了一天时间。上下文试图在名为 apps 的用户上运行 Unicorn,但 Errno::EPERM 错误一直困扰着我们。以下是堆栈跟踪:
E, [2018-04-12T20:45:07.277588 #2048] ERROR -- : Operation not permitted (Errno::EPERM)
/apps/cas-seas3/shared/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/worker.rb:143:in `initgroups'
/apps/cas-seas3/shared/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/worker.rb:143:in `user'
/apps/cas-seas3/shared/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/http_server.rb:657:in `init_worker_process'
/apps/cas-seas3/shared/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/http_server.rb:682:in `worker_loop'
/apps/cas-seas3/shared/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/http_server.rb:549:in `spawn_missing_workers'
/apps/cas-seas3/shared/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/http_server.rb:563:in `maintain_worker_count'
/apps/cas-seas3/shared/bundle/ruby/2.2.0/gems/unicorn-5.4.0/lib/unicorn/http_server.rb:293:in `join'
/apps/cas-seas3/shared/bundle/ruby/2.2.0/gems/unicorn-5.4.0/bin/unicorn:126:in `<top (required)>'
/apps/cas-seas3/shared/bundle/ruby/2.2.0/bin/unicorn:23:in `load'
/apps/cas-seas3/shared/bundle/ruby/2.2.0/bin/unicorn:23:in `<top (required)>'
在第 143 行左右使用打印语句对代码库进行检测,得到了以下调试信息:
user = apps
group=apps
uid=1040
gid=110
whoami=apps
Process.egid = 1001
gid 和 Process.egid 之间的差异导致此代码块失败:
if gid && Process.egid != gid
Process.initgroups(user, gid)
Process::GID.change_privilege(gid)
end
这就是导致失败的原因。
我最终将其归结为 GID / EGID 之间的差异,问题在于应用程序用户属于不同的主要组(管理员)。当我将应用程序用户移至应用程序组作为主要用户时,它就起作用了。这是通过编辑定义框的用户帐户的 /etc/passwd 文件来完成的。
另一种测试方法是使用 sg 手动运行具有正确组的 unicorn,使用 sg 命令如下:
bundle exec sg apps -c unicorn -c /apps/cas-seas3/current/config/unicorn.rb -E deployment -D
如果您发现它有效,那么这是一个非常好的信号,表明您需要查看您的用户/组设置。
Unicorn 似乎对用户/组设置非常敏感,会检查 /etc/passwd 和 /etc/group,还会使用此 ps 行检查执行 Unicorn 进程时的 UID 和 GID 差异:
ps -eo uid,gid,egid,args | grep unicorn
注意:上面的钩子后的独角兽对我来说不起作用。除了这个之外什么都不起作用。