nginx+unicorn環境にrails4.xプロジェクトを作成する


rails4.xを使って新規プロジェクトを作成する際に、毎回行う定型作業が面倒なので、スクリプトベースで記載します。環境はnginx+unicornです。Apache用ではないので注意してください。

やっている事は下記の通り。環境固有のパラメータは一番最初に設定する環境変数に集約しておいたので、環境に合わせて内容は書き換えてください。

  1. プロジェクト名やMySQLのパスワードを環境変数にセットする
  2. MySQLのDB作成
  3. Railsプロジェクトの作成
  4. gitによるバージョン管理対象にする
  5. database.ymlにDB名、DBパスワードをセットする
  6. capistranoを入れる
  7. unicornの設定
  8. サービスの登録

大抵の場合には、railsアプリケーションを作成する場合には、rails serverコマンドで3000番ポートで起動させながらアプリケーションを作成すると思いますが、外部公開していないようなサーバだと、ちょこっと開発して、そのまま運用に載せてしまう場合もあるので、(先輩諸兄からは怒られそうですが)動かしながら適宜修正する為に、こんな感じでセットアップしてしまう事も有ります。自分用のオリジナルのスクリプトは全部1ファイルにまとまっていますが、BLOGへ載せるために、わざと大項目毎にタイトルをつけて載せています。

環境変数を設定する

# RAILSのバージョン指定。
# gemを使っているとRCとかが設定される事があるので、明示的に。
RAILS_VERSION=_4.1.8_

# MySQLのルートパスワード。DB作成時にのみ使用
MYSQL_ROOT_PASS=mysql_root_password

# アプリケーション名。ドメイン指定ではなく、testapp等が一般的かも
APPNAME=testapp.senritu.net

# 作成しようとしているアプリケーションでのみ使用するDBパスワードは
# opensslでランダムに作成する。
APP_DB_PASS=`openssl rand -hex 10`

# rails newするディレクトリ。
# /var/www/testapp.senritu.netを作成したい場合には、下記のように指定。
WEB_ROOT=/var/www

# ドットをアンダースコアに変更してDBNAME変数を設定
DBNAME=`echo $APPNAME | sed -e "s/\./_/g"`

# DBのユーザー名。あまり長いとエラーとなるので注意
DB_USER_NAME=`echo $APPNAME | sed -e "s/\..*//g"`

# 開発者のアカウント(単純にパーミッションつけるときに使う)
# $USERは、ログインしたユーザー名が入っている環境変数
EDIT_USER=$USER
WEB_ACCOUNT=www-data

DBをセットアップする。

# 同名のデータベースがあれば削除(間違って削除しないように注意!!!)
mysql -uroot -p$MYSQL_ROOT_PASS -e \
    "drop database if exists $DBNAME;"

# utf8でDB作成。テスト用DBは必要に応じて作成して
mysql -uroot -p$MYSQL_ROOT_PASS -e \
    "CREATE DATABASE $DBNAME character set utf8;"

# アクセス権を設定する
mysql -uroot -p$MYSQL_ROOT_PASS -e \
    "grant all privileges on $DBNAME.* to '$DB_USER_NAME'@'localhost' identified by '$APP_DB_PASS';"

# DBの再起動なしにアクセス権変更を有効にする
mysql -uroot -p$MYSQL_ROOT_PASS -e \
    "flush privileges;"

# 動作確認。作成したDBが出来ているか確認しているだけ
mysql -u$DB_USER_NAME -p$APP_DB_PASS -e \
    'show databases;'

Railsアプリケーションを作成してgitで管理できるようにする。

sudo rails $RAILS_VERSION new $APPNAME --database=mysql
sudo chown -R $EDIT_USER:$WEB_ACCOUNT $APPNAME
cd $WEB_ROOT/$APPNAME

# コミットしておく
git init
git add .
git commit -m 'first commit'

# DBの設定値を反映しておく
cd $WEB_ROOT/$APPNAME/config

sed -i "s/username.*/username: $DB_USER_NAME/g" ./database.yml
sed -i "s/password:$/password: $APP_DB_PASS/g" ./database.yml

# _developmentと_productionはそのままでも良いですし、
# 下記のコマンドを叩いて、両方とも同じDBを見ても良いと思います。
# ちなみに、同じDBを見ているのは、開発機と本番機が物理的に違うので、
# DB名が同じ方が覚えやすいと言う事情でそうしています。
sed -i "s/_development//g" ./database.yml
sed -i "s/_production//g" ./database.yml

# コミット
git commit -a -m 'database.yml is changed'

# secrets.xmlの更新
sed -i "s/secret_key_base: [0-9a-f]+/secret_key_base: `bundle exec rake secret`/1" ./secrets.yml
sed -i "s/secret_key_base: [0-9a-f]+/secret_key_base: `bundle exec rake secret`/2" ./secrets.yml

capistranoの初期セットアップをする。

capistranoは開発環境から本番環境へのデプロイを支援してくれるツールです。よって、『取りあえず動かしたい』場合には、ここに記載してある内容以上の設定は不要かと。デプロイ時の設定は環境毎に異なると思いますので、必要に応じて設定してください。

cd $WEB_ROOT/$APPNAME
gem install capistrano
source ~/.bash_profile

# rails関係のパッケージを本パッケージ内に配置する
bundle install
git add vendor/bundle
git commit -a -m 'bundle install --deployment'

# capistranoの初期セットアップ
cap install
git add Capfile config/deploy*
git commit -a -m 'capistrano first commit'

echo "gem 'unicorn'" >> Gemfile
bundle install

unicornの設定ファイルを用意する。

cat <<- __EOT__ >> $WEB_ROOT/$APPNAME/config/unicorn.rb
worker_processes 2
 
working_directory("$WEB_ROOT/$APPNAME")
 
listen File.expand_path("tmp/unicorn.sock", ENV['RAILS_ROOT'])
pid File.expand_path("tmp/unicorn.pid", ENV['RAILS_ROOT'])
 
preload_app true
 
stdout_path "$WEB_ROOT/$APPNAME/log/unicorn.stdout.log"
stderr_path "$WEB_ROOT/$APPNAME/log/unicorn.stderr.log"
 
GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true
 
before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
  old_pid = "#{server.config[:pid]}.oldbin"
  if old_pid != server.pid
    begin
      sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
      Process.kill(sig, File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
  sleep 1
end
 
after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end
__EOT__

git add $WEB_ROOT/$APPNAME/config/unicorn.rb
git commit -a -m 'add unicorn.rb'

/etc/init.d/以下に格納するunicornのinitスクリプトから参照される設定ファイルを作成する。

このファイルを作成した後、UNICORN_OPTSで設定しているオプションがproductionになっているので、unicornを起動した際にはdevelopment環境として起動します。productionが良ければproductionに書き換えてからスクリプトを実行してください。

cat <<- __EOT__ | sudo tee -a /etc/default/unicorn_$APPNAME
CONFIGURED=yes
TIMEOUT=60
APP_ROOT=$WEB_ROOT/$APPNAME
CONFIG_RB="\$APP_ROOT/config/unicorn.rb"
PID=/run/unicorn_$APPNAME.pid
SECRET_KEY_BASE=`bundle exec rake secret`
UNICORN_OPTS="-E development -c $WEB_ROOT/$APPNAME/config/unicorn.rb -D"
__EOT__

nginxの設定ファイルにunicornを呼び出す設定を追記する

設定内容は必要に応じて追記してください。

sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default_bak
cat <<- __EOT__ | sudo tee -a /etc/nginx/sites-available/default

upstream $APPNAME {
  server unix:$WEB_ROOT/$APPNAME/tmp/unicorn.sock;
}
 
server {
  server_name $APPNAME;
  root $WEB_ROOT/$APPNAME;
  location / {
    proxy_pass http://$APPNAME;
  }
}
__EOT__

unicornの起動スクリプト

cat <<- __EOT__ | sudo tee -a /etc/init.d/unicorn_$APPNAME
#!/bin/sh
### BEGIN INIT INFO
# Provides:          unicorn_$APPNAME
# Required-Start:    \$local_fs \$remote_fs
# Required-Stop:     \$local_fs \$remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: unicorn_$APPNAME initscript
# Description:       unicorn_$APPNAME
### END INIT INFO

set -e

NAME=unicorn_$APPNAME
DESC="unicorn_$APPNAME web server"

. /lib/lsb/init-functions

if [ -f /etc/default/unicorn_$APPNAME ]; then
  . /etc/default/unicorn_$APPNAME
fi

DAEMON=/usr/bin/unicorn
PID=$WEB_ROOT/$APPNAME/tmp/unicorn.pid

run_by_init() {
    ([ "\${previous-}" ] && [ "\${runlevel-}" ]) || [ "\${runlevel-}" = S ]
}

exit_with_message() {
  if ! run_by_init; then
    log_action_msg "\$1 Not starting."
  fi
  exit 0
}

check_config() {
  if [ \$CONFIGURED != "yes" ]; then
    exit_with_message "unicorn_$APPNAME is not configured (see /etc/default/unicorn_$APPNAME)."
  fi
}

check_app_root() {
  if ! [ -d \$APP_ROOT ]; then
    exit_with_message "Application directory \$APP_ROOT is not exist."
  fi
}

set -u

case "\$1" in
  start)
        check_config
        check_app_root
        log_daemon_msg "Starting \$DESC" \$NAME || true
        if start-stop-daemon --start --quiet --oknodo --pidfile \$PID --exec \$DAEMON -- \$UNICORN_OPTS; then
          log_end_msg 0 || true
        else
          log_end_msg 1 || true
        fi
              ;;
  stop)
        log_daemon_msg "Stopping \$DESC" \$NAME || true
        if start-stop-daemon --stop --signal QUIT --quiet --oknodo --pidfile \$PID; then
          log_end_msg 0 || true
        else
          log_end_msg 1 || true
        fi
        ;;
  force-stop)
        log_daemon_msg "Forcing stop of \$DESC" \$NAME || true
        if start-stop-daemon --stop --quiet --oknodo --pidfile \$PID; then
          log_end_msg 0 || true
        else
          log_end_msg 1 || true
        fi
        ;;
  restart|force-reload)
        log_daemon_msg "Restarting \$DESC" \$NAME || true
        start-stop-daemon --stop --quiet --oknodo --pidfile \$PID
        sleep 1
        if start-stop-daemon --start --quiet --oknodo --pidfile \$PID --exec \$DAEMON -- \$UNICORN_OPTS; then
          log_end_msg 0 || true
        else
          log_end_msg 1 || true
        fi
        ;;
  reload)
        log_daemon_msg "Reloading \$DESC" \$NAME || true
        if start-stop-daemon --stop --signal HUP --quiet --oknodo --pidfile \$PID; then
          log_end_msg 0 || true
        else
          log_end_msg 1 || true
        fi
        ;;
  reopen-logs)
        log_daemon_msg "Relopening log files of \$DESC" \$NAME || true
        if start-stop-daemon --stop --signal USR1 --quiet --oknodo --pidfile \$PID; then
          log_end_msg 0 || true
        else
          log_end_msg 1 || true
        fi
        ;;
  status)
        status_of_proc -p \$PID \$DAEMON \$NAME && exit 0 || exit \$?
        ;;
  *)
        log_action_msg "Usage: \$0 <start|stop|restart|force-reload|reload|force-stop|reopen-logs|status>" || true
        exit 1
        ;;
esac

__EOT__

DBのマイグレーション

cd $WEB_ROOT/$APPNAME

bundle install

# 対象は、productionなり、environmentなり適宜修正してください。
RAILS_ENV=production rake db:migrate

起動する前にconfig/database.yml内のproductionに設定されているproduction環境のDBパスワードが環境変数となっています。productionのpassword:の行をコメントアウトすればdefaultに設定したパスワードが使用されます。環境変数に設置されたものを使いたい場合には、/etc/default/以下にあるunicorn用の設定ファイル中に環境変数を定義すれば良いと思います。

# 一番下の方にある
vi $WEB_ROOT/$APPNAME/config/database.yml

追加したunicornサービスを起動させる

# Linux起動時に自動起動するように設定する
sudo chmod +x /etc/init.d/unicorn_$APPNAME
sudo update-rc.d unicorn_$APPNAME defaults

# 今起動させてみる
sudo service unicorn_$APPNAME start

# ログはここで見る。
tail -f $WEB_ROOT/$APPNAME/log/*

同一サーバ上にあるgitサーバにコミットして、redmineと連携させる

# 下記、開発サーバとgitのリポジトリが存在するサーバが
# 同一サーバである前提で設定を行っている。
# 別サーバにする場合には、別サーバでgitのセットアップを行ってください。
if [ ! -e /opt/git ]; then
    sudo mkdir /opt/git
    sudo chown $EDIT_USER:$GIT_GROUP /opt/git
fi

if [ ! -e /opt/git/$APPNAME ]; then
    mkdir /opt/git/$APPNAME
    cd /opt/git/$APPNAME
    git --bare init
fi

cd $WEB_ROOT/$APPNAME
git remote add origin file:///opt/git/$APPNAME
git push origin master
git push --set-upstream origin master

# redmineに設定するgitのリポジトリ情報
echo /opt/git/$APPNAME

Redmineの設定

redmineの初期セットアップはこちらを参照。以降は、Redmineの初期設定は終わっているものとしてその続きを記載する。

redmine_git10

Redmineにログインして、新しいプロジェクトを作成する。

redmine_git11

該当プロジェクトの設定>リポジトリ>新しいリポジトリを選択。

redmine_git12

上記のような感じで、設定値を入力する。

redmine_git13

該当プロジェクトのリポジトリを参照して、コミットされたファイル群が参照できればOK。

適当なページを作成して動かしてみる

cd $WEB_ROOT/$APPNAME
rails generate scaffold testpage test:string suuzi:integer
rake db:migrate

# この$DBNAMEの環境変数、書いている途中で変数名が間違っていると気づきながらも書いていました。
sudo service unicorn_$DBNAME restart

# 接続先のURLを表示
echo http://$APPNAME/tests/

hostsファイルに$APPNAMEとRails環境をセットアップしたIPアドレスの対を記載して、ウェブブラウザでechoコマンドで表示したURLにアクセスすればページが参照できると思います。

 

タグ付けされた , . ブックマークする へのパーマリンク.

コメントを残す

メールアドレスが公開されることはありません。