Déploiement de Rails sur VPS avec Capistrano, Unicorn et RVM

Sur

cap deploy:cold 

ma recette de capistrano fonctionne très bien mais rest bloquée sur cette partie:

  * 2013-01-06 23:07:08 executing `deploy:start' * executing "/etc/init.d/seventysix_unicorn start" servers: ["xxxxxxxxxxxxx"] [xxxxxxxxxxxxx] executing command ** [out :: xxxxxxxxxxxxx] Password: 

Et attend ici pour toujours. En visitant la page Web, je peux voir que nginx fonctionne correctement, mais la licorne ne l’est pas. Même lorsque je lance la licorne manuellement en procédant comme suit:

 cd $APP_ROOT; bundle exec unicorn -c $APP_ROOT/config/unicorn.rb 

et recharger la page, la page semble traiter quelque chose (l’icône en forme de cercle indiquant la progression dans un navigateur tourne) mais après environ 30 secondes, elle s’arrête, me redirigeant vers la valeur par défaut de 500.html.

Voici mes configurations de déploiement.

nginx.conf

  1 upstream unicorn { 2 server unix:/tmp/unicorn.seventysix.sock fail_timeout=0; 3 } 4 5 server { 6 7 listen 80 default deferred; 8 server_name www.example.com example.com; 9 root /home/mr_deployer/apps/seventysix/current/public; 11 12 location ^~ /assets/ { 13 gzip_static on; 14 expires max; 15 add_header Cache-Control public; 16 } 17 18 try_files $uri/public $uri @unicorn; 19 20 location @unicorn { 21 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 22 proxy_set_header Host $http_host; 23 proxy_redirect off; 24 proxy_pass http://unicorn; 26 } 27 28 error_page 500 502 503 504 /500.html; 29 client_max_body_size 4G; 30 keepalive_timeout 10; 31 32 } 

licorne.rb

  1 root = "/home/mr_deployer/apps/seventysix/current" 3 4 working_directory root 5 pid "#{root}/tmp/pids/unicorn.pid" 6 stderr_path "#{root}/log/unicorn.log" 7 stdout_path "#{root}/log/unicorn.log" 8 9 listen "/tmp/unicorn.seventysix.sock" 10 worker_processes 2 11 timeout 30 

unicorn_init.sh

  1 #!/bin/sh 28 APP_ROOT=/home/mr_deployer/apps/seventysix/current 29 RAILS_ENV=production 32 USER=mr_deployer 33 34 PID=$APP_ROOT/tmp/pids/unicorn.pid 35 CMD="cd $APP_ROOT; bundle exec unicorn -c $APP_ROOT/config/unicorn.rb -E $RAILS_ENV -D" 38 39 action="$1" 40 set -u 41 42 old_pid="$PID.oldbin" 43 44 cd $APP_ROOT || exit 1 45 46 sig () { 47 test -s "$PID" && kill -$1 `cat $PID` 48 } 49 50 oldsig () { 51 test -s $old_pid && kill -$1 `cat $old_pid` 52 } 53 54 case $action in 55 56 start) 57 sig 0 && echo >&2 "Already running" && exit 0 58 su $USER -c "$CMD" 59 ;; 60 61 stop) 62 sig QUIT && exit 0 63 echo >&2 "Not running" 64 ;; 65 66 force-stop) 67 sig TERM && exit 0 68 echo >&2 "Not running" 69 ;; 70 71 restart|reload) 72 sig HUP && echo reloaded OK && exit 0 73 echo >&2 "Couldn't reload, starting '$CMD' instead" 74 su $USER -c "$CMD" 75 ;; 76 77 upgrade) 78 if sig USR2 && sleep 2 && sig 0 && oldsig QUIT 79 then 80 n=$TIMEOUT 81 while test -s $old_pid && test $n -ge 0 82 do 83 printf '.' && sleep 1 && n=$(( $n - 1 )) 84 done 85 echo 86 if test $n -lt 0 && test -s $old_pid 87 then 88 echo >&2 "$old_pid still exists after $TIMEOUT seconds" 89 exit 1 90 fi 91 exit 0 92 fi 93 echo >&2 "Couldn't upgrade, starting '$CMD' instead" 94 su $USER -c "$CMD" 95 ;; 96 reopen-logs) 97 sig USR1 98 ;; 99 100 *) 101 102 echo >&2 "Usage: $0 " 103 exit 1 104 ;; 105 esac 

deploy.rb

  1 require "bundler/capistrano" 2 3 set :rvm_ruby_ssortingng, '1.9.3-p125@seventysix' 4 5 require "rvm/capistrano" # Load RVM's capistrano plugin. 6 7 server "176.58.126.11", :web, :app, :db, primary: true 8 9 set :application, "seventysix" 10 set :user, "mr_deployer" 11 set :deploy_to, "/home/#{user}/apps/#{application}" 12 set :deploy_via, :remote_cache 13 set :use_sudo, false 14 15 set :scm, "git" 16 set :repository, "[email protected]:ofcan/#{application}.git" 17 set :branch, "master" 18 19 default_run_options[:pty] = true 20 ssh_options[:forward_agent] = true 21 22 after "deploy", "deploy:cleanup" # keep only the last 5 releases 23 24 namespace :deploy do 25 26 %w[start stop restart].each do |command| 27 desc "#{command} unicorn server" 28 task command, roles: :app, except: {no_release: true} do 29 run "/etc/init.d/#{application}_unicorn #{command}" 30 end 31 end 32 33 task :setup_config, roles: :app do 34 sudo "ln -nfs #{current_path}/config/nginx.conf /etc/nginx/sites-enabled/#{application}" 35 sudo "ln -nfs #{current_path}/config/unicorn_init.sh /etc/init.d/#{application}_unicorn" 36 run "mkdir -p #{shared_path}/config" 37 put File.read("config/database.example.yml"), "#{shared_path}/config/database.yml" 38 puts "Now edit the config files in #{shared_path}." 39 end 40 41 after "deploy:setup", "deploy:setup_config" 42 43 task :symlink_config, roles: :app do 44 run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml" 45 end 46 47 after "deploy:finalize_update", "deploy:symlink_config" 48 desc "Make sure local git is in sync with remote." 49 task :check_revision, roles: :web do 50 unless `git rev-parse HEAD` == `git rev-parse github/master` 51 puts "WARNING: HEAD is not the same as github/master" 52 puts "Run `git push` to sync changes." 53 exit 54 end 55 end 56 57 before "deploy", "deploy:check_revision" 58 59 end 

J’utilise aussi RVM. Je sais que les documents RVM suggèrent de créer un wrapper pour la licorne, mais je ne peux pas comprendre comment le créer. Aussi, pourquoi Unicorn, lorsqu’il a été démarré manuellement sur VPS avec cette commande, je l’ai dit plus tôt, le délai?

Je pense que votre commande de démarrage de licorne s’exécute en tant que sudo et nécessite un mot de passe (le mot de passe sudoless n’est pas configuré).

Je me base sur l’hypothèse que le rest de votre script capistrano s’est exécuté correctement et qu’il s’est connecté au serveur distant (ce n’est donc pas SSH qui demande une connexion interactive).

et recharger la page, la page semble traiter quelque chose (l’icône en forme de cercle indiquant la progression dans un navigateur tourne) mais après environ 30 secondes, elle s’arrête, me redirigeant vers la valeur par défaut de 500.html.

Il s’agit de nginx qui tente de se connecter au serveur en aval (unicorn) et qui expire après le délai d’attente par défaut (30 secondes) et renvoie un 500.

C’est étrange, car cela implique que le socket unix est actif (sinon nginx renverrait une mauvaise passerelle, pas une erreur du serveur), mais le socket ne répond pas.

J’ai eu un problème similaire cette semaine, avec Nginx 1.2.6.

Je vais tourner toutes les solutions qui ont pu résoudre ce problème, j’ai passé beaucoup de temps à le faire fonctionner. Commentez si quelque chose a fonctionné pour vous:

  1. J’ai supprimé gzip (l’ location ^~ /assets/ entier location ^~ /assets/ node). Je ne sais pas pourquoi cela n’a pas fonctionné, et je héberge des ressources sur S3, donc je m’en foutais beaucoup.

  2. Pour accéder à Unicorn depuis le script bash, vous avez deux options: avec bundle ou avec un exécutable démarré:

en utilisant Licorne avec bundle :

Vous devez faire confiance à RVM automatiquement dans votre APP_ROOT, en créant un fichier dans votre répertoire personnel: /home/mr_deployer/.rvmrc avec le contenu:

 export rvm_trust_rvmrcs_flag=1 

Ensuite, si vous ne l’avez pas encore, ajoutez le fichier .rvmrc à votre APP_ROOT avec

 rvm --create use "1.9.3-p125@seventysix" 

Et enfin changer le ; dans && :

 cd $APP_ROOT && bundle exec unicorn -c $APP_ROOT/config/unicorn.rb 

ou, en utilisant unicorn avec l’ exécutable rvm démarré :

Exécutez ceci sur votre serveur:

 rvm wrapper 1.9.3-p125@seventysix bootup unicorn 

Votre commande devrait alors ressembler à

  /home/mr_deployer/.rvm/bin/bootup_unicorn -c $APP_ROOT/config/unicorn.rb -E $RAILS_ENV -D 

Je devrais append que je suis en cours d’exécution service unicorn_blah de mon utilisateur de service unicorn_blah et cela fonctionne très bien. Pas de racine ou de sudo.