ゼロからCloud9で制作したRoRプロジェクトをDigitalOceanへdeployする

#Github

登録しrepositoryを作成します。
今回は```capistrano-example```で作成します。

#Cloud9

Githubアカウントでログインできます。

##Workspace作成

Clone from Git or Mercurial URLは空のままにしておきます。
Choose a templateはBlank(旧Custom)を選びます。

railsを選ばないのは自動でプロジェクトを生成されないようにするためで、git repositoryを設定しないのはworkspaceのルートとrepositoryのルートが一致しないためです。

##PostgreSQL

DBの初期設定を行います。
今回は```my_app_name```で登録します。

```bash
$ sudo service postgresql start
$ sudo sudo -u postgres psql
```
```psql
postgres=# create role my_app_name with createdb login password 'PA$$W0rd';
```

Cloud9の初期で入っているモノはそのままだとエラーを出すのでdatabase templateを更新します。

>```psql
postgres# UPDATE pg_database SET datistemplate = FALSE WHERE datname = 'template1';
postgres# DROP DATABASE template1;
postgres# CREATE DATABASE template1 WITH TEMPLATE = template0 ENCODING = 'UNICODE';
postgres# UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'template1';
postgres# \c template1
postgres# VACUUM FREEZE;
postgres# \q
```
https://github.com/Aerogami/guides/wiki/Cloud9-workspace-setup-with-Rails-and-Postgresql

##RoRプロジェクトの作成

DBの名前等と合わせて```my_app_name```で生成します。

```bash
$ rails new my_app_name -TB --database=postgresql
$ cd my_app_name
```

##Git
```bash
$ git init
$ echo "config/secrets.yml" >> .gitignore
$ git add .
$ git commit -m "first commit"
$ git remote add origin git@github.com:USER/capistrano-example.git
$ git push origin master
```
これ以降の作業はブランチ切って行うと戻りやすいです。

##Bundler

```rb:Gemfile
#追加
group :development do
  gem 'capistrano-rails'
  gem 'capistrano-rvm'
  gem 'capistrano3-unicorn'
  gem 'dotenv-rails'
end

gem 'unicorn'
```

```bash
$ bundle install --path vendor/bundle
$ echo "vendor/bundle" >> .gitignore
```

##Database

```yaml:config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5
  # この３行を追加
  username: my_app_name
  password: <%= ENV['MY_APP_NAME_DATABASE_PASSWORD'] %>
  host: localhost

development:
  <<: *default
  database: my_app_name_development

test:
  <<: *default
  database: my_app_name_test

production:
  <<: *default
  database: my_app_name_production
  username: my_app_name
  password: <%= ENV['MY_APP_NAME_DATABASE_PASSWORD'] %>
```

##dotenv

```bash
$ vi .env
$ echo ".env" >> .gitignore
```

```:.env
MY_APP_NAME_DATABASE_PASSWORD='PA$$W0rd'
```

##動作確認

```bash
$ rake db:setup
$ rails g scaffold Post title:string body:text
$ rake db:migrate
$ rails s -b $IP -p $PORT
```

右上に表示されるURLをクリックするか上のメニューからPreview->Preview Running Applicationを選択すると該当ページを参照できます。

##unicorn
```bash
$ mkdir config/unicorn
$ vi config/unicorn/production.rb
```

```rb:config/unicorn/production.rb
# アプリ名を自身のものにする
root = "/home/rails/apps/my_app_name/current"
# ソケットをnginxと合わせる
# DigitalOceanの/etc/nginx/sites-enabled/rails参照
listen '/tmp/unicorn.my_app_name.sock', backlog: 64
worker_processes 4
# ユーザ名をDigitalOceanデフォルトのrailsにする
user "rails"
working_directory root
pid "#{root}/tmp/pids/unicorn.pid"
stderr_path "#{root}/log/unicorn.log"
stdout_path "#{root}/log/unicorn.log"
```

リンク先を参考にしつつDigitalOceanのデフォルト```/etc/unicorn.conf```を書き換えました。
https://gist.github.com/ChuckJHardy/f44dda5f94c6bbdba9a4

##Capistrano

```bash
$ bundle exec cap install
# 編集内容全体はリンク先を参照
$ vi Capfile
$ vi config/deploy.rb
$ vi config/deploy/production.rb
```

