Ubuntu Oneiric + nginx + uwsgi + sinatra (rack)

Ubuntu Oneiric (11.10) + nginx + uwsgi な環境で Sinatra アプリを uwsgi に載せるまで。

まず sinatra のインストールから。 apt で sinatra をインストールしたい場合、現在は ruby-rack がみつからず依存関係エラーが出る。

$ sudo -s
# apt-get install ruby-sinatra
[...]
以下のパッケージには満たせない依存関係があります:
 ruby-sinatra : 依存: ruby-rack しかし、インストールすることができません
E: 問題を解決することができません。壊れた変更禁止パッケージがあります。
# apt-get install ruby-rack
[...]
パッケージ ruby-rack はデータベースには存在しますが、利用できません。
おそらく、そのパッケージが見つからないか、もう古くなっているか、
あるいは別のソースからのみしか利用できないという状況が考えられます

E: パッケージ 'ruby-rack' にはインストール候補がありません

ubuntu-proposed リポジトリに対策済みパッケージがあるので、有効にしてから ruby-sinatra をインストール。

参考:Bug #843734 in ruby-sinatra (Ubuntu): “ruby-sinatra : Depends: ruby-rack but it is not installable”

# vi /etc/apt/sources.list
...
deb http://jp.archive.ubuntu.com/ubuntu/ oneiric-proposed main restricted universe multiverse
deb-src http://jp.archive.ubuntu.com/ubuntu/ oneiric-proposed main restricted universe multivers
...
# apt-get update
# apt-get install ruby-sinatra

Sinatra DSL の Hello World なファイルを作る。


参考:http://projects.unbit.it/uwsgi/wiki/Rack

$ mkdir -p ~/code/ruby/hellosinatra
$ vi ~code/ruby/hellosinatra/hello.rb
require 'rubygems'
require 'sinatra'

get '/hi' do
  "Hello World!"
end

上のファイルを呼ぶ Rack-up ファイル。

$ vi ~/code/ruby/hellosinatra/config.ru
require '/home/cu39/code/ruby/hellosinatra/hello.rb'

run Sinatra::Application

uwsgi を設定。 WSGI アプリは mount オプションを使って同じプロセスに複数のアプリをマウントできるが、 Rack アプリだと使えない(やろうとしてかなりの時間を浪費。 rackup ファイルで map すればいいじゃんということかも)。

参考:Mountpoints for Rack applications - uwsgi@lists.unbit.it

# vi /etc/uwsgi/apps-available/hellosinatra
[uwsgi]
plugins = rack
logto = /var/log/uwsgi/hellosinatra.log
chdir = /home/cu39/code/ruby/hellosinatra
# mountオプションだと動かない
#mount = /hi=/home/cu39/code/ruby/hellosinatra/config.ru
rack = /home/cu39/code/ruby/hellosinatra/config.ru
chmod-socket = 660
post-buffering = 4096
# /etc/init.d/uwsgi start hellosinatra

nginx を設定。 uwsgi_modifier1 7 が地味にポイントらしい。

参考:http://projects.unbit.it/uwsgi/wiki/RubyOnRails
参考:http://projects.unbit.it/uwsgi/wiki/Rack

# vi /etc/nginx/sites-available/default
server {
        listen 80;
        # Make site accessible from http://localhost/
        server_name localhost;

        location /hi {
                include uwsgi_params;
                uwsgi_param SCRIPT_NAME /hi;
                uwsgi_pass unix:///var/run/uwsgi/hellosinatra/socket;
                uwsgi_modifier1 7;
        }
}
# /etc/init.d/nginx restart

Sinatra::Base のサブクラスにしつつ Haml テンプレートを追加など。

参考:Rubyist Magazine - Sinatra 再入門、 Padrino / Rack / その先の何か

$ vi ~code/ruby/hellosinatra/hello.rb
require 'rubygems'
#require 'sinatra'
require 'sinatra/base'
require 'haml'

class Hello < Sinatra::Base
  enable :inline_templates

  get '/hi' do
    @title = "Top"
    haml "Hello World!"
  end

  get '/hi/name/:name' do
    @name = params[:name]
    @title = "Song for #{@name}"
    haml "#{@name}'s Way"
  end
end

__END__

@@ layout
!!! 5
%html
 %head
  %title= @title
 %body
  %h1= @title
  %div= yield
$ vi ~/code/ruby/hellosinatra/config.ru
require '/home/cu39/code/ruby/hellosinatra/hello.rb'

#run Sinatra::Application
run Hello

もうちょっと試してみる。

require 'rubygems'
require 'sinatra/base'
require 'sinatra/reloader'
require 'haml'

class Hello < Sinatra::Base
  enable :inline_templates
  register Sinatra::Reloader

  get '/hi' do
    @title = "Top"
    content = "Hi all!"
    haml :hi, :locals => { :content => content }
  end

  get '/hi/name/:name' do
    name = params[:name]
    @title = "Song for #{name}"
    haml :name, :locals => { :name => name }
  end

  get '/hi/style.css' do
    content_type 'text/css'
    scss :style
  end
end

__END__

@@ layout
!!! 5
%html
 %head
  %title= @title
  %link{:rel => 'stylesheet', :type => 'text/css', :href => '/hi/style.css', :media => 'screen'}
 %body
  = yield

@@ hi
#header
 %h1= @title
#content
 %p= content

@@ name
#header
 %h1= @title
#content
 #{name}'s Way

@@ style                                                                        
@mixin border($width: 1px) { border: $width solid #ccc }
div { @include border }

発展:Sthyo: How to Convert From Using Sinatra::Application to Using Sinatra::Base