部署 Ubuntu Server + nginx + unicorn tcp socket 方式如何设置运行多个 app

phpnew · 2013年05月11日 · 最后由 hiveer 回复于 2014年04月04日 · 8849 次阅读

疑问一 tcp socket 和 unix socket 差别 的问题

我抄配置用 unix socket 失败 改用 tcp socket 却成功,不知道原因是什么 虽然这样搞定一个 app,但是第二个 app 就没招了

vim /home/rails/hellworld/config/unicorn.rb

module Rails
  class <<self
    def root
      File.expand_path("../..", __FILE__)
    end
  end
end
puts Rails.root
rails_env = ENV["RAILS_ENV"] || "production"

preload_app true
working_directory Rails.root
pid "#{Rails.root}/tmp/pids/unicorn.pid"
stderr_path "#{Rails.root}/log/unicorn.log"
stdout_path "#{Rails.root}/log/unicorn.log"

listen 5000, :tcp_nopush => false   # 

listen "/tmp/unicorn.ruby-china.sock"
worker_processes 6
timeout 120

if GC.respond_to?(:copy_on_write_friendly=)
  GC.copy_on_write_friendly = true
end

before_exec do |server|
  ENV["BUNDLE_GEMFILE"] = "#{Rails.root}/Gemfile"
end

