Azure + Nginx + Capistrano でRailsアプリのデプロイ

以下のWindows Azure公式ドキュメントにやり方があったので、ここを参考に進めていく。

http://azure.microsoft.com/en-us/documentation/articles/virtual-machines-ruby-deploy-capistrano-host-nginx-unicorn/azure.microsoft.com

(heroku使いてぇ...)

VMつくる

Azureで仮想マシンを作成します。この前やったのと同じ要領でつくった。

Windows Azure + Rails でサーバーを構築してみる - 珈琲駆動開発

自動でデプロイできるようにするには鍵認証でssh接続できる必要があるらしいので、以下を見ながら.pemファイルを作成して、それを使う。

Use SSH to connect to Linux virtual machines in Azure

またENDPOINTSではHTTPを追加します

ということでここまでのインストールしたものとかをもう一度インストールしなおす。。シェルスクリプトでやってしまうべし

ログインは以下でいけます。

# ssh -i  myPrivateKey.key -p <port> username@servicename.cloudapp.net

サーバーにもろもろインストール

sshVMに接続して作業

sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get -y install git build-essential libssl-dev curl nodejs nginx
git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
echo 'export RBENV_ROOT=~/.rbenv' >> ~/.bash_profile
echo 'export PATH="$RBENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
eval "$(rbenv init -)"
git clone git://github.com/sstephenson/ruby-build.git
cd ruby-build
sudo ./install.sh
~/.rbenv/bin/rbenv install 2.0.0-p451
~/.rbenv/bin/rbenv global 2.0.0-p451
gem install bundler
~/.rbenv/bin/rbenv rehash

rubyが入ってるか確認。

$ ruby -v
ruby 2.0.0p451 (2014-02-24 revision 45167) [x86_64-linux]

PostgreSQLインストール

PostgreSQLインストールします

$ sudo apt-get -y install postgresql postgresql-contrib libpq-dev

以下でPostgreSQLのユーザ名を登録。したらDBを作るのだけど、これはユーザ名と同じにする。らしい。これはcapistranoでデプロイするときのルールとのこと。

一行目でパスワードの設定が求められる。

$ sudo -u postgres createuser -D -A -P my_username
$ sudo -u postgres createdb -O my_username my_database

試しに接続してみる

$ psql -U my_username -W my_database

パスワードを入力して以下のように入力画面になればok

Password for user totz:
psql (9.1.15)
Type "help" for help.

totz=>

Nginxのテスト

nginxを起動。

$ sudo service nginx start

以下のように表示されればおけ!

Screenshot 2015-03-11 15.03.16.png

やったーー動いてるううう

今回初めてNginx使った(エンジンエックスと読む。なんか中2感あってかっこいい)。以下の記事が参考になる。

これから始める人のためのNginx(1):高速・軽量・高機能……Nginxの基礎知識 (1/2) - @IT

Raisアプリの修正

デプロイするため、Unicorn web server、PostgreSQLCapistranoに対応するようRailsアプリを修正していきます。

Capistranoの使い方は以下が一番詳しそう。勉強勉強

入門 Capistrano 3 ~ 全ての手作業を生まれる前に消し去りたい | GREE Engineers' Blog

  • Capistranoは2まではRailsのデプロイツールだったけど、3は汎用的なデプロイツールに変わっている。したがってデフォルトの状態ではRails用のデプロイタスクは特に含まれていない

まずGemfileに以下を追加します。

# Use Unicorn
gem 'unicorn'
# Use PostgreSQL
gem 'pg', group: :production

group :development do
  # Use Capistrano for deployment
  gem 'capistrano', '~> 3.1'
  gem 'capistrano-rails', '~> 1.1.1'
  gem 'capistrano-bundler'
  gem 'capistrano-rbenv', '~> 2.0'
  gem 'capistrano-unicorn-nginx', '~> 2.0'
  gem 'capistrano-postgresql', '~> 3.0'
end

インストール

$ bundle 

ここでCapistranoとは。以下の記事を参考に。

ぱち ブログ

CapistranoRubyで記述されたデプロイメントツールで、SSH経由で複数のリモートマシン上で並列にコマンドを実行するためのフレームワークです。一般的には、git(github含む)やsubversion等といったSCM(Source Code Management)からソースコードアプリケーションサーバへデプロイしたり、アプリケーション関連ディレクトリの管理やデータベースの更新等を行うことが多いと思います。

あとこことか