```rb:config/deploy.rb
# repositoryを設定
set :repo_url, 'git@github.com:USER/capistrano-example.git'

# databaseはDigitalOceanの環境変数で管理し、secretsはそれで管理できないのでgit管理外にしてdeploy時にアップロードする
set :linked_files, fetch(:linked_files, []).push('config/secrets.yml')

namespace :deploy do
  
  desc 'Upload secrets.yml'
  task :upload do
    on roles(:app) do |host|
      if test "[ ! -d #{shared_path}/config ]"
        execute "mkdir -p #{shared_path}/config"
      end
      upload!('config/secrets.yml', "#{shared_path}/config/secrets.yml")
    end
  end
  
  task :restart do
    invoke 'unicorn:reload'
  end
  
  before :starting, :upload
end
```

下記リンクを参考に```deploy:upload```を追加
http://chroju89.hatenablog.jp/entry/2014/04/12/215628

```rb:config/deploy/production.rb
#ユーザ名をDigitalOceanデフォルトのrailsにする
set :user, 'rails'

#DigitalOceanで作成したドロップレットのIPを指定する
server '123.333.333.333',

# ssh_optionsのuserもrailsにする
# user: 'deployer',
  user: fetch(:user),
```

上記設定の内repositoryの公開に疑問がある設定は全部```ENV['key_name']```に変換しましょう。Capistrano関連のファイルは```.env```ファイルに書いても適用されません。なので```/etc/profile.d/deploy.sh```等に```export SERVER_IP='123.333.333.333'```といった感じで記述してシェルを再起動してからdeployするようにしましょう。

https://gist.github.com/ChuckJHardy/f44dda5f94c6bbdba9a4

#完成

```bash
$ git push origin master
```

#DigitalOcean

有料ですので別のサービス利用の方は適宜対応してください。

##ドロップレットの作成

```Create Droplets```を選択し、```One-click Apps```から```Ruby on Rails```を選択します。

料金プランは一番安いのでも可能ですが後述のスワップ領域の作成を行う必要があります。

webコンソール以外を利用する場合は```Add your SSH keys
```の項目で作業端末の公開鍵を登録しておいてください。

##スワップ領域の確保

メモリが足りない場合は、リンク先の手順通り行えば問題は無くなります。
最安プラン採用時この手順を行わなかった場合```bundle install```した際に```out of memory```で中断されます。
また、この手順をせずにdeployするとここでハマってCPUが常にビジー状態になってsshすら弾かれるようになったので気を付けてください。

https://www.digitalocean.com/community/tutorials/how-to-add-swap-on-ubuntu-12-04

##鍵交換

```bash
# Cloud9側の公開鍵を取得する
$ cat ~/.ssh/id_rsa.pub

# Error reading response length from authentication socketにならないようにssh-agentを設定する
$ eval `ssh-agent -s`
$ ssh-add ~/.ssh/id_rsa
```

```bash
# DigitalOceanのドロップレットへ入る
$ ssh root@123.123.123.123
$ su rails
$ ssh-keygen
$ vi ~/.ssh/authorized_keys
# Cloud9の公開鍵を設定

$ cat ~/.ssh/id_rsa.pub
# 公開鍵をgithubに登録
```

##unicorn

稼働しているソケットを確認します。

```bash
$ ps auxf | grep unicorn | grep -v grep
root      1562  0.0  2.4  77696 12356 ?        Sl   01:33   0:00 unicorn master -D -c /etc/unicorn.conf -E production
$ vi /etc/unicorn.conf
listen "unix:/var/run/unicorn.sock"

#デフォルトのunicornプロセスは停止させておく
$ kill -QUIT 1562
```

　```/var/run/unicorn.sock```で稼働している事が分かったので```/etc/unicorn.conf```を参考にunicornの設定を書きました。

##Nginx

```:/etc/nginx/sites-enabled/rails
upstream app_server {
  server unix:/tmp/unicorn.my_app_name.sock fail_timeout=0;
}
```

```bash
$ sudo service nginx restart
```

##PostgreSQL

DigitalOcean側のDBの初期設定を行います。
Cloud9と同じ```my_app_name```で登録します。

```bash
$ sudo -u postgres psql
```
```psql
postgres=# create role my_app_name with createdb login password 'PA$$W0rd';
postgres=# create database my_app_name_production owner my_app_name;
```

##環境変数

```bash
$ sudo vi /etc/environment
# MY_APP_NAME_DATABASE_PASSWORD='PA$$W0rd' # ADD
```

リンク先にもっと良いやり方が書いてあるような気がするのですが、試してみても上手くいきませんでした。
http://stackoverflow.com/questions/23672631/capistrano-and-environment-variables

#Cloud9からデプロイ

```bash
$ rake secret
$ vi config/secrets.yml
# 環境変数なり直書きなりでproductionのsecret_key_baseを設定する
$ bin/bundle exec cap production deploy
```