Vagrant＋Rails6＋PostgreSQL12(MySQL) 開発環境構築 まとめ

# 内容
- Vagrant+Rails6+PostgreSQL12の環境構築をしているとかなりハマったため、手順の忘備録と、出会ったエラーの対処が誰かの役に立てばと思い、まとめました
- 題名をPostgreSQLとしましたがMySQLを使用したいという方もそのまま進めていただける内容です


# 環境
- macOS Mojave 10.14.6
- VirtualBox 6.0.10
- Vagrant 2.2.5
- centos/7 (virtualbox, 1905.1)
- rbenv 1.1.2-4-g577f046
- ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]
- Rails 6.0.0
- psql (PostgreSQL) 12.0


# 目次
長くなったのでざっくり内容説明

1. 仮想環境を作る
    - vagrant init, Vagrantfile編集, SSH接続
2. 各種アップデート&インストール
    - yum, git, rbenv, Ruby, Node.js, RubyGems, Bundler, Rails, PostgreSQL
3. プロジェクトの作成
    - rails new
    - bundler install
        - [nokogiriエラー](#321-bundle-install時のエラー)
        - [pgエラー](#321-bundle-install時のエラー)
    - db:create
        - [role "vagrant"エラー](#db作成時のエラー)
4. サーバー起動
    - [webpackerエラー](#サーバー起動時のwebpakerエラーrails6のみ)


# 1. 仮想環境を作る

```sh
$ vagrant init 
```


## 1.2. Vagrantfile編集

```sh:Vagrantfile
#-*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  
  ...
  config.vm.box = "centos/7"
  ...
  config.vm.network "forwarded_port", guest: 2000, host: 3000
  ...
  config.vm.network "private_network", ip: "192.168.33.10"
  ...
  config.vm.synced_folder "~/MyVagrant/sample_app", "/share"
```



## 1.3. 起動とSSH接続

```sh
# 設定変更したのでリロード
$ vagrant reload
# 起動
$ vagrant up
# SSH接続
$ vagrant ssh
```



## 1.4. 時刻設定
centOSの時刻をUTCからJSTへ変更

```sh
$ sudo timedatectl set-timezone Asia/Tokyo
```



# 2. 各種インストール

## 2.1. yumアップデート&パッケージインストール

```sh
# yumを最新版にアップデート
$ sudo yum -y update

# 必要なパッケージをインストール
$ sudo yum -y install git-all openssl-devel readline-devel sqlite gcc gcc-c++
```


## 2.2. git インストール

```sh
# git
$ sudo yum -y install gcccurl-devel expat-devel gettext-devel openssl-devel zlib-devel perl-ExtUtils-MakeMaker
```



## 2.3. rbenvインストール
rubyのバージョン管理
開発の環境によってrubyのバージョンを管理できる

```sh
# rbenv導入
$ git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

# pathを通す
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
$ echo 'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(rbenv init -)"' >> ~/.bashrc
$ echo 'gem: --no-ri --no-rdoc' > ~/.gemrc
$ exec $SHELL

# 確認
$ rbenv -v
rbenv 1.1.2-4-g577f046
```


## 2.4 Rubyインストール
rbenvを使ってrubyをインストール
[公式](https://www.ruby-lang.org/ja/downloads/)から最新の安定版が確認可能

```sh
# 次のコマンドでrbenv上で安定で最新のものを確認
$ rbenv install --list

# 最新版をインストール
$ rbenv install 2.6.5
# 時間がかかりすぎる場合は下記コマンドで時短可能
# (参考) https://qiita.com/yn-misaki/items/23ff4e0f1268511aed41
$ sudo yum install -y https://github.com/feedforce/ruby-rpm/releases/download/2.6.5/ruby-2.6.5-1.el7.centos.x86_64.rpm

# rbenvにインストールされているversionをリストで表示
$ rbenv versions

# 環境全体のRubyバージョンを指定
$ rbenv global 2.6.5

# 特定のプロジェクトだけで指定したい場合
# localの場合は適用したいプロジェクト内で実行する
$ rbenv local 2.6.5

# どこで管理されているrubyを使用しているかを確認
$ which ruby
```

## 2.5. Node.jsインストール

```sh
$ sudo rpm -Uvh https://rpm.nodesource.com/pub_4.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm
$ sudo yum -y install nodejs
```


## 2.6. RubyGemsアップデート
Rubyと一緒にインストールされる
gemを管理するパッケージ管理ツールであり、これを最新にアップデートしておく

```sh
# アップデート
$ gem update --install

# 現在のバージョンを確認
$ gem -v

# 既にインストールされているリストを確認
$ gem list
```


## 2.7. Bundlerインストール
- gemの依存性を解消し、パッケージの種類やバージョンを管理するパッケージ管理ツール
- `gem install`ではグローバルにインストールされるが、`bundle install`ではRubyバージョンごとに管理され、ローカルにもインストールが可能


```sh
# bunderインストール
$ gem install bundler
```

### (補足)各種コマンド
プロジェクトごとにbundlergでemを管理する場合はGemfileに必要なものを記述していき、それをインストールすることで使えるようになる

- Gemfileの生成(`rails new`したときは自動で生成される)

```sh
bundle init
```

- Gemfileに記載されたgemをインストール
    - 保存場所を指定しなければ`$HOME/.rbenv/versions/2.x.x/lib/ruby/gems/2.x.x/gems`に保存される

```sh
# 保存場所を指定しない
bundle install 

# 保存場所を指定する
bundle install --path vendor/bundle
```

- bundlerでインスールされ、管理されているgemを実行

```sh
$ bin/rails {コマンド}
# or 
$ bundle exec {コマンド}
```

## 2.8. Railsインストール

[公式サイト](https://rubyonrails.org)から適用したいrailsのバージョンを確認
今回はRails6を選択

```sh
# Railsインストール
$ gem install rails -v 6.0.0

# 確認
$ rails -v
```


## 2.9. PostgreSQLインストール
MySQLをインストールする場合は2.9を飛ばし、下記を参考にしてください
[Vagrant＋Rails6＋MySQL 開発環境構築](https://qiita.com/KZ-taran/items/cc0802e28d538cf60e61)


### (補足)PostgreSQLインストールの前に導入済みの場合で削除したい場合

```sh
# PostgreSQLが導入されているか確認
$ rpm -qa | grep postgres

# PostgreSQLが存在していたら削除
$ sudo yum -y remove postgresql
```

### 2.9.1. PostgreSQLインストール

- 今回は最新のPostgreSQL12をインストールする
- [公式サイト](https://www.postgresql.org/download/linux/redhat/)からリポジトリRPMインストール
- 赤で囲った部分(1, 2, 3)を選択すればインストール用コマンドが出現するため、そのままコマンド入力していく(4, 5, 6, 7)
![スクリーンショット 2019-10-19 14.54.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449626/81bad9bb-90e3-d5db-0998-e585277b7b6a.png)


```sh
# リポジトリRPMインストール
$ sudo yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm

# client packageインストール
$ sudo yum install postgresql12
# server packageインストール
$ sudo yum install postgresql12-server
```

### 2.9.2. PostgreSQL初期化
PostgreSQLのデータベースクラスタを作成

```sh
$ sudo /usr/pgsql-12/bin/postgresql-12-setup initdb

# 確認
$ psql --version
# psql (PostgreSQL) 12.0
```

(補足) initdb(初期化)をやり直したい場合`/var/lib/pgsql`の中身をすべて削除後にコマンド実行


### 2.9.3. 実行停止

```sh
# 実行
$ sudo systemctl start postgresql-12
# 停止
$ sudo systemctl stop postgresql-12
# 再起動
$ sudo systemctl reload postgresql-12
# 起動されているか確認
$ sudo systemctl status postgresql-12

# OS起動時に自動起動するように設定
$ sudo systemctl enable postgresql-12
# 自動起動の停止
$ sudo systemctl disable postgresql-12
# 自動起動が有効か確認
$ systemctl is-enabled postgresql-12
```

### 2.9.4. 必要に応じて初期設定
#### 外部サーバーからのアクセスを許可する場合
`/var/lib/pgsql/12/data/postgresql.conf`でデフォルトでlocalhost(127.0.0.1)のみ許可となっているため次のように設定する

```sh
$ sudo cat /var/lib/pgsql/12/data/postgresql.conf 
```

```sh:/var/lib/pgsql/12/data/postgresql.conf
(編集前)
#listen_addresses = 'localhost'

(編集後)
listen_addresses = '*'
```

#### ポート番号を変更する場合
デフォルトでは5432となっているため同様に`/var/lib/pgsql/12/data/postgresql.conf`を編集する
変更しない場合でもコメントアウトは外しておく

```sh:/var/lib/pgsql/12/data/postgresql.conf
(編集前)
#port 5432

(編集後)
port xxxx
```

#### ログ出力のprefixを変更する場合
同様に`/var/lib/pgsql/12/data/postgresql.conf`を編集

```sh
(編集前)
log_line_prefix = '< %m >'

(編集後)
log_line_prefix = '< %t %u %d >'
```

#### クライアントの認証設定(外部接続の条件を設定)
※ こちらの設定で「すべて許可」等の設定は本番環境では危険ですので開発時のみで理解した上で使用しましょう

`/var/lib/pgsql/12/data/pg_hba.conf`の内容を編集する

```sh
$ sudo vi /var/lib/pgsql/12/data/pg_hba.conf
```

下記の認証設定では上から順番に優先される

```sh:/var/lib/pgsql/12/data/pg_hba.conf
(編集前)
# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
host    all             all             127.0.0.1/32            ident
# IPv6 local connections:
host    all             all             ::1/128                 ident


(編集後1)　特定のIPのみ、外部接続を無条件に許可（パスワード無しに）する場合
# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
- host    all             all           127.0.0.1/32            ident
+ host    all             all           {接続許可するIP}/32       trust
# IPv6 local connections:
host    all             all             ::1/128                 ident


(編集後2) すべてのアクセスを許可する場合
# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
- host    all             all           127.0.0.1/32            ident
+ host    all             all           0.0.0.0/0               trust
# IPv6 local connections:
host    all             all             ::1/128                 ident
```

**編集項目の内容**

- TYPE（接続方式)
    - local: UNIXドメインソケットで接続した場合
    - host: TCP/IPで接続した場合
- DATABASE(接続DB)
    - all: すべてのDBを指定
    - DB名を入力
- USER(接続USER)
    - all: すべてのユーザ指定
    - 接続USER名を入力
- ADDRESS(接続元のIPアドレス)
    - 接続元のIPアドレスを入力
- METHOD(認証方式)
    - trust: すべて許可
    - reject: すべて拒否
    - md5: md5暗号化によるパスワード認証
    - password: 平文によるパスワード認証
    - ident: UNIXで設定されている現在のユーザー名とPostgreSQLのユーザー名が一致した場合認証(TCP/IP接続のみ)
    - peer: UNIXで設定されている現在のユーザー名とPostgreSQLのユーザー名が一致した場合認証(local接続のみ)



#### 編集完了後は再起動

```sh
$ sudo systemctl restart postgresql-12
```


### 2.9.5. PostgreSQLに接続
PostgreSQL導入後はCentOS上にpostgresユーザーが自動で追加され、データベースpostgresとデータベース接続ユーザーpostgresも自動で作成される

#### 自動生成されたpostgresユーザーのパスワード設定

```sh
# 下記コマンド実行後、任意のパスワードを入力
$ sudo passwd postgres
```

### 2.9.6. ログイン

```sh
$ su - postgres
-bash-4.2$

# PostgreSQLのシェルにログイン(postgresという名称のDBにアクセス)
-bash-4.2$ psql -U postgres

# 次のように表示されればOK
psql (12.0)
Type "help" for help.
postgres=#
```


### (参考)
http://vdeep.net/centos7-postgres
http://note.kurodigi.com/centos7-postgresql/


# 3. プロジェクトの作成
## 3.1. プロジェクトの作成

```sh
# プロジェクトの作成
# オプション-dで利用するDB指定
$ rails new {名前} -d postgresql 

# 生成されたフォルダへ移動
$ cd {名前}
```

## 3.2. bundle install
```sh
# bundleインストール
$ bundle install --path /vendor/bundle
```

単に`bundle install`とコマンドを実行して、パスを指定しなければ `$HOME/.rbenv/versions/<current version>/lib/ruby/gems/<target version>/gems`にインストールされる
プロジェクト内の`/vendor/bundle`にインストールするようにパスを指定して管理するようにする


### 3.2.1. bundle install時のエラー
- **nokogiriがインストールできない場合**


```sh:エラー内容
An error occurred while installing nokogiri (1.10.4), and Bundler
cannot continue.
Make sure that `gem install nokogiri -v '1.10.4' --source
'https://rubygems.org/'` succeeds before bundling.
```

【解決】[Vagrant+Railsでbindle install時にnokogiriインストールできないエラー](https://qiita.com/KZ-taran/items/787136dc3d121c721c2c)



- **pgがインストールできない場合**

```sh:エラー内容
An error occurred while installing pg (1.1.4), and Bundler cannot
continue.
Make sure that `gem install pg -v '1.1.4' --source 'https://rubygems.org/'`
succeeds before bundling.
```

【解決】[Vagrant+Railsでbindle install時にpgインストールできないエラー](https://qiita.com/KZ-taran/items/ff988f67f8cedd89d5a5)



## 3.3. DB作成

2.9を飛ばしてMySQLをインストールした場合はDB作成の前に下記を参考にしてください

- [Vagrant＋Rails6＋MySQL 開発環境構築　**Railsで必要なパッケージをインストール**](https://qiita.com/KZ-taran/items/cc0802e28d538cf60e61#railsで必要なパッケージをインストール)
- [Vagrant＋Rails6＋MySQL 開発環境構築　**プロジェクト作成まで進んだらconfigファイルの編集**](https://qiita.com/KZ-taran/items/cc0802e28d538cf60e61#プロジェクト作成まで進んだらconfigファイルの編集)


```sh
# DB作成
# 自動生成されたconfig/database.ymlファイルに沿って作成される
$ bin/rails db:create
```

### DB作成時のエラー
DB作成時に次のようなエラーが表示される場合の対処

```sh:エラー内容
FATAL:  role "vagrant" does not exist
Couldn't create 'sample_app_development' database. Please check your configuration.
rails aborted!
ActiveRecord::NoDatabaseError: FATAL:  role "vagrant" does not exist
bin/rails:4:in `<main>'

Caused by:
PG::ConnectionBad: FATAL:  role "vagrant" does not exist
bin/rails:4:in `<main>'
Tasks: TOP => db:create
(See full trace by running task with --trace)
```

```sh:対処
# vagrantロールが存在しないと指摘されているためロールを追加する
# PostgreSQLのスーパーユーザーとして新規作成
$ su postgres
-bash-4.2$ createuser --superuser -P vagrant

# 再度db：createでok
$ bin/rails db:create
```

# 4. サーバー起動

```sh
# 起動
$ bin/rails server -b 0.0.0.0 -p 2000
# Vagrantfileで設定した通りのポートで接続可能となる
# http://localhost:3000/
```

## サーバー起動時のwebpakerエラー(Rails6のみ)

```sh:エラー内容
=> Booting Puma
=> Rails 6.0.0 application starting in development 
=> Run `rails server --help` for more startup options
RAILS_ENV=development environment is not defined in config/webpacker.yml, falling back to production environment
Exiting
Traceback (most recent call last):
...
略
...
/home/vagrant/share/vendor/bundle/ruby/2.6.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:91:in `rescue in load': Webpacker configuration file not found /share/sample_app/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /share/sample_app/config/webpacker.yml (RuntimeError)
```


【解決】[Rails6サーバー起動時webpackerエラー(Node.jsアップデート, yarnインストール)](https://qiita.com/KZ-taran/items/d4c6eb1a41e0abd5b448)

解決したら再度サーバー起動

```sh
# 起動
$ bin/rails server -b 0.0.0.0 -p 2000
```

![スクリーンショット 2019-10-19 17.14.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449626/8e4c7de8-e92c-1d1b-9f36-0713b03ef92c.png)

# 変更を反映させる
vagrant上ではデフォルトではファイルを変更した場合サーバーを再起動しないとブラウザ上に反映されない。
ファイルを変更した時にブラウザのリロードで変更を反映させる場合は`config/environments/development.rm`の内容を次のように変更する。
※browsersyncのような自動リロード機能ではない

```rb:config/environments/development.rm
  # Use an evented file watcher to asynchronously detect changes in source code,
  # routes, locales, etc. This feature depends on the listen gem.
- config.file_watcher = ActiveSupport::EventedFileUpdateChecker
+ config.file_watcher = ActiveSupport::FileUpdateChecker
```


# 参考
https://qiita.com/uu64/items/eb5f64e45a0e39f2dafb