当前位置: 首页 > 工具软件 > Sinatra > 使用案例 >

使用Nginx+Unicorn+Capistrano+Sinatra搭建Ruby Web应用

云凌
2023-12-01

记录一下使用如下工具搭建一个简单的Ruby Web应用的过程:

工具集:

步骤:

  1. 使用Sinatra提供的DSL编写一个能够运行的最小化web应用:

    # Gemfile
    source 'http://ruby.taobao.org/'
    gem 'sinatra'
    

    # app.rb
    require 'sinatra'
    
    get '/' do
      'Hello world'
    end
    

    使用bundle exec ruby app.rb检验应用是否能正常运行:

    twer@app$ bundle exec ruby app.rb
    [2014-02-06 03:06:59] INFO  WEBrick 1.3.1
    [2014-02-06 03:06:59] INFO  ruby 1.9.3 (2013-11-22) [x86_64-darwin13.0.0]
    == Sinatra/1.4.4 has taken the stage on 4567 for development with backup from WEBrick
    [2014-02-06 03:06:59] INFO  WEBrick::HTTPServer#start: pid=62687 port=4567
    

    访问http://localhost:4567应该能得到’Hello world’的响应

  2. 现在将其整理为Rack-based app:

    # app.rb
    require 'sinatra'
    
    class App < Sinatra::Base
      get '/' do
        'Hello world'
      end
    end
    

    # config.ru
    root = ::File.dirname(__FILE__)
    require ::File.join(root, 'app')
    
    run App
    

    使用rackup -p1818检验应用是否能正常运行:

    twer@app$ rackup -p1818
    Thin web server (v1.6.1 codename Death Proof)
    Maximum connections set to 1024
    Listening on 0.0.0.0:1818, CTRL+C to stop
    

    访问http://localhost:1818应该能得到’Hello world’的响应

  3. 引入unicorn和capistrano配置:

    # Gemfile
    source 'http://ruby.taobao.org/'
    gem 'sinatra'
    gem 'unicorn'
    gem 'capistrano', '~> 2.15.5'
    gem 'rvm-capistrano'
    

    使用bundle install安装相应的gem包后,运行capify .生成部署所需的配置文件:

    twer@app$ capify .
    [add] writing './Capfile'
    [add] making directory './config'
    [add] writing './config/deploy.rb'
    [done] capified!
    

    配置config/deploy.rb,注意git仓库地址的配置,以及阿里云服务器ip地址及用户名的配置:

    # config/deploy.rb
    require 'rvm/capistrano'
    set :rvm_ruby_string, '1.9.3'
    set :rvm_type, :system
    
    # Bundler tasks
    require 'bundler/capistrano'
    
    # Your application name
    set :application, 'my-ruby-web-demo'
    
    # Input your git repository address
    set :repository,  'git@github.com:tongzh/my-ruby-web-demo.git'
    
    set :scm, :git
    
    # do not use sudo
    set :use_sudo, false
    set(:run_method) { use_sudo ? :sudo : :run }
    
    # This is needed to correctly handle sudo password prompt
    default_run_options[:pty] = true
    
    # Input your username to login remote server address
    set :user, 'root'
    set :group, user
    set :runner, user
    
    # Input your server address
    set :host, "#{user}@115.28.137.21"
    role :web, host
    role :app, host
    
    set :rails_env, :production
    
    # Where will it be located on a server?
    set :deploy_to, "/srv/#{application}"
    set :unicorn_conf, "#{deploy_to}/current/config/unicorn.rb"
    set :unicorn_pid, "#{deploy_to}/shared/pids/unicorn.pid"
    
    # Unicorn control tasks
    namespace :deploy do
      task :restart do
        run "if [ -f #{unicorn_pid} ]; then kill -USR2 `cat #{unicorn_pid}`; else cd #{deploy_to}/current && bundle exec unicorn -c #{unicorn_conf} -E #{rails_env} -D; fi"
      end
      task :start do
        run "cd #{deploy_to}/current && bundle exec unicorn -c #{unicorn_conf} -E #{rails_env} -D"
      end
      task :stop do
        run "if [ -f #{unicorn_pid} ]; then kill -QUIT `cat #{unicorn_pid}`; fi"
      end
    end
    

    新建config/unicorn.rb文件,对unicorn进行配置:

    # config/unicorn.rb
    deploy_to = '/srv/my-ruby-web-demo'
    rails_root = "#{deploy_to}/current"
    pid_file = "#{deploy_to}/shared/pids/unicorn.pid"
    socket_file= "#{deploy_to}/shared/unicorn.sock"
    log_file = "#{rails_root}/log/unicorn.log"
    err_log = "#{rails_root}/log/unicorn_error.log"
    old_pid = pid_file + '.oldbin'
    
    timeout 30
    worker_processes 2 # increase or decrease
    listen socket_file, :backlog => 1024
    
    pid pid_file
    stderr_path err_log
    stdout_path log_file
    
    # make forks faster
    preload_app true
    
    # make sure that Bundler finds the Gemfile
    before_exec do |server|
      ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__))
    end
    
    before_fork do |server, worker|
      defined?(ActiveRecord::Base) and
        ActiveRecord::Base.connection.disconnect!
    
      # zero downtime deploy magic:
      # if unicorn is already running, ask it to start a new process and quit.
      if File.exists?(old_pid) && server.pid != old_pid
        begin
          Process.kill("QUIT", File.read(old_pid).to_i)
        rescue Errno::ENOENT, Errno::ESRCH
          # someone else did our job for us
        end
      end
    end
    
    after_fork do |server, worker|
    
      # re-establish activerecord connections.
      defined?(ActiveRecord::Base) and
        ActiveRecord::Base.establish_connection
    end
    

    然后push代码到git仓库。

  4. 在正式进行部署前,ssh登录到远程主机上依次安装所需的软件环境:
  5. 依次使用cap deploy:setupcap deploy命令进行部署:

    twer@app<master>$ cap deploy:setup
        triggering load callbacks
      * 2014-02-06 21:13:12 executing `deploy:setup'
      * executing "mkdir -p /srv/my-ruby-web-demo /srv/my-ruby-web-demo/releases /srv/my-ruby-web-demo/shared /srv/my-ruby-web-demo/shared/system /srv/my-ruby-web-demo/shared/log /srv/my-ruby-web-demo/shared/pids"
        servers: ["115.28.137.21"]
    Password: 
        [root@115.28.137.21] executing command
        command finished in 647ms
      * executing "chmod g+w /srv/my-ruby-web-demo /srv/my-ruby-web-demo/releases /srv/my-ruby-web-demo/shared /srv/my-ruby-web-demo/shared/system /srv/my-ruby-web-demo/shared/log /srv/my-ruby-web-demo/shared/pids"
        servers: ["115.28.137.21"]
        [root@115.28.137.21] executing command
        command finished in 644ms
    

    twer@app<master>$ cap deploy
        triggering load callbacks
      * 2014-02-06 21:20:06 executing `deploy'
      * 2014-02-06 21:20:06 executing `deploy:update'
     ** transaction: start
      * 2014-02-06 21:20:06 executing `deploy:update_code'
        executing locally: "git ls-remote git@github.com:tongzh/my-ruby-web-demo.git HEAD"
        command finished in 7722ms
      * executing "git clone -q git@github.com:tongzh/my-ruby-web-demo.git /srv/my-ruby-web-demo/releases/20140206102014 && cd /srv/my-ruby-web-demo/releases/20140206102014 && git checkout -q -b deploy 0de5794f2d7e13af76e671df6a7796c676e88e2b && (echo 0de5794f2d7e13af76e671df6a7796c676e88e2b > /srv/my-ruby-web-demo/releases/20140206102014/REVISION)"
        servers: ["115.28.137.21"]
    Password: 
        [root@115.28.137.21] executing command
        command finished in 4891ms
      * 2014-02-06 21:20:25 executing `deploy:finalize_update'
        triggering before callbacks for `deploy:finalize_update'
      * 2014-02-06 21:20:25 executing `bundle:install'
      * executing "cd /srv/my-ruby-web-demo/releases/20140206102014 && bundle install --gemfile /srv/my-ruby-web-demo/releases/20140206102014/Gemfile --path /srv/my-ruby-web-demo/shared/bundle --deployment --quiet --without development test"
        servers: ["115.28.137.21"]
        [root@115.28.137.21] executing command
        command finished in 45056ms
      * executing "chmod -R -- g+w /srv/my-ruby-web-demo/releases/20140206102014 && rm -rf -- /srv/my-ruby-web-demo/releases/20140206102014/public/system && mkdir -p -- /srv/my-ruby-web-demo/releases/20140206102014/public/ && ln -s -- /srv/my-ruby-web-demo/shared/system /srv/my-ruby-web-demo/releases/20140206102014/public/system && rm -rf -- /srv/my-ruby-web-demo/releases/20140206102014/log && ln -s -- /srv/my-ruby-web-demo/shared/log /srv/my-ruby-web-demo/releases/20140206102014/log && rm -rf -- /srv/my-ruby-web-demo/releases/20140206102014/tmp/pids && mkdir -p -- /srv/my-ruby-web-demo/releases/20140206102014/tmp/ && ln -s -- /srv/my-ruby-web-demo/shared/pids /srv/my-ruby-web-demo/releases/20140206102014/tmp/pids"
        servers: ["115.28.137.21"]
        [root@115.28.137.21] executing command
        command finished in 692ms
      * executing "find /srv/my-ruby-web-demo/releases/20140206102014/public/images /srv/my-ruby-web-demo/releases/20140206102014/public/stylesheets /srv/my-ruby-web-demo/releases/20140206102014/public/javascripts -exec touch -t 201402061021.11 -- {} ';'; true"
        servers: ["115.28.137.21"]
        [root@115.28.137.21] executing command
     ** [out :: root@115.28.137.21] find: `/srv/my-ruby-web-demo/releases/20140206102014/public/images': No such file or directory
     ** [out :: root@115.28.137.21] find: `/srv/my-ruby-web-demo/releases/20140206102014/public/stylesheets': No such file or directory
     ** [out :: root@115.28.137.21] find: `/srv/my-ruby-web-demo/releases/20140206102014/public/javascripts': No such file or directory
        command finished in 655ms
      * 2014-02-06 21:21:12 executing `deploy:create_symlink'
      * executing "rm -f /srv/my-ruby-web-demo/current &&  ln -s /srv/my-ruby-web-demo/releases/20140206102014 /srv/my-ruby-web-demo/current"
        servers: ["115.28.137.21"]
        [root@115.28.137.21] executing command
        command finished in 702ms
     ** transaction: commit
      * 2014-02-06 21:21:12 executing `deploy:restart'
      * executing "if [ -f /srv/my-ruby-web-demo/shared/pids/unicorn.pid ]; then kill -USR2 `cat /srv/my-ruby-web-demo/shared/pids/unicorn.pid`; else cd /srv/my-ruby-web-demo/current && bundle exec unicorn -c /srv/my-ruby-web-demo/current/config/unicorn.rb -E production -D; fi"
        servers: ["115.28.137.21"]
        [root@115.28.137.21] executing command
        command finished in 1633ms
    

    确保以上操作无异常输出,然后登录到远程主机上查看应用是否已正常装载到unicorn进程中:

    root@~$ ps aux | grep my-ruby-web-demo
    root     20071  0.0  7.3 218396 37016 ?        Sl   21:21   0:00 unicorn master -c /srv/my-ruby-web-demo/current/config/unicorn.rb -E production -D                                                 
    root     20074  0.0  7.2 218396 36476 ?        Sl   21:21   0:00 unicorn worker[0] -c /srv/my-ruby-web-demo/current/config/unicorn.rb -E production -D                                              
    root     20076  0.0  7.2 218396 36476 ?        Sl   21:21   0:00 unicorn worker[1] -c /srv/my-ruby-web-demo/current/config/unicorn.rb -E production -D                                              
    root     20141  0.0  0.1 103208   824 pts/1    S+   21:23   0:00 grep my-ruby-web-demo
    
  6. 在远程主机上安装nginx,并在nginx配置中增添一个反向代理配置,将请求分发给应用所在的unicorn进程:

    # /etc/nginx/default.conf
    upstream my-ruby-web-demo-unicorn {
        server unix:/srv/my-ruby-web-demo/shared/unicorn.sock fail_timeout=0;
    }
    
    server {
        listen       80;
        server_name  localhost;
    
        root /srv/my-ruby-web-demo/current/public;
    
        location / {
            try_files $uri @net;
        }
    
        location @net {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_pass http://my-ruby-web-demo-unicorn;
        }
    
        error_page  404              /404.html;
    
        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    }
    

    在远程主机上重启nginx:service nginx restart,之后通过远程主机的ip就可以访问到所部署的应用程序的’Hello world’响应了。

参考:

 类似资料: