RailsのDeploy環境+運用を考慮したサーバー構築


Ruby on RailsでDev環境は使ったことあるけど、test・prod環境を考慮した環境構築をしたことがない人にお勧めの内容です。

##サーバー構成図

![スクリーンショット 2014-01-11 12.15.17.png](https://qiita-image-store.s3.amazonaws.com/0/29861/b3ec75c8-91cb-f9cc-8968-90525852d7ec.png "スクリーンショット 2014-01-11 12.15.17.png")

##サーバーの役割
###リバースプロキシサーバー(ホスト名：rp01）
* ロードバランサ機能を使ってWEBサーバ二台に処理を振り分け、アクセスを１台のサーバーに集中させない
* WEBサーバーを外部から隠せることでセキュリティ面の向上

###WEBサーバー（web01、web02）
* webサーバーを２台用意することでアクセスが１つのサーバーに集中しないため、レスポンスを早くできる

###マスターDBサーバー（db01m）
* DB内容をもう１台のDBサーバー（スレーブ）へリアルタイムにコピーし、障害でマスターが停止したときはスレーブに切り替える

###スレーブDBサーバー（db01s）
* 読み込み専用のサーバー。書き込みをしない分レスポンスが早くなる
* マスターの内容を常にコピーする（レプリケーションという）

###開発環境（dev01）
* 開発はこの環境だけで行い、完成物をWEBサーバーにアップロードする（デプロイという）

###DNS（rp01）
* 各サーバーのホスト名を管理するDNS。リバースプロキシと同じサーバー内で動作させる

##準備

* VPS等でサーバーを5台借りておく（rp01、web01、web02、db01m、db01s）
* リバースプロキシはグローバルIP必須
* 開発環境（手持ちにMacやUnix環境がないならvpsで借りる）

##サーバー仕様

###WEBサーバー・リバースプロキシ
* Apache/2.2.15 (Unix)

###データベース
* MySQL Server 5.1.71

###DNS
* mydns 1.2.8.31

###Ruby
* ruby-2.0.0-p353

###Ruby on Rails
* Rails 4.0.2

##全サーバーに共通するセットアップ

###ログインユーザーのセキュリティ設定編

初期インストールされたパッケージをアップデート

`$ sudo yum update`

ログインユーザー（deploy01）の作成

```
$ useradd deploy01
$ passwd  deploy01
```

deploy01をsudo権限が使えるグループに所属させる

```
$ usermod –G wheel deploy01
```

wheelグループ以外はsudo権限を与えない設定。
下記行のコメントを外す。

```zsh:/etc/pam.d/su
#auth  required pam_wheel.so use_uid
```

wheelグループのみrootユーザーにログイン可能にする。
下記行を追加

```vim:/etc/login.defs
SU_WHEEL_ONLY yes
```

wheelグループのユーザーのみ sudoコマンドを実行許可。
下記コマンドを実行する。

```
$ visudo
```

すると、設定ファイルが開くので下記行のコメントを外す

```
# %wheel ALL=(ALL) ALL
```

rootユーザーでのsshログインを禁止する。
下記行をコメント化する

```vim:/etc/ssh/sshd_config
PermitRootLogin no
```

SSHのポートを狙った攻撃を回避するため、ポート番号を変更する。
Portの後ろに変更したいポート番号を入れる

```vim:/etc/ssh/sshd_config
Port 3243
```

SSHの変更を有効にするため、SSHを再起動するコマンドを実行

`$ /etc/init.d/sshd restart`

###ファイアウォール編

下記コマンドを実行するとファイアウォールの設定情報を確認できる

```
$ /sbin/iptables -L --line-number

Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination

```

上記と同じ表示の場合、すべての通信を許可しているためセキュリティ上問題がある。
各サーバーごとにファイアウォールを設定する。

#### リバースプロキシ（rp01）のファイアウォール設定

外部パケットから入ってくるパケットのうち
http、https、ssh（ポートは3824）、DNSのみ許可する。

```vim:/etc/sysconfig/iptables
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
## allow well-known port ##
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
## allow port(SSH,http,https,DNS) ##
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3824 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80   -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 443  -j ACCEPT
-A INPUT -m state --state NEW -m udp -p udp --dport 53   -j ACCEPT
COMMIT
```

#### WEBサーバー（web01、web02）の設定

※IPアドレスをホスト名に置き換えてます。

```vim:/etc/sysconfig/iptables
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
#------------------------------------------------------
# ping、ループバックアドレスを許可
#------------------------------------------------------
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
#------------------------------------------------------
# RPのみ、webサーバーへの通信を許可
# 80は本番環境（prod）のサイト表示
# 8000はテスト環境（test）のサイト表示
#------------------------------------------------------
-A INPUT -s rp01 -p tcp --dport 80   -j ACCEPT
-A INPUT -s rp01 -p tcp --dport 8000 -j ACCEPT
#------------------------------------------------------
# SSHを許可
#------------------------------------------------------
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3843 -j ACCEPT
COMMIT
```

#### DBサーバー（db01m）の設定

※IPアドレスをホスト名に置き換えてます。

```
*filter
#------------------------------------------------------
# メンテナンス可能リスト
# web01
# web02
# db01s
#------------------------------------------------------
#------------------------------------------------------
# ポリシー：全ての送受信パケットを破棄。必要な用途に応じて開けていく。
#------------------------------------------------------
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
#------------------------------------------------------
# pingとループバックアドレス（自分自身のIP）からの送受信を許可
#------------------------------------------------------
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A INPUT  -p icmp -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT
#------------------------------------------------------
# 内部からのDNS送信を許可
#------------------------------------------------------
-A OUTPUT -m state --state NEW -m udp -p udp --dport 53   -j ACCEPT
#------------------------------------------------------
# 内部からのhttp送信を許可（yum等）
#------------------------------------------------------
-A OUTPUT -m state --state NEW -m tcp -p tcp --dport 80   -j ACCEPT
#------------------------------------------------------
# メンテナンスのみSSH接続を許可
#------------------------------------------------------
-A INPUT  -s web01 -p tcp --dport 3843 -j ACCEPT
-A OUTPUT -d web01 -p tcp --sport 3843 -j ACCEPT
-A INPUT  -s web02 -p tcp --dport 3843 -j ACCEPT
-A OUTPUT -d web02 -p tcp --sport 3843 -j ACCEPT
-A INPUT  -s db01s -p tcp --dport 3843 -j ACCEPT
-A OUTPUT -d db01s -p tcp --sport 3843 -j ACCEPT
#------------------------------------------------------
# メンテナンスのみMySQL接続を許可
#------------------------------------------------------
-A INPUT  -s web01 -p tcp --dport 3306 -j ACCEPT
-A OUTPUT -d web01 -p tcp --sport 3306 -j ACCEPT
-A INPUT  -s web02 -p tcp --dport 3306 -j ACCEPT
-A OUTPUT -d web02 -p tcp --sport 3306 -j ACCEPT
-A INPUT  -s db01s -p tcp --dport 3306 -j ACCEPT
-A OUTPUT -d db01s -p tcp --sport 3306 -j ACCEPT
#------------------------------------------------------
# 接続済みパケットの送受信を許可
#------------------------------------------------------
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
COMMIT
```


#### DBサーバー（db01s）の設定

※IPアドレスをホスト名に置き換えてます。

```
*filter
#------------------------------------------------------
# メンテナンス可能リスト
# web01
# web02
# db01m
#------------------------------------------------------
#------------------------------------------------------
# ポリシー：全ての送受信パケットを破棄。必要な用途に応じて開けていく。
#------------------------------------------------------
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
#------------------------------------------------------
# pingとループバックアドレス（自分自身のIP）からの送受信を許可
#------------------------------------------------------
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A INPUT  -p icmp -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT
#------------------------------------------------------
# 内部からのDNS送信を許可
#------------------------------------------------------
-A OUTPUT -m state --state NEW -m udp -p udp --dport 53   -j ACCEPT
#------------------------------------------------------
# 内部からのhttp送信を許可（yum等）
#------------------------------------------------------
-A OUTPUT -m state --state NEW -m tcp -p tcp --dport 80   -j ACCEPT
#------------------------------------------------------
# メンテナンスのみSSH接続を許可
#------------------------------------------------------
-A INPUT  -s web01 -p tcp --dport 3843 -j ACCEPT
-A OUTPUT -d web01 -p tcp --sport 3843 -j ACCEPT
-A INPUT  -s web02 -p tcp --dport 3843 -j ACCEPT
-A OUTPUT -d web02 -p tcp --sport 3843 -j ACCEPT
-A INPUT  -s db01m -p tcp --dport 3843 -j ACCEPT
-A OUTPUT -d db01m -p tcp --sport 3843 -j ACCEPT
#------------------------------------------------------
# メンテナンスのみMySQL接続を許可
#------------------------------------------------------
-A INPUT  -s web01 -p tcp --dport 3306 -j ACCEPT
-A OUTPUT -d web01 -p tcp --sport 3306 -j ACCEPT
-A INPUT  -s web02 -p tcp --dport 3306 -j ACCEPT
-A OUTPUT -d web02 -p tcp --sport 3306 -j ACCEPT
-A INPUT  -s db01m -p tcp --dport 3306 -j ACCEPT
-A OUTPUT -d db01m -p tcp --sport 3306 -j ACCEPT
#------------------------------------------------------
# 接続済みパケットの送受信を許可
#------------------------------------------------------
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
COMMIT
```

すべての設定を書き終えたらiptablesを再起動してファイアウォールを有効化

```
$ service iptables restart
```

ファイアウォールの設定は以上。
開発環境のファイアウォールは任意で設定してください。

## MySQL（データベースサーバー）のインストール

### Mysqlのパッケージについて

mysqlのパッケージには大きく分けて３種類ある

* mysql：client用
* mysql-server：server用
* mysql-devel：アプリケーションとの連携用

そのため、用途によってはインストールするパッケージを絞ることが可能

terminalからmysqlに接続する

* mysql

railsやmydns等のアプリケーションからmysqlサーバーに接続

* mysql、mysql-devel

データベース運用

* mysql-server


今回はサーバーごとにインストールするパッケージを変える

### MySQLのインストール

rp01（DNSサーバー用として使う）

`$ yum install mysql mysql-devel mysql-server`

web01、web02（rails用にインストール）

`$ yum install mysql mysql-devel`

db01m、db01s（mysqlデータベース用）

`$ yum install mysql mysql-server`

### mysqlの設定

以下をサーバー5台全てに設定する

mysqlの設定ファイルをバックアップする

`$ sudo cp /etc/my.cnf /etc/my.cnf.org`

MySQLの設定ファイルをバックアップ

`$ sudo cp /etc/my.cnf /etc/my.cnf.org`

MySQLの設定ファイルを下記のように設定

```vim:/etc/my.cnf

[mysqld]
character-set-server = utf8
skip-character-set-client-handshake
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
symbolic-links=0

innodb_buffer_pool_size = 512MB # サーバのメモリ70〜80%
innodb_log_file_size = 100MB # 100-500MB程度
innodb_flush_log_at_trx_commit = 2

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid          
```

rootのパスワード設定

```
$ sudo mysqladmin -u root password 'パスワード'
```

mysql-serverをインストールしている
rp01とdb01m、db02mのみMySQLの自動起動をONにする

```
$ sudo service mysqld start
$ sudo chkconfig mysqld on
```

MySQLにログインし、不要なユーザーとデータベースを削除する

```
$ mysql -u root -p ****

mysql ＞ use mysql;
mysql ＞ select user,password, host from user;
+------+-------------------------------------------+-------------------------+
| user | password                                  | host                    |
+------+-------------------------------------------+-------------------------+
| root | *hogehogehogehogehogehogehogehogehogehoge | localhost               |
| root |                                           | hogehogehogehogeh.ne.jp |
| root |                                           | 127.0.0.1               |
|      |                                           | localhost               |
|      |                                           | hogehogehogehogeh.ne.jp |
+------+-------------------------------------------+-------------------------+
mysql　＞ DELETE FROM user WHERE user = '' OR ( user = 'root' AND host != 'localhost' );
Query OK, 4 rows affected (0.00 sec)

mysql　＞ select user,password, host from user;
+------+-------------------------------------------+-----------+
| user | password                                  | host      |
+------+-------------------------------------------+-----------+
| root | *hogehogehogehogehogehogehogehogehogehoge | localhost |
+------+-------------------------------------------+-----------+
1 row in set (0.00 sec)
```

続いて、不要なデータベースを削除

```
mysql ＞ show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| test               |
+--------------------+
3 rows in set (0.00 sec)

mysql＞ DROP DATABASE test;
Query OK, 0 rows affected (0.00 sec)

```

文字セットの確認

```
show variables like 'character_set%';
# ↓ のようになっていれば成功
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
```

### rails用のデータベースを作成

```
mysql > create database app;
mysql > create database app_test;
mysql > create database app_dev;
```

## mydns（DNSサーバー）のインストール

### mydnsとは？

MySQLのデータベースを使って、ホスト名の管理ができる。
ホストを追加するときはinsert文を１つ打つだけで設定可能なので管理が楽。

### インストールについて

MyDNSのインストールは任意。
SSH接続やiptables、apache設定でipを使わずホスト名を使いたい人は
設定してください。（この記事は全てホスト名になっています）

### インストール方法

インストールはrp01で行います。

mydnsをダウンロードするためのリポジトリを追加

```
rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
```

mydnsパッケージのインストール

```
$ yum install mydns
$ yum install mydns-mysql
```

mysqlにログインし、mydns用データベースを作成

```
mysql > create database mydns;
```

ターミナルから下記コマンドを実行

`$ mydns --create-tables | mysql -u root -p mydns`

mysqlにログインし、mydns用のテーブルができているか確認

```
mysql > use mydns;

Database changed
mysql> show tables;
+-----------------+
| Tables_in_mydns |
+-----------------+
| rr              |
| soa             |
+-----------------+
```

mydns用のユーザーを作成する。
※データベースmydnsに対して、全ての権限を持ったユーザー（全てのホストからのアクセス許可）

```
GRANT ALL ON mydns.* TO 'mydns'@'%' IDENTIFIED BY 'mydns';
Query OK, 0 rows affected (0.01 sec)
```

DNSゾーンとレコードの作成

※ネットワークをxxx.localにする
※xxx.xxx.xxx.xxxはIPアドレスです

```
mysql> insert into soa (origin, ns) values ('local.', 'ns.local');
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> insert into rr (zone, name, type, data) values(1, 'web01', 'A', ‘xxx.xxx.xxx.xxx’);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> insert into rr (zone, name, type, data) values(1, 'web02', 'A', 'xxx.xxx.xxx.xxx’);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> insert into rr (zone, name, type, data) values(1, 'db01m', 'A', 'xxx.xxx.xxx.xxx’);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> insert into rr (zone, name, type, data) values(1, 'db01s', 'A', 'xxx.xxx.xxx.xxx’);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> insert into rr (zone, name, type, data) values(1, ‘rp01,   'A', 'xxx.xxx.xxx.xxx’);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> insert into rr (zone, name, type, data) values(1, ‘dev01’, 'A', 'xxx.xxx.xxx.xxx’);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select * from rr;
+----+------+-------+------------------+-----+-------+------+
| id | zone | name  | data             | aux | ttl   | type |
+----+------+-------+------------------+-----+-------+------+
|  1 |    1 | web01 | xxx.xxx.xxx.xxx  |   0 | 86400 | A    |
|  2 |    1 | web02 | xxx.xxx.xxx.xxx  |   0 | 86400 | A    |
|  3 |    1 | db01m | xxx.xxx.xxx.xxx  |   0 | 86400 | A    |
|  4 |    1 | db01s | xxx.xxx.xxx.xxx  |   0 | 86400 | A    |
|  5 |    1 | rp01  | xxx.xxx.xxx.xxx  |   0 | 86400 | A    |
|  6 |    1 | dev01 | xxx.xxx.xxx.xxx  |   0 | 86400 | A    |
+----+------+-------+------------------+-----+-------+------+

mysql > select * from soa;
+----+--------+----------+------+--------+---------+-------+--------+---------+-------+
| id | origin | ns       | mbox | serial | refresh | retry | expire | minimum | ttl   |
+----+--------+----------+------+--------+---------+-------+--------+---------+-------+
|  1 | local. | ns.local |      |      1 |   28800 |  7200 | 604800 |   86400 | 86400 |
+----+--------+----------+------+--------+---------+-------+--------+---------+-------+
1 row in set (0.00 sec)
```

###DNSの設定とmydnsの起動

ホスト名で通信したいすべてのサーバーで下記を設定

xxx.xxx.xxx.xxxはrp01のグローバルIPアドレス

```vim:/etc/resolv.conf
search local
nameserver xxx.xxx.xxx.xxx
```

mydnsを起動

```
$ service mydns start
```

設定したホスト名でpingが通るか確認

```
ping web01
```

##レプリケーションの設定

### レプリケーションとは
データベースの内容を別のデータベースにリアルタイムで同期させる。
コピ元をマスター、コピー先をスレーブという。

### レプリケーションの設定方法

マスターのdb01mのmy.cnfを下記のように設定

```vim:/etc/my.cnf
[mysqld]
log-bin=mysql-bin
server-id=1001
```

スレーブのdb01sにマスターに接続するmysqlユーザーを作成するため、
db01sのmysqlにログインして、下記を実行
※xxx.xxx.xxx.xxxはmasterのipアドレス

```
GRANT REPLICATION SLAVE ON *.* TO 'repl’@‘xxx.xxx.xxx.xxx’ IDENTIFIED BY 'slavepass';
```

スレーブのmy.cnfファイル内で以下の通り設定

```vim:/etc/my.cnf
[mysqld]
server-id=1002
```

マスター側のpositionを確認

```
mysql>  SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000002 |      379 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
```

それぞれの意味

File        : バイナリログ名
Position  : ファイル内のオフセット（現在位置）

Positionとファイル名をメモしておき、マスターのデータベースのテーブルをロックしておく

```
mysql > FLUSH TABLES WITH READ LOCK
```

マスターのデータベースのバックアップを取る

`$ mysqldump -u root -p --all-databases --lock-all-tables > /tmp/dbdump.db`


スレーブ側でSCPコマンドを使って、マスターのdbファイルを取得

`$ scp -P sshのポート番号 deploy01@db01m :/tmp/dbdump.db /tmp/`

スレーブのデータベースにマスターの内容を反映

`# mysql -u root -p /tmp/dbdump.db `


スレーブ側でマスター情報を登録

xxx.xxx.xxx.xxxにはマスターのipアドレスを入れる

```
mysql > CHANGE MASTER TO
           MASTER_HOST=‘xxx.xxx.xxx.xxx’,
           MASTER_USER='repl',
           MASTER_PASSWORD='XXXXXX',
           MASTER_LOG_FILE='mysql-bin.000002',
           MASTER_LOG_POS=379;
```

レプリケーション開始するため、スレーブ側で下記コマンドを実行

```
mysql > START SLAVE;
```

レプリケーションが開始されているか確認

```
show slave status;

mysql> show slave status \G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: xxx.xxx.xxx.xxx
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000002
          Read_Master_Log_Pos: 450
               Relay_Log_File: mysqld-relay-bin.000003
                Relay_Log_Pos: 251
        Relay_Master_Log_File: mysql-bin.000002
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
```

下記を確認できればDBの同期が取れている

```
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
```

## Rubyのインストール

作業はweb01とweb02で行う

rootユーザーでインストールすると、root権限が必要なときがあるため
deploy01ユーザーにインストールを行う。（シングルインストール）

### rvmを使ったRubyのインストール

rvmはRubyのバージョン管理を容易に行える。
コマンド１つでバージョンを切り替えたり、バージョンごとのインストールが可能

必要なパッケージのインストール

```
$ sudo yum -y install curl curl-devel gcc gcc-c++ httpd-devel readline-devel tk-devel make zlib-devel libffi-devel
```

rvmをインストール

```
$ bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer )
$ echo "source $HOME/.rvm/scripts/rvm" >> ~/.bash_profile
$ source ~/.bash_profile
```


Rubyのver 2.0.0をインストール

```
$ rvm install 2.0.0
```

RVMの設定確認

```
$ rvm list
=* ruby-2.0.0-p247 [ x86_64 ] # 
```

### railsの導入

railsのインストール（RDocのインストール部分で結構時間かかる）

```
$ gem install rails
```

RDocが不要な場合は下記でインストールする

```
$ gem install rails –no-ri –no-rdoc
```


passangerのインストールを行う

```
$ gem install passenger
$ passenger-install-apache2-module
```

インストール完了後、下記のような表示が出るのでコピー

```
LoadModule passenger_module /usr/lib64/ruby/gems/1.8/gems/passenger-4.0.19/buildout/apache2/mod_passenger.so
PassengerRoot /usr/lib64/ruby/gems/1.8/gems/passenger-4.0.19
PassengerDefaultRuby /usr/bin/ruby
```

passenger.confに上記設定とオプションを記入

```vim:/etc/httpd/conf.d/passnger.conf
# Passengerの基本設定
LoadModule passenger_module /usr/local/rvm/gems/ruby-2.0.0-p247@global/gems/passenger-4.0.18/buildout/apache2/mod_passenger.so
PassengerRoot /usr/local/rvm/gems/ruby-2.0.0-p247@global/gems/passenger-4.0.18
PassengerDefaultRuby /usr/local/rvm/wrappers/ruby-2.0.0-p247@global/ruby

# Passengerが追加するHTTPヘッダを削除するための設定
Header always unset "X-Powered-By"
Header always unset "X-Rack-Cache"
Header always unset "X-Content-Digest"
Header always unset "X-Runtime"

# 必要に応じてPassengerのチューニングのための設定を追加
PassengerMaxPoolSize 20
PassengerMaxInstancesPerApp 4
PassengerPoolIdleTime 3600
PassengerHighPerformance on
PassengerStatThrottleRate 10
RailsSpawnMethod smart
RailsAppSpawnerIdleTime 86400
PassengerMaxPreloaderIdleTime 0
```

### デプロイ用のディレクトリを作成

test環境とprod環境の２つを用意する

```
$ sudo mkdir /var/www/deploy01/
$ sudo chown deploy01:deploy01 /var/www/deploy01/
$ chmod 775 /var/www/deploy01/
$ mkdir /var/www/deploy01/prod/
$ mkdir /var/www/deploy01/test/
```

### 開発環境側の設定

開発環境側（dev01）はappというアプリが出来ている状況とします。

database.ymlにslaveとmasterのdb情報を設定する

```ruby:config/database.yml
development:
  adapter: mysql2
  encoding: utf8
  database: app_dev
  pool: 5
  username: root
  password: xxxx
  host: localhost

test_slave_database:
  adapter: mysql2
  encoding: utf8
  database: app_test
  pool: 5
  username: root
  password: xxx
  host: db01s

test:
  adapter: mysql2
  encoding: utf8
  database: app_test
  pool: 5
  username: root
  password: xxx
  host: db01m

production_slave_database:
  adapter: mysql2
  encoding: utf8
  database: app
  pool: 5
  username: root
  password: xxx
  host: db01s

production:
  adapter: mysql2
  encoding: utf8
  database: app
  pool: 5
  username: root
  password: xxx
  host: db01m
```

Gemfileに下記パッケージを記載する

```ruby:Gemlife
gem 'multi_db'
```

#### デプロイツールのインストール

web01とweb02にgitをインストール
```
$ sudo yum install git
```

appアプリ配下で下記を実行

```
$ gem install capistrano
```

インストールが完了したらcapifyコマンドを実行

```
capify .
> [add] writing './Capfile'
> [add] writing './config/deploy.rb'
> [done] capified!
```

test環境とprod環境用のCapistrano設定ファイルを作成

```
$ mkdir config/deploy
$ touch config/deploy/test.rb
$ touch config/deploy/production.rb
```

共通のデプロイ情報をdeploy.rbに記入

ipアドレスをホスト名に変えてます。

```ruby:app/config/deploy.rb
# -*- coding: utf-8 -*-
set :default_stage, "production"

# 複数環境にデプロイできるようにする
require "capistrano/ext/multistage"

# capistranoの出力をカラーに
require 'capistrano_colors'

# cap deploy時に自動で bundle installを実行
require "bundler/capistrano"

# RVM
require "rvm/capistrano"
set :rvm_ruby_string, ‘2.0.0-p353’
set :rvm_type, :user

# gitリポジトリの設定
#### gitリポジトリをセット ####
set :repository,  “gitのリポジトリ”
set :scm, :git
set :deploy_via, :remote_cache

# SSH
set :use_sudo, false
set :default_run_options, :pty => true
ssh_options[:port] = 22
ssh_options[:forward_agent] = true

set :normalize_asset_timestamps, false
# 過去のデプロイしたフォルダを履歴として保持する数
set :keep_releases, 5

# デプロイ先のサーバの設定
server “web01:3843", :app, :web, :db, :primary => true
server “web02:3843", :app, :web, :db, :primary => true

# bundle install条件
set :bundle_flags, "--no-deployment --without test development"

# SSH
set :user, "deploy01"
set :user_group, "deploy01"
set :password, “SSHのログインパスワード”

# RVM
set :rvm_path, '/home/deploy01/.rvm/'
set :rvm_bin_path, “app/bin"
set :rvm_lib_path, “app/lib"

# assets:precompile
namespace :assets do
  task :precompile, :roles => :web do
    run "cd #{current_path} && RAILS_ENV=#{rails_env} bundle exec rake assets:precompile"
  end
end

# メンテナンスモード
namespace :maintenance do
  desc "Maintenance start"
  task :on, :roles => :web do
    on_rollback { run "rm #{current_path}/tmp/maintenance.yml" }
    page = File.read("config/maintenance.yml")
    put page, "#{current_path}/tmp/maintenance.yml", :mode => 0644
  end

  desc "Maintenance stop"
  task :off, :roles => :web do
    run "rm #{release_path}/tmp/maintenance.yml"
  end
end

namespace :deploy do
  # Passengerの実行ユーザー/Groupをセット
  task :set_file_process_owner do
    sudo "chown -R #{user}:#{user_group} #{deploy_to}"
  end

  #### sitemap_generatorを使ってない場合は削除 ####
  desc "sitemapの更新"
  task :refresh_sitemaps do
    run "cd #{latest_release} && RAILS_ENV=#{rails_env} bundle exec rake sitemap:refresh"
  end

  # 本番サーバでPassenger以外を使っている場合は適宜変更して下さい。
  desc "Passenger用に起動/停止タスクを変更"
  task :restart, :roles => :web do
    run "touch #{current_path}/tmp/restart.txt"
  end

  # page_cacheを使用していない場合は不要
  desc "キャッシュhtmlの削除(deploy中に不完全なhtmlを生成しないための対策)"
  task :remove_caches, :roles => :web do
    run "rm -rf #{current_path}/public/index.html"
  end

  #### Wheneverを使っていない場合は削除
  desc "wheneverのアップデート"
  task :whenever_update do
    run "cd #{latest_release} && RAILS_ENV=#{rails_env} bundle exec whenever --update-crontab #{application} -f config/schedule_#{rails_env}.rb"
  end
end
before :deploy, "deploy:set_file_process_owner"
```

prod用の設定

```ruby:app/config/deploy/production.rb
#### デプロイ先のフォルダを設定　####
set :deploy_to, "/var/www/deploy01/prod/app”
set :rails_env, "production"

# deploy ==========================
after :deploy, "maintenance:on"
after :deploy, "assets:precompile"
after :deploy, "deploy:migrate"
after :deploy, "deploy:restart"
after :deploy, "deploy:remove_caches"
after :deploy, "maintenance:off"
after :deploy, "deploy:cleanup"
```


test用の設定

```ruby:app/config/deploy/test.rb
#### デプロイ先のフォルダを設定　####
set :deploy_to, "/var/www/deploy01/test/app”
set :rails_env, “test”

# deploy ==========================
after :deploy, "assets:precompile"
after :deploy, "deploy:migrate"
after :deploy, "deploy:restart"
after :deploy, "deploy:remove_caches"
after :deploy, "deploy:cleanup"
```

メンテナンス画面表示用にconfig/maintenance.ymlを追加。 

```
---
reason: メンテナンス中です
allowed_paths:
- ^/help
- ^/contact_us
allowed_ips:
- 127.0.0.1
- 192.168.0.0/24
```

リポジトリへのパスフレーズ入力を省略するため、ssh-agentの追加をする
※鍵にはgitリポジトリの秘密鍵を指定

```
# ssh-agent zsh
# ssh-agent ~/.ssh/id_rsa
```

デプロイができるかのテスト（初回のみ）

```
cap deploy:check
```

デプロイコマンド一覧

```
セットアップ（初回に実行）
$ cap production deploy:setup
$ cap test deploy:setup

デプロイを実行
$ cap production deploy:cold
$ cap test deploy:cold

以前の状態に戻す
$ cap production deploy:rollback
$ cap test deploy:rollback

以前の状態のソースコードを削除
$ cap production deploy:cleanup
$ cap test deploy:cleanup
```

### Apacheの設定
deployが完了したらweb01とweb02のhttpd.confにrailsアプリの設定を行う

xxx.xxx.xxx.xxxにはweb01ならweb01のIPを記入

```vim:/etc/httpd/conf/httpd.conf 
# prod
<VirtualHost *:80>
  ServerName xxx.xxx.xxx.xxx
  DocumentRoot /var/www/deploy01/prod/app/current/public/
  ErrorLog  /var/log/httpd/prod_app_error.log
  CustomLog /var/log/httpd/prod_app_access.log combined
  <Directory "/var/www/deploy01/prod/app/current/public">
        Options -MultiViews
        AllowOverride All
        Order allow,deny
        Allow from all
  </Directory>
</VirtualHost>

# test
<VirtualHost *:8000>
  RailsEnv test
  ServerName xxx.xxx.xxx.xxx
  DocumentRoot /var/www/deploy01/test/app/current/public/
  ErrorLog  /var/log/httpd/test_app_error.log
  CustomLog /var/log/httpd/test_app_access.log combined
  <Directory "/var/www/deploy01/test/app/current/public">
        Options -MultiViews
        AllowOverride All
        Order allow,deny
        Allow from all
  </Directory>
</VirtualHost>
```

serverNameでvirtualhostを分ける設定をONにするため
下記行のコメントを外す

```vim:/etc/httpd/conf/httpd.conf
#NameVirtualHost *:80
```

web01とweb02のapacheを再起動

```
$ sudo service httpd restart
```

iptablesを停止して、testとprod環境にアクセスできるか確認

```
http://xxx.xxx.xxx.xxx:80/
http://xxx.xxx.xxx.xxx:8000/
```

testとprod環境が動いていることを確認できたらiptablesを再スタートする

```
$ sudo service iptables start
```

## リバースプロキシの設定

rp01のhttp.confファイルに下記モジュールを設定

```vim:/etc/httpd/conf/httpd.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
```

さらに、rp01のhttp.confにロードバランサの処理を追加

※ipアドレスをホスト名に置き換えてます

```
#prod環境へのアクセスを「xxx.com」
#test環境へのアクセスを「test.xxx.com」のサブドメインにした場合の設定

#prod設定
<VirtualHost *:80>
  ServerName xxx.com:80

  ProxyPass /balancer-manager !
  <Location /balancer-manager>
          SetHandler balancer-manager
  </Location>

  ProxyPass / balancer://rp01/
  ProxyPassReverse / balancer://rp01/

  <Proxy balancer://rp01/>
          BalancerMember http://web01:80 loadfactor=5
          BalancerMember http://web02:80 loadfactor=5
  </Proxy>
</VirtualHost>

#test設定
<VirtualHost *:80>
  ServerName test.xxx.com:80

  ProxyPass /balancer-manager !
  <Location /balancer-manager>
          SetHandler balancer-manager
  </Location>

  ProxyPass / balancer://test-rp01/ 
  ProxyPassReverse / balancer://test-rp01/

  <Proxy balancer://test-rp01/>
          BalancerMember http://web01:8000 loadfactor=5
          BalancerMember http://web02:8000 loadfactor=5
  </Proxy>
</VirtualHost>
```

loadfactorの数字を大きくすると、使用頻度が大きくなります。

web01・web02のapacheを交互に停止して、xxx.comにアクセスできたらロードバランサの設定が完了している。

## 余談

DTIのVPSを借りれば、月420円 * 5台 = 2100円で実現可能です。
DTIの場合、aaa.bbb.ccc.1とaaa.bbb.ccc.2のように、グローバルIPの４桁目以外が同じの場合は
セキュリティ上、通信が出来ないようです(T_T)