before_fork do |server, worker|
  old_pid = "#{Rails.root}/tmp/pids/unicorn.pid.oldbin"
  if File.exists?(old_pid) && server.pid != old_pid
    begin
      Process.kill("QUIT", File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
      puts "Send 'QUIT' signal to unicorn error!"
    end
  end
end

listen 5000, :tcp_nopush => false # 这个 listen 5000 是咋回事,我看不少 listen 3000,随意指定一个不冲突端口都可以吧 我测试 5001 5002 都可以

我 tmp 下创建了 listen "/tmp/unicorn.ruby-china.sock" chown www:wwww 也 chmod 777 了 nginx 也

upstream unicorn_server {
       server unix:/tmp/unicorn.ruby-china.sock fail_timeout=0;
    }
/usr/local/rvm/gems/ruby-1.9.3-p374/gems/unicorn-4.6.2/lib/unicorn/socket_helper.rb:134:in `bind_listen': socket=/tmp/ruby-china.sock specified but it is not a socket! (ArgumentError)
```ruby

后来我想起了tcp socket 
```ruby
listen "/tmp/unicorn.ruby-china.sock" 替换为 listen '127.0.0.1:8080'

nginx.conf 更改 upstream

upstream unicorn_app1{
       server 127.0.0.1:8080 fail_timeout=0;
    }

然后 RAILS_ENV=production bundle exec unicorn_rails -c config/unicorn.rb -E production -D 第一 app 正常了 问题是 我不知道为咋 unix socket 不行,tcp socket 却可以,发生了什么问题??? 是我 nginx 编译问题,还是我配置出问题?

问题 2 用 tcp socket 如何跑多个运用 直接复制 app1 的会变成访问两个域名,都跑到第一个运行的 app 上

我尝试修改第二 app2 unicorn.rb

listen 5077, :tcp_nopush => false #用不同端口,这个端口好像随便不冲突的都可以
listen '127.0.0.1:3000'  #换一个3000的

nginx.conf app2

upstream unicorn_app2{
       server 127.0.0.1:3000 fail_timeout=0;
    }

然后 RAILS_ENV=production bundle exec unicorn_rails -c config/unicorn.rb -E production -D

现在是第二个 app 正常访问,但是内容跑到第一个上面去 同时第一个 app 不正常了 “We're sorry, but something went wrong.”

问题就是 用 tcp socket 方式如何设置跑多个运用 一台服务器上,127.0.0.1 的除了换端口不知道用什么办法 求助

unix domain socket 会比 tcp socket 快,而且节约端口,不过小应用来讲,快的可以忽略不计

unicorn 里的 listen 就是监听指定端口,127.0.0.1:3000 表示只监听本机的 3000 端口,所以会拒绝来自其他主机的请求

socket 文件是由 unicorn 创建,而不是你手动创建,也就是说运行 unicorn 的进程应当对/tmp 有写权限,777 不是一个好习惯,生产环境要谨慎 unicorn 抛出异常,则是 unicorn 配置的问题,与 nginx 无关

不同的 app 应该配置不同的 upstream,然后在 server 节设置 listen 不同的端口,不过这时候你就需要通过http://ip:port方式访问网站,或者绑定到不同的域名上 或者用 virtual host 方式,这个你 google "virtual host nginx"就是了,大概就是在 domain 设置上有点 trick 同时配合一下域名那边的 a record

nginx 与 unicorn 配合的大概的原理是:外部请求进来,nginx 会匹配,然后把请求转发给对应的 upstream,这里就是 unicorn,然后 unicorn 承载的 rails app 处理请求之后返回结果给请求者,nginx 只是作为一个中间人存在,这也就是为啥管他叫反向代理的原因

至于出现 something went wrong,你需要检查 app 的日志,看是什么异常

小技巧,nginx 的配置语法有误,启动或重启 nginx 时会提示,bad gateway 说明 upstream 配置有误或者 unicorn 未启动,sth went wrong 说明 rails 程序写疵了,unicorn 抛出异常说明 unicorn 配置有误 定位好错误源第一反应去查对应的日志,根据日志的信息才好做出正确的解决方案

关于 nginx 的配置可以参考我的https://github.com/jasl/a_rails_start_up_omakase/tree/master/lib/generators/conf/templates unicorn https://github.com/jasl/a_rails_start_up_omakase/blob/master/config/unicorn/production.rb

非常感谢 @jasl 的指导 已搞定,确实是写瞎了,没有预编译 css 等

思路过程:

我已经邦在不同的二级域名上 app1.domain.com app2.domain.com kill 掉 unicorn_rails,分别单独分别独立运行访问,两个都是正常的,所以程序没有写瞎。 应该是 unicorn.rb 或者 nginx.conf 哪里写错了

nginx 那边每次都是正常的,没有错误提醒

/usr/local/webserver/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/webserver/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/webserver/nginx/conf/nginx.conf test is successful

然后

kill -HUP `cat /usr/local/webserver/nginx/logs/nginx.pid`

app 的 unicorn 的错误日志是说 当用 unix domain socket 错误提醒是 (两个 app 都运行不起来)

/usr/local/rvm/gems/ruby-1.9.3-p374/gems/unicorn-4.6.2/lib/unicorn/socket_helper.rb:134:in `bind_listen': socket=/tmp/ruby-china.sock specified but it is not a socket! (ArgumentError)

改用 tcp socket 的时候,能运行一个 app,谁先运行 unicorn 的谁就先能用,第二个运行似乎也正常了没出现提醒,但是

等等, 我重新对应一下

app1
uicorn.rb
listen 5001
listen 127.0.0.1:3000

app1.conf 那边

listen 127.0.0.1:3000

app2

uniorn.rb
listen 5002
listen 127.0.0.1:3002
app2.conf那边
listen 127.0.0.1:3002

-t conf 正常,kill 重启 nginx app1 正常 app2 sth wrong

查看 production.log 发现 不好意思,果然是写瞎了! 开发环境和生产环境的切换没注意到, 看 production.log 发现是没有预编译

bundle exec rake assets:precompile
/usr/local/rvm/rubies/ruby-1.9.3-p374/bin/ruby /usr/local/rvm/gems/ruby-1.9.3-p374/bin/rake assets:precompile:all RAILS_ENV=production RAILS_GROUPS=assets

ps:没搞懂为咋当初单独的时候可以,可能是我中间过程端口改来改去的,导致端口对应错了

非常感谢 @jasl 的指导,问题已解决

@phpnew 你好,我现在遇到一个问题,tcpsocket,Unicorn 没有监听设置的端口,导致 nginx 没法访问 配置

  upstream app_server {
    # fail_timeout=0 means we always retry an upstream even if it failed
    # to return a good HTTP response (in case the Unicorn master nukes a
    # single worker for timing out).

    # for UNIX domain socket setups:
    #server unix:/path/to/.unicorn.sock fail_timeout=0;    

    # for TCP setups, point these to your backend servers
    # server 192.168.0.7:8080 fail_timeout=0;
    # server 192.168.0.8:8080 fail_timeout=0;    
    server 192.168.1.4:8080 fail_timeout=0;
  }

#listen "/tmp/#{application}.sock", :backlog => 256
listen "127.0.0.1:8080"

你看配置有问题吗

需要 登录 后方可回复, 如果你还没有账号请 注册新账号