特集 DevOps時代の必須知識:まとめてたくさん処理したい! を解決する「Capistrano」 - @IT

$ cap installで以下のようにファイルが作成されます

▶ bundle exec cap install
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
create Capfile
Capified

おもにconfigディレクトリ内のファイルがcapistranoのデプロイ設定ファイルで、さらにその中のdeploy/production.rbdeploy/staging.rbで詳しく設定できる。

ルートにあるCapfileの該当する場所(必要なもの)のコメントアウトを外す。

# Capfile

# require 'capistrano/rvm'
require 'capistrano/rbenv'
# require 'capistrano/chruby'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
# require 'capistrano/passenger'

さらに以下を追加。

require 'capistrano/unicorn_nginx'
require 'capistrano/postgresql'

そしてconfig/deploy.rbを以下のように変更

lock '3.1.0'
# application name and the github repository
set :application, 'YourApplicationName'
set :repo_url, 'git@github.com:YourGitHubName/YourRepoName.git'

# describe the rbenv environment we are deploying into
set :rbenv_type, :user
set :rbenv_ruby, '2.0.0-p451'
set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
set :rbenv_map_bins, %w{rake gem bundle ruby rails}

# dirs we want symlinked to the shared folder
# during deployment
set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}

namespace :deploy do

  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      # Your restart mechanism here, for example:
      # execute :touch, release_path.join('tmp/restart.txt')
      #
      # The capistrano-unicorn-nginx gem handles all this
      # for this example
    end
  end

  after :publishing, :restart

  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
      # Here we can do anything such as:
      # within release_path do
      #   execute :rake, 'cache:clear'
      # end
    end
  end

end

そして次はconfig/deploy/production.rbを以下のように変更

# production deployment
set :stage, :production
# use the master branch of the repository
set :branch, "master"
# the user login on the remote server
# used to connect and deploy
set :deploy_user, "YourAzureVMUserName"
# the 'full name' of the application
set :full_app_name, "#{fetch(:application)}_#{fetch(:stage)}"
# the server(s) to deploy to
server 'YourVM.cloudapp.net', user: 'YourAzureVMUserName', roles: %w{web app db}, primary: true
# the path to deploy to
set :deploy_to, "/home/#{fetch(:deploy_user)}/apps/#{fetch(:full_app_name)}"
# set to production for Rails
set :rails_env, :production

サーバー上デプロイ用の設定を書いてる

そしたらgitリポジトリの内容をコミットして更新しておく。

デプロイ

ついについにデプロイ...!!

以下で実行。

▶ bundle exec cap production setup

なんかエラー出た。

cap aborted!
SSHKit::Runner::ExecuteError: Exception while executing as totz@vm.cloudapp.net: Authentication failed for user totz@vm.cloudapp.net

Net::SSH::AuthenticationFailed: Authentication failed for user totz@vm.cloudapp.net

Tasks: TOP => rbenv:validate
(See full trace by running task with --trace)                                    4m ⚑  ⍉

ssh接続するためのkeyを指定できてないからかな。

config/deploy/production.rbssh_optionsをいじったらいけた。ローカルのkeyを指定して、パスワードをいれたら、setupは通るようになってサーバー側にconfigファイルとかが生成されたけど、今度はdeployでエラーがでた。

SSHKit::Runner::ExecuteError: Exception while executing as totz@bodabodavm.cloudapp.net: git exit status: 128
git stdout: Nothing written
git stderr: Warning: Permanently added 'github.com,192.30.252.129' (RSA) to the list of known hosts.
Permission denied (publickey).

git側と鍵認証がうまくできてないようだ。。

以下あたりを参考にしながらローカル側でagent_forwardの設定して、鍵を生成してgithubに登録した。

Use SSH agent forwarding to deploy via Capistrano : grits – the blenderbox blog

Using SSH Agent Forwarding | GitHub API

ちなみに agent_forwardとは

ホストマシンのssh-agentをログイン先のマシンからも参照できるsshの機能です。 これを利用することで、githubなどいろいろなところに登録されたホストマシンの公開鍵を、ローカルVMからも利用することができ、開発の際に捗ります。

ssh-agentのforwardを利用し、ホストマシンとローカルVMの非公開鍵を共有する - MANA-DOT

というものらしく。VMを使って開発するときとか便利!!

そしてこのあともう一度deployコマンド叩いてみて、もう少し進むようになったけど、今度はrbenvのcommandがみつからないとか、、

