RailsをGCEにcapistranoを使ってdeployする (CentOS、Nginx、Puma）

- RailsをGCEにdeployして公開するまでの手順を記事にしたいと思い書きました。
- 今回の記事では単一のGCEインスタンスにdeployするまでです。
- GCP(GCE、VPC)
- ruby 2.6.5
- rails 6.0.0 (今回railsアプリはapiモードで作成し、DB接続しない前提です。）
- CentOS7
- Nginx
- puma
- capistrano
 
#### 必要であればVPCでカスタムネットワークと、ssh接続やhttp接続するなら、そのportを開けるファイアウォールを作ります。
- GCPは、カスタムネットワークを設定しない場合、デフォルトのネットワークが使われる。個人開発であればデフォルトネットワークでも構わないと思います。
- GCE立ち上げ時にhttp通信の許可にチェックするでもいいですが、自宅やオフィスなどアクセスするIPが決まっているなら、そのIPからのみアクセスできるファイアウォールを作成するなどして開発すると良いと思います。

## GCEにCentOS 7のインスタンスを作成します。
- USのリージョンで、1系のAZ(us-west1など)かつ、インスタンスタイプがmicroであれば無料ですが、railsを動かす場合など最初のrubyのinstallの時にメモリ不足なるので、最初はsmallタイプ以上で立ち上げた方が早いです。(microでswapを作っても良い)
- CentOS 7のディスクタイプを選択します。標準の永続ディスクで30GBまで無料です。

- とりあえず、http通信させるなら、http通信にチェックを入れます。
- デフォルトで、GIPがエフェメラルに作成されます。VMインスタンスのネットワークインターフェイスの設定で、GIPや内部IPを静的にしたり、削除したりもできます。
- エフェメラルは短命なという意味で、エフェメラルなIPはインスタンスを停止すると変更される場合があります。
- ちなみGCEはインスタンスを作成したユーザーはsudo権限がついた状態になります。

## インスタンスの設定
## TZの設定
- 必要であれば日本時間に変更します。

```
$ date # 日時確認
$ sudo timedatectl # 設定内容確認
$ sudo timedatectl set-timezone Asia/Tokyo # Asia/Tokyoに設定
```

## ユーザー作成
- 必要であればdeploy用のユーザーを作成します。

```
### deployユーザ作成
$ sudo adduser deploy

### sudo権限の付与。gceの場合、sudo グループは無くて、google-sudoers がある。
$ sudo gpasswd -a deploy google-sudoers

### deployユーザーに切り替え
$ sudo su - deploy
```

## 必要なpackageのinstall
```
### 既存packageのupdate
$ sudo yum update

### よく使用するpackage や、ruby rails で必要なpackage のinstall 
$ sudo yum install nkf wget git bzip2
$ sudo yum install gcc-c++ glibc-headers openssl-devel libyaml-devel readline-devel  zlib-devel libffi-devel libxml2-devel libxslt-devel libicu-devel libcurl-devel cmake

### mysql(mysqlを使う場合)
$ sudo yum install mysql-devel

### インストール済みpackage確認
$ sudo yum list installed # 
```

## nginxのinstall
- [nginxの初期設定参考サイト](https://weblabo.oscasierra.net/nginx-centos7-install/)
- 上記のURLにある手順で行えば初期設定は完了です。（リポジトリの追加は必ず行います）

```
### install(yum)
$ sudo yum install nginx

### nginx起動
$ sudo systemctl start nginx

### nginx自動起動
$ sudo systemctl enable nginx
```
- nginxが起動できていれば、GCEのGIPをブラウザでたたくとnginxの初期画面が表示されます。

## rbenv と ruby
- [rbenv参考サイト](https://crowrabbit.hatenablog.com/entry/2019/04/06/CentOS7%E3%81%ABrbenv%E3%82%92%E5%B0%8E%E5%85%A5)

```
### rbenv をclone
$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv 
### 以下を .bash_profile に設定
$ export PATH="$HOME/.rbenv/bin:$PATH"
$ eval "$(rbenv init -)"

### .bash_profileの読み込み
$ source ~/.bash_profile

### rbenv確認
$ rbenv -v

### ruby-buildをcloneし、設定。
$ git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
$ sudo ~/.rbenv/plugins/ruby-build/install.sh

### インストールできるrubyのバージョンの一覧確認
$ rbenv install -l

### 確認したruby-versionをinstall
$ rbenv install 2.6.5

### global設定
$ rbenv global 2.6.5

### ruby確認
$ ruby -v
```

## bundler
```
### bundlerのinstall
$ rbenv exec gem install bundler
```

## ssh接続系
- ssh-keyの発行と設定に関しては割愛しますが、GitHubとの接続や、capistranoの設定で使います。
- GCEインスタンスにアクセスする方法は色々あり、GCPのコンソールから対象GCEインスタンスでブラウザでの接続や、ローカル環境のgcloudの設定をしていれば、gcloudコマンドで接続できます。また、一度gcloudコマンド接続していれば、 `google_compute_engine` と `google_compute_engine.pub`ファイルが作成されssh接続も可能です。

## capistrano 関連
- [capistranoでdeploy](https://www.kumilog.net/entry/cap-deploy)
- 上記のサイトが参考になります。
- 何も設定しなければmaster-branchがdeploy対象
- 各環境の設定ファイル `config/deploy/production.rb` などのssh オプションはdepoly対象のserverに接続するためのssh秘密鍵を設定します。


```ruby
### capistrano関連のGemを設定する。
### Gemfile
group :development, :test do
  gem "capistrano", "~> 3.11", require: false
  gem "capistrano-rails", "~> 1.4", require: false
  gem 'capistrano-bundler', '~> 1.5', require: false
  gem 'capistrano-rbenv', '~> 2.1', require: false
  gem 'capistrano3-puma', require: false
end
```
- `bundle exec cap install` を実行して `Capfile` を生成し、編集します。

```
### Capfile
require "capistrano/rbenv"
require "capistrano/bundler"
require "capistrano/rails/assets"
require "capistrano/rails/migrations"
require 'capistrano/puma'
install_plugin Capistrano::Puma
install_plugin Capistrano::Puma::Nginx
```

- capistrano-rbenv はdeploy対象serverでもrbenvでrubyを管理している前提で、使用するruby versionを設定する。
- capistrano-rails は、deploy時のAssetsのコンパイルやmigrationの実行を設定できる。
- capistrano-bundler はdeployの際にbundle installを実行してくれる。
- capistrano3-puma はpumaの設定をdeploy先に反映させたり、deployの際にpumaの再起動を実行したりしてくれる。

### production deploy コマンド
```
$ bundle exec cap production deploy
```
- そのほか便利なcapistranoコマンド

```
### /var/www/myapp/shared/puma.rb に設定ファイルがアップロード
$ bundle exec cap production puma:config
```
```
### cap コマンド確認
$ bundle exec cap -T
```
```
### puma再起動
$ bundle exec cap production puma:restart
```

## nginx 設定
- `/etc/nginx` がnginxの設定ファイルなどが設置されているディレクトリです。

- `/etc/nginx/nginx.conf` の userをrailsアプリのユーザに変更します。

```
### nginx.conf
#user  nginx;
user  deploy;
```
- `/etc/nginx/conf.d` 以下に自分のアプリ用のconfファイルを作成します。 
- `例: /etc/nginx/conf.d/myapp.conf`
- 下記のnginxの設定でrailsアプリとのアクセスはできます。細かい設定に関してはしていないです。

```
upstream backend {
  server unix:///var/www/myapp/shared/tmp/sockets/puma.sock;
}
server {
    # 80番ポートを許可
    listen 80;

    # host-IPを指定
    server_name host-IP;

    # 静的ファイルのパスをドキュメントルートに設定
    root   /var/www/myapp/public;

    location / {
      try_files $uri @app;
    }

    # 上記の@appが呼び出された場合のみ以下の設定を読み込む
    location @app {
        proxy_pass http://backend;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
    }
}
```

## master.keyの設定
- 必要であればmaster.keyを本番serverに設定します。
- `master.key` を `shared/config` 以下にscpで送信しておき、`config/deploy.rb` を編集します。

```ruby
append :linked_files, "config/master.key"
```

- ここまでの設定で問題なければ、GCEインスタンスのGIPをブラウザでたたくとdeployしたrailsの画面が表示されると思います。

## 上手くいかない場合確認するところ
### deployが失敗する場合
- deployが失敗する場合、標準出力のlogもしくは、`log/capistrano.log` を確認しどこで失敗しているかとそのエラー内容を見て対応します。
- 多いのが sshの権限やGithubにアクセスできないなどです。ローカルやdeploy用serverから本番server(deploy対象server)にssh接続できるかどうかの確認やGitHubと接続できるかを確かめます。
- またファイアウォールの設定が間違っていないかを確認します。

### deployはできたが、アプリがエラーになる場合
- deploy対象serverでlogの確認や、プロセスの確認を行います。
- ` /var/log/nginx 以下 nginxのログ`
- ` production.log puma_access.log などのrailsのログ` 
- 上記のログファイルでもエラーログを見て確認します。
- nginx でよくあるエラーで、 `failed (13: Permission denied)` このエラーが出ている場合、SELinuxを無効にすると改善される場合があります。[SELinux設定変更](http://dqn.sakusakutto.jp/2016/04/nginx_open_failed_permission_denied.html)
- プロセスの確認はpsやgrepなどを使って確認することもできます。

```
$ ps aux | grep 'puma'
deploy   23668  0.0  4.0 699108 69916 ?        Sl   01:40   0:01 puma 3.12.1 (unix:///var/www/myapp/shared/tmp/sockets/puma.sock)

$ ps aux | grep 'nginx'
root      2970  0.0  0.1  46592  2020 ?        Ss   Nov07   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
deploy   21695  0.0  0.1  46988  2304 ?        S    01:08   0:00 nginx: worker process
```

##### 参考URL
- [nginxの初期設定](https://weblabo.oscasierra.net/nginx-centos7-install/)
- [rbenv設定](https://crowrabbit.hatenablog.com/entry/2019/04/06/CentOS7%E3%81%ABrbenv%E3%82%92%E5%B0%8E%E5%85%A5)
- [capistranoでdeploy](https://www.kumilog.net/entry/cap-deploy)
- [SELinux設定変更](http://dqn.sakusakutto.jp/2016/04/nginx_open_failed_permission_denied.html)

- 次回の記事で、ロードバランシングとオートスケールの設定について書きたいと思います。
- 間違っている点などありましたらコメントいただけると助かります。