ConoHa VPS(CentOS 8.2)に Rails 6 + PostgreSQL + Nginx + Unicorn + Capistrano でデプロイする
September 3, 2020
前置き #
初デプロイ時に相当苦労し、調べに調べてなんとかデプロイ完了まで漕ぎ着けました(デプロイするのに数日間…)。作業中は手順を逐一記録しており、それらをデプロイ完了後に改めて整理したのが本記事の手順です。本手順を作成した後で一度 VPS を削除し、改めてゼロから本手順に通りに作業したところ、無事にデプロイができました。そのため、ある程度信頼できる手順になっているのではないかと思います。なおローカル環境については Mac でターミナルを使用して作業を進めています。
また、パッケージのインストール部分について補足しておきます。
パッケージ(PostgreSQL など)をインストールする部分では、CentOS (今回は 8.2)の標準リポジトリからインストールできるバージョンを利用しています。つまり、パッケージのバージョンは特に指定せず、その時に CentOS が標準でインストールするものを導入する形です。ただしこの場合、必ずしも最新版のパッケージがインストールされるわけではありません。例えば、本記事作成時点の PostgreSQL 最新版は 12 ですが、CentOS 8.2 の標準だと 10 がインストールされます。
パッケージ開発元のリポジトリから最新版を指定してインストールすることもできるのですが、その場合はバージョンを明示する必要があったりと、今後さらにバージョンが変わっていった時に、手順の内容が使えない(古い)ものになったために不用意なエラーが起こる可能性があります。今回は手順の汎用性を考慮して全て CentOS 標準のバージョンをインストールしています。
CentOS 標準のバージョンで困ることは無いと考えていますが、もしも最新版を使いたい場合は、一度本手順に沿ってデプロイまで済ませた後、個別にバージョンを変更するのが安定しているかと思います。
いずれにせよ、初学者にとってはデプロイするというハードルを超えるのが一苦労なので、そこまでたどり着くことが本手順の第一目的です。
以上、前置きでした。それでは以下が手順です。
1.ConoHa の VPS を契約する #
メモリ等のプランは任意。私は以下を選択。
- リージョン:東京、メモリ:1 GB、CPU:2 Core、SSD:100GB、880 円/月
- イメージタイプ:CentOS 8.2(64bit)
- root パスワード:任意のパスワード
- ネームタグ:任意のネーム
- 追加オプション:全てデフォルトのまま(例:SSH Key 使用しない)
以降、VPS のことをサーバと記載。
2.サーバにログインする #
1で作成したサーバの詳細ページを開き、IP アドレスを確認。その後、ターミナルから以下のコマンドでサーバに接続。
ssh root@IPアドレス
その後、
The authenticity of host IPアドレス can't be established.
ECDSA key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
上記のように、known hosts に追加するかと聞かれるので、yes と入力し回答。
これでローカルの ~/.ssh/known_hosts
にある known hosts ファイルに追記される。
その後パスワードを求められるので、1で設定した root パスワードを入力してログイン。
3.作業用ユーザを作成する #
今後のために、ここで作業用ユーザを作成。
以下コマンドで新規ユーザ作成。
adduser ユーザ名
ここで作成したユーザのことを、以降は作業用ユーザと記載する。
その後、パスワードを設定。
passwd 作業用ユーザ名
root 権限(sudo 権限)を付与するために、設定ファイルを開く。
visudo
以下の部分を探す。
## Allow root to run any commands anywhere
root ALL=(ALL) ALL
キーボードの i を押下して挿入モードに移行し、上記を下記の通り更新。
## Allow root to run any commands anywhere
root ALL=(ALL) ALL
作業用ユーザ名 ALL=(ALL) ALL
ESC キーを押下してコマンドモードに戻り、その後、:wq
を入力しエンターで、ファイルを保存。
sudo 実行時に、パスワード入力を求められないように設定を変えるため、再び設定ファイルを開く。
visudo
以下の部分を探す。
## Same thing without a password
# %wheel ALL=(ALL) NOPASSWD: ALL
先ほどと同様に操作し、上記を下記の通り更新して保存。
## Same thing without a password
# %wheel ALL=(ALL) NOPASSWD: ALL
%作業用ユーザ名 ALL=(ALL) NOPASSWD: ALL
ここまでの設定ができているかを確認する。作成したユーザにスイッチしてから、sudo コマンドを使用してみる。
su 作成したユーザ名
sudo echo test
上記実行後、パスワード入力を求められずに、test とだけ表示されれば OK.
ここまで完了したら、exit で一度サーバから抜けて、作成したユーザでログインできることを確認する。
exit
exit
ssh 作成したユーザ名@IPアドレス
ユーザ作成後に設定したパスワードを入力し、ログインする。
その後、root によるログインを不許可にしておくため、下記で設定ファイルを開く。
sudo vi /etc/ssh/sshd_config
下記の記載を探す。
# Authentication:
#LoginGraceTime 2m
PermitRootLogin yes
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
上記のうち、PermitRootLogin の部分を no に変えて、下記の通りとして保存する。
# Authentication:
#LoginGraceTime 2m
PermitRootLogin no
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
設定を反映させるために sshd のデーモンを再起動し、設定を読み込ませる。以下のコマンドを実行。
sudo systemctl restart sshd
一度サーバから抜けて、root でログインを試してみると、正しいパスワードを入力しても、Permission denied となってログインできなくなっている。
4.Git をインストールする #
3で作業用ユーザをせっかく作成したわけだが、一回一回 sudo するのが手間のため、以降は root ユーザで作業をしていく。
作業用ユーザでサーバにログイン後、root ユーザへスイッチ。
su root
その後、サーバで下記を実行し、Git をインストール。
*メモ:CentOS 8 では、パッケージ管理システムとして Yum ではなく DNF が使われている(DNF は Yum の事実上の後継)。現状、引き続き yum コマンドを使用することもできるが、yum コマンドを入力しても内部的には dnf が呼び出されており、将来的に yum は廃止されるため、以降使用するのは dnf コマンドに統一しておく。(といっても、yum と打つところを dnf と打つだけの違い。)
dnf -y install git
ちゃんとインストールできたか確認する。下記のコマンドを実行。
git --version
git version 2.18.4 などとバージョンが表示されれば OK.
5.rbenv をインストールする #
下記を実行。リモートの rbenv リポジトリを/usr/local/rbenv というディレクトリにクローンしている。
git clone https://github.com/rbenv/rbenv.git /usr/local/rbenv
次にパスを通す(環境変数を設定する)ため、ファイルを作成する。
vi /etc/profile.d/rbenv.sh
ファイルが作られ、開かれるので下記を記述する。
export RBENV_ROOT=/usr/local/rbenv
export PATH="$RBENV_ROOT/bin:$PATH"
eval "$(rbenv init -)"
そして、設定ファイルを読み込ませるために以下を実行。
source /etc/profile.d/rbenv.sh
その後、ちゃんとインストールできたか確認する。
rbenv --version
rbenv 1.1.2 などとバージョンが表示されれば OK.
6.ruby-build をインストールする #
root ユーザで下記を実行。ruby-build は、rbenv でインストールを実行するときに必要なプラグイン。
git clone https://github.com/rbenv/ruby-build.git /usr/local/rbenv/plugins/ruby-build
7.開発パッケージをインストールする #
Ruby をインストールするために必要なパッケージをインストールする。
dnf -y groupinstall "Development Tools"
dnf -y install gcc gcc-c++ glibc-headers openssl-devel readline readline-devel zlib zlib-devel libffi-devel libxml2 libxml2-devel libxslt libxslt-devel mysql-devel bzip2
2つ目のコマンドの中で、1つ目のコマンドでインストールしたものと重複するものが含まれている場合があるが、その場合は未インストールのものだけを自動的にインストールしてくれるので、そこまで気にしなくても大丈夫。
8.Ruby をインストールする #
以下を入力して、rbenv でインストールできる Ruby のバージョン一覧を表示する。
rbenv install -list
表示される結果例は下記の通り。
2.5.8
2.6.6
2.7.1
jruby-9.2.13.0
maglev-1.0.0
mruby-2.1.2
rbx-5.0
truffleruby-20.2.0
truffleruby+graalvm-20.2.0
Ruby をインストールする。バージョンはローカルで使っているものを指定。私の場合は 2.7.1 をインストールする。下記を実行。
rbenv install 2.7.1
インストールにはそれなりに時間がかかるので、気長に。
ちゃんとインストールされたかを確認する。
rbenv versions
2.7.1 などと表示されれば OK.
次にサーバで利用する Ruby の使用バージョンを設定する。
rbenv global 2.7.1
rbenv rehash
設定できているか確認する。
ruby -v
2.7.1 と表示されていれば OK.
次に、作業用ユーザでも同様のことを行う。作業用ユーザに戻す。
exit
さらに以下を入力し、ディレクトリを移動。
cd /usr/local/rbenv/
事前確認のため、以下を実行。
ls -la
ファイルやフォルダの所有者が全て root になっていることを確認。続いて、以下を実行。
sudo chown 作業用ユーザ名 version
sudo chown 作業用ユーザ名 shims
その後、再度以下を実行。
ls -la
version と shims の所有ユーザが作業用ユーザ名に変更されていることを確認する。
一度サーバからログアウトし、改めて作業用ユーザでログインする。その後、さらに以下を実行。
rbenv global 2.7.1
rbenv rehash
最後に、以下を入力し、設定を確認。
ruby -v
2.7.1 と表示されていれば OK.
9.Bundler をインストールする #
root ユーザにスイッチする。
su root
そして以下のコマンドを実行。
rbenv exec gem install bundler
rbenv rehash
インストールできているか確認する。
which bundler
上記入力後、/usr/local/rbenv/shims/bundler と返ってくれば OK.
10.Node.js をインストールする #
以降、引き続き root ユーザのまま。インストールを実行。
dnf install -y nodejs
インストールできていることを確認する。
node -v
v10.21.0 などとバージョンが表示されれば OK.
11.Yarn をインストールする #
以下を実行。
npm install -g yarn
インストールできていることを確認する。
yarn -v
1.22.5 などとバージョンが表示されれば OK.
12.PostgreSQL をインストールする #
以下を実行。
dnf install -y postgresql postgresql-server postgresql-devel postgresql-contrib postgresql-docs
postgresql-setup initdb
OS 起動時に PostgreSQL も自動起動するように設定。
systemctl enable postgresql
自動起動設定できたことを確認。
systemctl is-enabled postgresql
enabled であれば OK.
現時点では PostgreSQL は起動していないため、起動させる。
systemctl start postgresql
インストールできたことを確認。
psql --version
psql (PostgreSQL) 10.6 などと表示されれば OK.
さらに、PostgreSQL が起動していることを確認する。
systemctl status postgresql
active (running)になっていれば OK.
次に PostgreSQL の設定を変える。下記を実行してファイルを開く。
vi /var/lib/pgsql/data/postgresql.conf
CONNECTIONS AND AUTHENTICATION の項目にある以下
#listen_addresses = 'localhost'
のコメントアウトを解除して下記の通り変更する。
listen_addresses = '*'
変更後、さらにもう1つファイルを開く。
vi /var/lib/pgsql/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
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all peer
host replication all 127.0.0.1/32 ident
host replication all ::1/128 ident
次のように変更する。(途中3行をコメントアウト、最終行に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
# IPv6 local connections:
# host all all ::1/128 ident
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all peer
host replication all 127.0.0.1/32 ident
host replication all ::1/128 ident
local all all trust
host all all 0.0.0.0/0 md5
設定を反映させるため、PostgreSQL を再起動する。
systemctl restart postgresql
13.Rails アプリで使用する DB を作成する #
一度ターミナルから目を離し、デプロイしたい Rails アプリの config/database.yml を開いてファイル内の以下の記述を確認する。
production:
<<: *default
database: test_production
username: test
password: <%= ENV['TEST_DATABASE_PASSWORD'] %>
“test"の部分は rails new した時のプロジェクト名が設定されている。
その後、ターミナルに戻って以下の作業。
PostgreSQL にデフォルトで作られている、postgres というユーザを使って PostgreSQL に接続する。
psql -U postgres
と入力し、プロンプトが postgres=# となったことを確認する。
その後、以下コマンドによりロールを作成したいのだが、
CREATE ROLE "ロール名" WITH SUPERUSER LOGIN;
“ロール名"の部分には、config/database.yml の username に書いてある名称を記述する。今回の例では test なので、
CREATE ROLE "test" WITH SUPERUSER LOGIN;
となる。これを入力して実行する。
次に、以下コマンドによりデータベースを作成したいのだが、
CREATE DATABASE "データベース名"
“データベース名"の部分には、config/database.yml の database に書いてある名称を記述する。今回の例では test_production なので、
CREATE DATABASE "test_production";
となる。これを入力して実行する。
データベースの操作はこれで終わりなので、
\q
と入力して、PostgreSQL から抜ける。
最後に、PostgreSQL を再起動しておく。
systemctl restart postgresql
14.Nginx をインストールする #
以下のコマンドを実行。
dnf -y install nginx
インストールされていることを確認。
nginx -v
nginx version: nginx/1.14.1 などと表示されれば OK.
次に以下を実行して、OS 起動時に Nginx も自動起動するよう設定しておく。
systemctl enable nginx
自動起動設定できたことを確認。
systemctl is-enabled nginx
enabled であれば OK.
次に以下を実行して、Nginx を起動する。
systemctl start nginx
Nginx が起動していることを確認する。
systemctl status nginx
active (running)になっていれば OK.
次に、Nginx に http で接続できるように、firewalld の 80 番ポートを開放する。
firewall-cmd --add-service=http --permanent
firewalld をリロードする。
firewall-cmd --reload
その後、ウェブブラウザを開いてサーバの IP アドレスを入力して接続し、「Welcome to nginx」が出れば OK.
15.Capistrano でデプロイできるようにする #
15 − 1.サーバと GitHub で SSH 接続できるようにする #
Capistrano を使うために、サーバと GitHub 間で SSH 接続できるようにする。
ここで作業用ユーザに戻る。
exit
ホームディレクトリに移動。
cd
その後、以下で公開鍵と秘密鍵を作成。
ssh-keygen -t rsa
この時、
Enter file in which to save the key (/home/devsup/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
と聞かれるが、全てそのまま Enger を押下すれば OK.
次に、以下を入力し、公開鍵の中身を表示する。
cat ~/.ssh/id_rsa.pub
すると、
ssh-rsa XXXX...= ユーザ名@IPアドレス
といったものが表示されるので、ssh-rsa から最後の IP アドレスまで全てをコピー。
その後、GitHub にログインし、SSH キーの登録ページ(https://github.com/settings/keys)から New SSH Key を押下して、コピーした内容をペーストし登録。
これで、サーバと GitHub 間で SSH 接続できるようになった。
次に、サーバにアプリ公開用のディレクトリを作成する。
まずディレクトリを移動。
cd /var
www ディレクトリを作成。
sudo mkdir www
www ディレクトリの所有ユーザとグループを root から変更する。
sudo chown -R 作業用ユーザ名:作業用ユーザ名 www
所有が変わったことを確認する。
ls -l
root ではなく、作業用ユーザの所有に変わっていれば OK.
15 − 2.Capistrano、Unicorn をインストールする #
ローカルで Rails アプリを開き、Gemfile に以下を追記。
gem 'dotenv-rails'
gem 'unicorn'
gem 'mini_racer', platforms: :ruby
group :development, :test do
gem 'capistrano'
gem 'capistrano-bundler'
gem 'capistrano-rails'
gem 'capistrano-rbenv'
gem 'capistrano3-unicorn'
end
Gemfile 更新後、ローカルで bundle install 実行。
bundle install
次に、Capistrano の設定ファイルを作成する。ローカルで実行。
bundle exec cap install
/Capfile が作成されるので、そのファイルに以下を追記。
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'
デフォルトで記載されているものもあるため、不足しているものについて、上記となるように追記する。
次に、/config/deploy/production.rb を開き、以下を追記。
server 'サーバのIPアドレス', user: 'サーバの作業用ユーザ名', roles: %w{app db web}
set :ssh_options, keys: 'ローカルの秘密鍵のパス'
ローカルの秘密鍵のパスは、"/Users/ユーザ名/.ssh/id_rsa” といった感じになる。
次に、Gemfile.lock を開き、インストールされた Capistrano のバージョンを確認。
capistrano (3.14.1)
airbrussh (>= 1.0.0)
i18n
rake (>= 10.0.0)
sshkit (>= 1.9.0)
capistrano の右の 3.14.1 がバージョンを示している。
次に、/config/deploy.rb を開き、既存の記述を全て削除した後、下記を記載。
# config valid only for current version of Capistrano
lock "~> 3.14.1" # Capistranoのバージョン
set :application, 'アプリケーション名' # アプリケーション名
set :repo_url, 'https://github.com/xxxx/yyyy' # クローンするGitHubリポジトリ(xxxxはユーザ名、yyyyはアプリ名)
set :deploy_to, '/var/www/アプリケーション名' # デプロイ先のディレクトリ
set :linked_files, %w{.env config/secrets.yml} # シンボリックリンクを貼るファイル
set :linked_dirs, %w{log tmp/pids tmp/cache tmp/sockets public/uploads} # シンボリックリンクを貼るディレクトリ
set :keep_releases, 3 # 保持するバージョンの数
set :rbenv_ruby, '2.7.1' # Rubyのバージョン
set :rbenv_type, :system
set :log_level, :debug # 出力するログのレベル 概要レベルにしたければ :info とする
namespace :deploy do
desc 'Restart application'
task :restart do
invoke 'unicorn:restart'
end
desc 'Create database'
task :db_create do
on roles(:db) do |host|
with rails_env: fetch(:rails_env) do
within current_path do
execute :bundle, :exec, :rails, 'db:create'
end
end
end
end
desc 'Run seed'
task :seed do
on roles(:app) do
with rails_env: fetch(:rails_env) do
within current_path do
execute :bundle, :exec, :rails, 'db:seed'
end
end
end
end
after :publishing, :restart
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
end
end
end
アプリケーション名、Capistrano や Ruby のバージョン、GitHub のリポジトリは環境(人)によって異なるので、適宜変更。アプリケーション名は、Rails new した時のプロジェクト名に合わせておけば適当かと。
次に、config 直下に unicorn ディレクトリを作成し、その直下に production.rb を作成する(/config/unicorn/production.rb)。作成した production.rb に以下を記載。
$worker = 2
$timeout = 30
$app_dir = "/var/www/アプリケーション名/current"
$listen = File.expand_path 'tmp/sockets/unicorn.sock', $app_dir
$pid = File.expand_path 'tmp/pids/unicorn.pid', $app_dir
$std_log = File.expand_path 'log/unicorn.log', $app_dir
worker_processes $worker
working_directory $app_dir
stderr_path $std_log
stdout_path $std_log
timeout $timeout
listen $listen
pid $pid
preload_app 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
Process.kill "QUIT", File.read(old_pid).to_i
rescue Errno::ENOENT, Errno::ESRCH
end
end
end
after_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end
アプリケーション名の部分は、/config/deploy.rb 内で記述したアプリケーション名を記載する。
ここまで終わったら、更新内容をコミットして、GitHub にプッシュする。
15 − 3.Unicorn の自動起動設定をする #
サーバに戻り、以下を実行。
sudo vi /usr/lib/systemd/system/unicorn_アプリケーション名.service
作成されたファイルに以下を記載。
[Unit]
Description=unicorn アプリケーション名 service
After=network.target
[Service]
User=作業用ユーザ名
Environment=RAILS_ENV=production
WorkingDirectory=/var/www/アプリケーション名/current
PIDFile=/var/www/アプリケーション名/current/tmp/pids/unicorn.pid
ExecStart=/usr/local/rbenv/shims/bundle exec unicorn -c /var/www/アプリケーション名/current/config/unicorn/production.rb -D
Restart=always
[Install]
WantedBy=multi-user.target
記述の書式が正しいことをチェック。
sudo systemd-analyze verify /usr/lib/systemd/system/unicorn_アプリケーション名.service
何も表示されなければ問題ないということなので OK.
OS 起動時に Unicorn も自動起動するように設定。
sudo systemctl enable unicorn_アプリケーション名.service
自動起動設定できているか確認。
sudo systemctl is-enabled unicorn_アプリケーション名.service
enabled であれば OK.
なお Unicorn はこの後デプロイする中で起動されるので、今は起動しない。
15 − 4.Nginx の設定ファイルを作成 #
以下を実行。
sudo vi /etc/nginx/conf.d/アプリケーション名.conf
作成されたファイルに以下を記載。
upstream unicorn_アプリケーション名 {
server unix:/var/www/アプリケーション名/current/tmp/sockets/unicorn.sock;
}
server {
listen 80;
server_name サーバのIPアドレス;
root /var/www/アプリケーション名/current/public;
access_log /var/log/nginx/アプリケーション名_access.log;
error_log /var/log/nginx/アプリケーション名_error.log;
location / {
try_files $uri @unicorn;
}
location @unicorn {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://unicorn_アプリケーション名;
}
}
設定ファイル作成後、以下のコマンドで設定ファイルに問題ないかをテストする。
sudo nginx -t
下記のメッセージが表示され、テストに成功していることが確認できれば OK.
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
その後、設定を反映させるために Nginx を再起動する。
sudo systemctl restart nginx
15 − 5.デプロイできる状態か確認する #
ローカル(のアプリのプロジェクトディレクトリ)で以下を実行する。
bundle exec cap production deploy:check
なお、デプロイチェックにあたり、GitHub について、以下の点に留意。
- ローカルと GitHub で SSH 接続できる(GitHub に鍵が登録されている)状態となっていること。
- GitHub のリポジトリがパブリックとなっていること。
GitHub のプライベートリポジトリでデプロイしたい場合は、本記事下部の「80 − 2.GitHub のプライベートリポジトリからデプロイする」を参照して設定しておく。
デプロイチェック実行後、
ERROR linked file /var/www/アプリケーション名/shared/.env does not exist on IPアドレス
というエラーが出るが想定内なので大丈夫。
上記処理内ではデプロイできるかのチェックだけでなく、サーバで先ほど作成した www ディレクトリ配下にアプリ用のディレクトリも作っている。
15 − 6.環境変数を設定する #
ローカルで以下を実行し、乱数を生成する。
bundle exec rake secret
出力された乱数をコピーしておく。
次にサーバで、secrets.yml ファイルを作成する。
sudo vi /var/www/アプリケーション名/shared/config/secrets.yml
ファイルが開いたら、下記の通り、ローカルで生成した乱数をペーストして保存する。
production:
secret_key_base: 生成した乱数
次に、.env ファイルを作成する。
sudo vi /var/www/アプリケーション名/shared/.env
ファイルが開いたら、Rails アプリで.env に記述していた環境変数をコピーして、上記の.env ファイルにペーストする。
15 − 7.改めてデプロイできる状態か確認する #
改めてローカル(のアプリのプロジェクトディレクトリ)で以下を実行する。
bundle exec cap production deploy:check
今度はエラーが発生しないことを確認する。これでデプロイできる状態となった。
16.デプロイを実行する #
ローカルで以下を実行する。
bundle exec cap production deploy
bundler:install のところで時間がかかるため、固まったのか…?という不安と戦いながらじっと耐えるべし。
もし本当に固まったように思われた場合、Ctrl + C でデプロイを中止し、もう一度デプロイコマンドを実行すると、次はうまくいくことが多い。
これでようやくデプロイ完了。アクセスしてみる。
http://IP アドレス
(トップページを設定していないのであれば、http://IP アドレス/blogs
など存在するページを指定)
Rails アプリのページが表示されることを確認する。
80.その他設定編 #
これまででデプロイはできたわけだが、以降、追加の設定について。
80 − 1.SSH のポート番号を変更する #
セキュリティの観点から実施しておく。
root ユーザで作業する。
su root
まずは、SELinux(Linux カーネルのセキュリティ機能のひとつ)の状態を確認する。
getenforce
CentOS 8.2 では、デフォルトが Disabled となっていることを確認。そのままにしておく。
ファイルを開き、
vi /etc/ssh/sshd_config
以下の部分を見つけ、
# If you want to change the port on a SELinux system, you have to tell
# SELinux about this change.
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::</code></pre>
Port 22 の部分のコメントアウトを外し、適当な番号を設定する。下記は例。 #
# If you want to change the port on a SELinux system, you have to tell
# SELinux about this change.
# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER
#
Port 50022
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
ポート番号は自由に決めることができるが、自分のサーバ内で他のサービスが使っているポート番号と被ると問題になるので注意。とりあえず 49152〜65535 の間で適当に決めるのが良い。
どんなサービスがどんなポート番号を使っているかは、参考までに下記を参照。
TCP や UDP におけるポート番号の一覧 - Wikipedia
また、設定ファイル内に、「# If you want to change the port on a SELinux system, you have to tell …」と記載がある通り、先に確認した SELinux が Disabled ではなく有効になっていると、SELinux の設定も変える必要がある。
次に、Firewalld のデフォルト設定の格納場所である「/usr/lib/firewalld/services/」直下にある「ssh.xml」を、カスタム設定の格納場所である「/etc/firewalld/services/」直下へコピーする。
cp /usr/lib/firewalld/services/ssh.xml /etc/firewalld/services/ssh.xml
コピーして作成したファイルを開いて編集する。
vi /etc/firewalld/services/ssh.xml
以下部分のポート番号を、
<port protocol="tcp" port="22"/>
先ほど設定したポート番号に変える。
<port protocol="tcp" port="50022"/>
設定を反映させるため、Firewalld をリロード、SSHD を再起動する。
firewall-cmd --reload
systemctl restart sshd
ここまで終わったら、ターミナルをもう一つ立ち上げる。この時、上記作業に使ったターミナルはサーバに接続したままにしておき、決して閉じないように。万が一設定がうまくいっていないままターミナルを閉じると、二度と繋げなくなってしまう。
新たに立ち上げたターミナルで以下を実行。
ssh 作業用ユーザ名@IPアドレス
結果、
ssh: connect to host IPアドレス port 22: Operation timed out
になっていれば OK. 22 番ポートは閉じられている。
次に以下で接続。以下は SSH のポート番号を 50022 にしている場合。
ssh 作業用ユーザ名@IPアドレス -p 50022
接続できることを確認。
ここまでの作業で SSH のポート番号が変わったわけだが、それと同時に、Capistrano でデプロイする時にもそのポート番号を使うように設定しておかないといけない。
ローカルで Rails アプリの/config/deploy/production.rb を開き、
server 'サーバのIPアドレス', user: 'サーバの作業用ユーザ名', roles: %w{app db web}
set :ssh_options, keys: 'ローカルの秘密鍵のパス'
上記に、ポート番号の設定を追加する。下記はポート番号が 5022 の場合。
server 'サーバのIPアドレス', user: 'サーバの作業用ユーザ名', port: '50022', roles: %w{app db web}
set :ssh_options, keys: 'ローカルの秘密鍵のパス'
変更後は、コミットして GitHub へプッシュ。
最後にローカルで、
bundle exec cap production deploy:check
を実行して、ちゃんとデプロイできるようになっているか確認しておく。
80 − 2.GitHub のプライベートリポジトリからデプロイする #
GitHub のリポジトリをプライベートにする場合は、デプロイの設定にも手を入れる必要がある。
まず、GitHub の以下ページから、
https://github.com/settings/tokens
Generate new token を押下し、repo 項目の Full control of private repositories をチェックして生成。トークンが表示されたらコピーしておく。
その後、Rails アプリの/config/deploy.rb を開き、
set :repo_url, 'https://github.com/xxxx/yyyy' # クローンするGitHubリポジトリ(xxxxはユーザ名、yyyyはアプリ名)
上記となっている set :repo_url を、以下のように編集。https://github.com/
の部分を、 https://トークン:@github.com/
に変える。
set :repo_url, 'https://トークン:@github.com/xxxx/yyyy' # クローンするGitHubリポジトリ(xxxxはユーザ名、yyyyはアプリ名)
最後にローカルで下記を実行し、
bundle exec cap production deploy:check
デプロイできる状態となっていることを確認しておく。
80 − 3.タイムゾーンを日本時間で統一する #
必要であれば実施。
アプリ内で時刻を使用する場合、OS(CentOS)、DB(PostgreSQL)、Rails の時刻基準を合わせておくと良さそう。
まず、CentOS のタイムゾーンを変更する。サーバ上で、root ユーザにて以下を実行。
timedatectl set-timezone Asia/Tokyo
上記後、以下で確認。
timedatectl status
Time zone: Asia/Tokyo (JST, +0900) となっていれば OK.
次に PostgreSQL のタイムゾーンを変更。DB にアクセスし、
psql -U postgres
プロンプトが、postgres=# となったのを確認して、DB 一覧を確認。
\l
タイムテーブルを変更したい DB の名前をコピーしておき、一度 DB から抜ける。
\q
そしてタイムゾーンを変更したい DB に接続する。
psql -U postgres -d DB名
プロンプトが、DB 名=# となったのを確認して、以下でタイムゾーンを変更。
ALTER DATABASE "DB名" SET timezone TO 'Asia/Tokyo';
その後以下を実行し、
SELECT CURRENT_TIMESTAMP;
日本時間で現在時刻が表示されていれば OK、DB から抜ける。
\q
なお、上記では DB 単位でタイムゾーンを設定しているため、他の DB のタイムゾーンは変わっていないことに注意。
最後に Rails のタイムゾーン設定を変える。
ローカルで Rails アプリの、config/application.rb を開く。
そして、class Application < Rails::Application ブロックの中に以下2行を追記。
module XXXX
class Application < Rails::Application
.........
......
...
config.time_zone = 'Tokyo' # 追記
config.active_record.default_timezone = :local # 追記
end
end
最後に忘れずコミット&プッシュ&デプロイしておくこと。
80 − 4.ログローテーションの設定 #
放っておくと際限なくログファイルが膨れ上がってしまうため、自動的に削除するように設定しておく。
まず、Nginx のログについてはデフォルトでログローテーションされるようになっているため対応不要。
次に、Unicorn のログについて設定。/etc/logrotate.d/の下に設定ファイルを作る。サーバ上で root ユーザにて以下を実行。
vim /etc/logrotate.d/アプリケーション名_unicorn
開いたファイルに以下を記載。
/var/www/アプリケーション名/current/log/*unicorn.log {
create 0664 作業用ユーザ名 作業用ユーザ名
daily
rotate 10
missingok
notifempty
compress
postrotate
pid=/var/www/アプリケーション名/current/tmp/pids/unicorn.pid
test -s $pid && kill -USR1 "$(cat $pid)"
endscript
}
上記では、1日1ファイルを作成、10 世代保存という設定にしている。
最後に、Rails のログについて設定。ローカルで Rails アプリの config/environments/production.rb を開き、下記を追加する。設定内容の意味はコメントに記載している通り。
# production.0, production.1, production.2 の3世代保持 10Mを超えるとローテーション
config.logger = Logger.new('log/production.log', 3, 10 * 1024 * 1024)
その後、コミット&プッシュ&デプロイを忘れずに。
90.その他知っておくこと編 #
90 − 1.再度デプロイする場合 #
資産を更新しデプロイする場合は、GitHub にプッシュした後、ローカルで再度、
bundle exec cap production deploy
を実行すれば OK.
90 − 2.サーバで本番環境の Rails c を使う方法 #
サーバ内の、
var/www/アプリケーション名/current
にて、下記を実行する。
bundle exec rails console -e production
-e production を付けずに行うと、開発環境(development)のコンソールが開かれるので注意。
コンソール上で以下を入力するとその時の環境が表示されるので、確認することも可能。
Rails.env
本番環境で開けていれば、“production"と表示される。
90 − 3.サーバで本番環境の Rails db コマンドを使う方法 #
サーバ内の以下で実施。
var/www/アプリケーション名/current
コマンドの後ろに、RAILS_ENV=production を付ける。例えば、rails db:seed なら以下。
bundle exec rails db:seed RAILS_ENV=production
ただし、本番環境の Rails db:reset したいときは以下ではダメ。
bundle exec rails db:reset RAILS_ENV=production
上記を実行すると、「ActiveRecord::ProtectedEnvironmentError: You are attempting to run a destructive action against your “production” database.」というエラーが出る。
本番環境で Rails db:reset する場合は下記を入力する。
bundle exec rails db:reset RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1
他にも、本番環境の DB に破壊的なコマンドを発行するときには、DISABLE_DATABASE_ENVIRONMENT_CHECK=1 が必要。
90 − 4.ログの場所 #
本手順で構築した場合のログの格納場所。
Nginx のログはサーバ内の以下。
/var/log/nginx/
- アクセスログ
/var/log/nginx/アプリケーション名_access.log
- エラーログ
/var/log/nginx/アプリケーション名_error.log
Unicorn および Rails のログはサーバ内の以下。
/var/www/アプリケーション名/shared/log/
- Unicorn のログ
/var/www/アプリケーション名/shared/log/unicorn.log
- Rails のログ
/var/www/アプリケーション名/shared/log/production.log
以上 #
長くなったがようやく終わり。めでたしめでたし。
あとは、独自ドメインの設定、SSL 化を行い、こうしてメモを残していきたい。
*追記
次の記事を作成しました。