どうやらbashでうまくrbenvにパスが通ってなかったらしい。~/.bash_profileの設定をいちからやりなおしたらrbenvコマンドが叩けるようになったのでもういちどdeploy

今度は

DEBUG [3cc901e3]     rbenv: bundle: command not found

なんて言われた。ということで以下でbundlerをインストール。

$ gem install bundler

$ rake db:migratがうまくいっていなかったようなのでgithubcapistrano-postgresqlのREADMEをみてみると以下の記述が。

Be sure to remove config/database.yml from your application's version control.

capistrano-plugins/capistrano-postgresql · GitHub

なおらない。。

次はこちらの記事で。

さくらVPS Capistrano編 - プログラミングノート

サーバー上のdatabase.ymlのユーザ名とパスワードを修正。

migratingはいけた。。。!!!!

と思ったら次はnginxのエラー。エラーに続くエラーだよほんと。。

[67f25685]   Reloading nginx configuration:
DEBUG [67f25685]    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
DEBUG [67f25685]    nginx: [emerg] open() "/home/bodaapivm/apps/boda_api_production/shared/log/nginx.access.log" failed (2: No such file or directory)
DEBUG [67f25685]    nginx: configuration file /etc/nginx/nginx.conf test failed

となってしまった。明らかに/homeの下のユーザのとこがおかしい。最初に書き間違えてたのがダメだったのか。

Reloading nginx configurationのタスクは以下の部分っぽい。

capistrano-unicorn-nginx/nginx.rake at master · capistrano-plugins/capistrano-unicorn-nginx · GitHub

ここのnginx_service_pathというのが怪しそう。。

いい方法が思いつかなかったのでVMをもう一度作り直した。(AzureはOSの再インストール的なのできないのかなー)

すると、、、デプロイできたー!!

けど画面には何も表示されない。とりあえず$ rake routesでルーティングができているか確認してみると以下のようなメッセージが

ActiveRecord::AdapterNotSpecified: 'development' database is not configured. Available: ["production"]

ググったらここがでた。

ruby - ActiveRecord::AdapterNotSpecified database configuration does not specify adapter - Stack Overflow

参考にして、shared/config/database.ymlの情報を書き換える。ここがなんかAzureのdashboardで設定していたものと違っていた。

Railsのデプロイでハマった点まとめ - そのねこが学ぶとき

Qoosky - Rails4のデプロイでCapistrano3の基本的な使い方を把握する

ローカルのconfig/database.ymlは管理対象から外して、リモートではshared/以下の設定ファイルを用いる。

この2つのフォルダをcurrent配下にシンボリックリンクすることにより、currentが実際のアプリ配置場所として機能する。

と思ったらリフレッシュしても今度は画面が真っ白。ググったら以下の記事が参考になりました。

Rails が production 環境で真っ白、SECRET_KEY_BASE 設定忘れが原因でした | EasyRamble

tailsコマンドなんてのがあるんだなー。-fオプションはファイルの内容を常に監視し,表示を更新するもの。このコマンドすごく便利です。

unicornのreloadできなかったのでぐぐってみると以下の記事が。

ruby on rails 3 - Unicorn with Foreman - Socket Already Used Error - Stack Overflow

コメントアウトしてもうまくいかない。とりあえずローカルのconfig/deploy/production.rbに以下を加えてunicornのreloadのタスクをcapistranoのタスクから外す。

Rake::Task["unicorn:restart"].clear_actions

どうやらunicornを再起動するときにプロセスをkillできてない(ID間違えっぽい?)みたいなのでsshでサーバにログインしてprocess idがあっているか確認してみる。

以下でunicorn関連のプロセスを確認する。

$ ps aux | grep unicorn

killするprocess idはshared/tmp/pids/unicorn.pidによって決められているみたいなので、これをさっっき確認した走ってるprocess idに書き換える。

(でもこのprocess idはどういう基準で決められるんだろう...)

すると、動いたのは動いたけどリフレッシュすると2回に1回500 Internal server errorが返ってくる...。

なんかさっきの段階でゾンビなプロセスがたくさん走ってたようなので一回全部手動でkillしてもういちどunicornをloadしたら正常に動くようになった。

やっとやっと動きました...!!!!

ここまでなんか1週間弱かかった。なんなんだほんと...笑

とりあえずAzureとかnginxとかCapistranoを使って一通りRailsのデプロイを体験できたので、まぁよかったかなと。この苦しい期間でいろいろ学んだこともあったし。。。笑

勉強がんばろ!もっともっとコード書こう!!