#3 VPSでの開発サーバ作成 バックアップの設定,sidekiqを入れる

投稿者: | 2021年1月29日

前回までで主要なサーバやツールをインストールしました。サービス開始後を考慮し、データベースのバックアップの準備をしておきます。また、いずれメールを複数送る時に備え、非同期で(JOBで)でメールを送れるようにsidekiqというキューイングサービスもインストールしておきましょう。

データのバックアップ

アプリのプログラムはgitでバージョン管理されているため、バックアップも問題ありません。データについては何もバックアップを取っていません。今回は念のためデータのバックアップを定期的にとることにします。

今回はサーバ障害によるデータ消失には備えていません。本来であれば、何らかの手段でデータをサーバの外に置いておく必要もあると思いますが、サーバに保存しているだけです。アプリの不具合によってデータが消失したときに備えて、あるいは必要に応じて調査する際に備えてデータを保存しておきます。

なお、今回はパスワードを直書きしています。https://www.postgresql.jp/document/9.0/html/libpq-pgpass.html

ls -al ~/.pgpass
-rw------- 1 normal01 normal01 51 Aug  1 01:37 /home/normal01/.pgpass
cat ~/.pgpass
localhost:5432:DB名:DBユーザ名:パスワード

script_dump.sh

ファイルを10個まで新しい順に残します。

#!/bin/bash

# バックアップファイルを残しておく日数
PERIOD='+10'
# 日付
DATE=`date '+%Y%m%d-%H%M%S'`
# バックアップ先ディレクトリ
SAVEPATH='/home/normal01/dump/'
# 先頭文字
PREFIX='backup-'
# 拡張子
EXT='.dmp.gz'

# バックアップ実行
pg_dump -h localhost -Fc -U ユーザ名 DB名 | gzip > $SAVEPATH$PREFIX$DATE$EXT

# 保存期間が過ぎたファイルの削除
find $SAVEPATH -type f -daystart -mtime $PERIOD -exec rm {} \;
pwd
/home/normal01
ls -l
drwxrwxr-x  2 normal01 normal01 4096 Jan 27 02:30 dump
drwxrwxr-x 15 normal01 normal01 4096 Jan  8 03:13 アプリケーションのフォルダ
-rwxrwxr-x  1 normal01 normal01  523 Aug  1 01:47 script_dump.sh

cronで定期実行する

毎日2時半にバックアップスクリプトを流します。実行時に1ファイルができ、11個目の古いファイルが消えます。2時半としたのは、流石にこの時間に使う人は少なかろうという理由からです。

なお、システムによってはWindowsであればVSSのような仕組みが必要です。この辺りはインフラ屋さんにお任せします。アプリ屋さんが作る小規模システムであれば何も考えずにダンプをとるだけでよいでしょう。

sudo crontab -e -u normal01
# (行頭の # マークはコメント行を示す)
# +------------ 分 (0 - 59)
# | +---------- 時 (0 - 23)
# | | +-------- 日 (1 - 31)
# | | | +------ 月 (1 - 12)
# | | | | +---- 曜日 (0 - 6) (日曜日=0)
# | | | | |
# * * * * * 実行されるコマンド
30 2 * * * /home/normal01/script_dump.sh > /dev/null 2>&1

実行結果のサンプル

pwd
/home/normal01/dump
ls -al
total 932
drwxrwxr-x  2 normal01 normal01  4096 Jan 27 02:30 .
drwx------ 10 normal01 normal01  4096 Jan 27 04:57 ..
-rw-r--r--  1 normal01 normal01 84754 Jan 17 02:30 backup-20210117-023001.dmp.gz
-rw-r--r--  1 normal01 normal01 84754 Jan 18 02:30 backup-20210118-023001.dmp.gz
-rw-r--r--  1 normal01 normal01 84752 Jan 19 02:30 backup-20210119-023001.dmp.gz
-rw-r--r--  1 normal01 normal01 84853 Jan 20 02:30 backup-20210120-023002.dmp.gz
-rw-r--r--  1 normal01 normal01 84874 Jan 21 02:30 backup-20210121-023001.dmp.gz
-rw-r--r--  1 normal01 normal01 84930 Jan 22 02:30 backup-20210122-023001.dmp.gz
-rw-r--r--  1 normal01 normal01 84964 Jan 23 02:30 backup-20210123-023002.dmp.gz
-rw-r--r--  1 normal01 normal01 84967 Jan 24 02:30 backup-20210124-023001.dmp.gz
-rw-r--r--  1 normal01 normal01 84967 Jan 25 02:30 backup-20210125-023001.dmp.gz
-rw-r--r--  1 normal01 normal01 84966 Jan 26 02:30 backup-20210126-023001.dmp.gz
-rw-r--r--  1 normal01 normal01 84983 Jan 27 02:30 backup-20210127-023001.dmp.gz

Active JOBのキューイングサーバ

Active Jobという仕組みがrailsにはあります。この仕組みがあるので、画面からリクエストを受け取り、レスポンスを返す数秒の間では実行できない処理も非同期時で実行できます。あるいは、何月何日に実行するという予約もできます。

この機能を使うことで、メール(Action Mailer)の送信も簡単に非同期にできます。これを使うにはバックにキューイングの仕組みが必要です。

https://railsguides.jp/active_job_basics.html#%E3%83%90%E3%83%83%E3%82%AF%E3%82%A8%E3%83%B3%E3%83%89%E3%82%92%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B

その中の一つであるsidekiqを使うことにします。

sidekiqのインストール

sidekiqにはredisというno sqlなデータベースサーバが必要なのでこれもインストールしておきます。

sudo yum install redis
sudo systemctl restart redis

sidekiqも引き続きインストールします。

gemファイルに定義しておきます。bundle installで入れてみるとlistenが必要といわれるのでlistenもいれておきます。

gem 'sidekiq'
gem 'listen'

/etc/systemd/system/sidekiq.service

#
# This file tells systemd how to run Sidekiq as a 24/7 long-running daemon.
#
# Customize this file based on your bundler location, app directory, etc.
# Customize and copy this into /usr/lib/systemd/system (CentOS) or /lib/systemd/system (Ubuntu).
# Then run:
#   - systemctl enable sidekiq
#   - systemctl {start,stop,restart} sidekiq
#
# This file corresponds to a single Sidekiq process.  Add multiple copies
# to run multiple processes (sidekiq-1, sidekiq-2, etc).
#
# Use `journalctl -u sidekiq -rn 100` to view the last 100 lines of log output.
#
[Unit]
Description=sidekiq
# start us only once the network and logging subsystems are available,
# consider adding redis-server.service if Redis is local and systemd-managed.
After=syslog.target network.target

# See these pages for lots of options:
#
#   https://www.freedesktop.org/software/systemd/man/systemd.service.html
#   https://www.freedesktop.org/software/systemd/man/systemd.exec.html
#
# THOSE PAGES ARE CRITICAL FOR ANY LINUX DEVOPS WORK; read them multiple
# times! systemd is a critical tool for all developers to know and understand.
#
[Service]
#
#      !!!!  !!!!  !!!!
#
# As of v6.0.6, Sidekiq automatically supports systemd's `Type=notify` and watchdog service
# monitoring. If you are using an earlier version of Sidekiq, change this to `Type=simple`
# and remove the `WatchdogSec` line.
#
#      !!!!  !!!!  !!!!
#
Type=notify
# If your Sidekiq process locks up, systemd's watchdog will restart it within seconds.
WatchdogSec=10

WorkingDirectory=/home/normal01/man_hour_app
# If you use rbenv:
# ExecStart=/bin/bash -lc 'exec /home/deploy/.rbenv/shims/bundle exec sidekiq -e production'
# If you use the system's ruby:
# ExecStart=/usr/local/bin/bundle exec sidekiq -e production
# If you use rvm in production without gemset and your ruby version is 2.6.5
# ExecStart=/home/deploy/.rvm/gems/ruby-2.6.5/wrappers/bundle exec sidekiq -e production
# If you use rvm in production wit gemset and your ruby version is 2.6.5
#ExecStart=/bin/bash -lc 'exec /home/normal01/.rbenv/shims/bundle exec sidekiq'
ExecStart=/bin/bash -lc 'exec /home/normal01/.rbenv/shims/bundle exec sidekiq -e production -C /home/normal01/アプリ名/config/sidekiq.yml'


# Use `systemctl kill -s TSTP sidekiq` to quiet the Sidekiq process

# !!! Change this to your deploy user account !!!
User=normal01

Group=normal01

UMask=0002

# Greatly reduce Ruby memory fragmentation and heap usage
# https://www.mikeperham.com/2018/04/25/taming-rails-memory-bloat/
Environment=MALLOC_ARENA_MAX=2

# if we crash, restart
RestartSec=1
Restart=on-failure

# output goes to /var/log/syslog (Ubuntu) or /var/log/messages (CentOS)
StandardOutput=syslog
StandardError=syslog

# This will default to "bundler" if we don't specify it
SyslogIdentifier=sidekiq

[Install]
WantedBy=multi-user.target

アプリホームの下のconfig/sidekiq.ymlを指定しているので、その場所にファイルを作っておきます。(もちろんgit管理の対象です)

cat config/sidekiq.yml
:concurrency: 25
:pidfile: ./tmp/pids/sidekiq.pid
:logfile: ./log/sidekiq.log
:queues:
  - default
  - mailers
:daemon: true

なお、routes.rbにsidekiqのダッシュボードをマウントしておくこともできます。念のため、/sidekiqの部分はかえておき、basic認証程度はかけておいたほうが無難です。

mount Sidekiq::Web => '/sidekiq'

メンテナンス手順

構成としては上記のようになっています。まずは、WebサーバであるnginxからAPサーバであるPumaへの経路を遮断します。

その手順を記載します。

  1. メンテナンスモード切替
  2. アプリ更新
  3. 復帰

以前、nginxをインストールしたときに、メンテナンスモード(フラグファイルがある)の時にはメッセージを表示し、アプリケーションへのアクセスを止められるようにしてあります。

メンテナンスモード切替

nginxのconfファイルの関係個所を抜粋します。mainte.htmlの内容を編集します。

        error_page 503 @maintenance;
        set $maintenance false;
        if (-e /etc/nginx/maintenance) {
          set $maintenance true;
        }
        if ($access_from !~ external) {
          set $maintenance false;
        }
        if ($maintenance = true) {
          return 503;
        }
        location @maintenance {
          root         /usr/share/nginx/html;
          rewrite ^(.*)$ /mainte.html break;
        }

それほど凝ったページを作成する必要はないと思いますので簡単に、下記のように作ってしまいます。

普段はこのようになっている空ファイルをリネームします。

ls -al maintenance*
-rw-r--r-- 1 root root 0 Jul 30  2020 maintenance_____
sudo mv maintenance_____ maintenance

これでリクエストがAPサーバまで届きません。

アプリ更新

git経由でソースファイルを落として、アプリを更新します。

APサーバからすればアクセス元であるnginxから遮断されているのでサーバサービスをstopしても利用中のユーザはいません。

sudo systemctl stop puma.service
sudo systemctl stop sidekiq.service
sudo systemctl stop redis
git pull origin master

これでサーバサービスをストップしてソースファイルが更新されました。リリース前に、毎日cronで流しているデータのバックアップスクリプトを流しておきます。

最新10日前まで、というバックアップの世代が1つずれるので、むやみにたたかないようにしておきましょう。

/home/normal01/script_dump.sh > /dev/null 2>&1
bundle install
rails assets:precompile RAILS_ENV=production
rails db:migrate:status RAILS_ENV=production
rails db:migrate RAILS_ENV=production
sudo systemctl restart redis
sudo systemctl restart sidekiq.service
sudo systemctl restart puma.service

動作確認

まだメンテナンスモードのままなので誰もアクセスしてきませんが、正常に画面が見えるかを確認しておきます。sshでサーバには接続していますから、ポートフォワーディングをかけます。(補足:nginxの設定でinternalならメンテナンスモードに入らないようにしてあります。)

        if ($access_from !~ external) {
          set $maintenance false;
        }

localhostの8080ポートにアクセスします。

ひとまず今は問題ありません。

これでアクセスできれば問題ありません。本番環境にテストユーザを用意しておき、機能が一通りアクセスできることを確認しておきましょう。

復帰

メンテナンスモードを解除します。

sudo mv maintenance maintenance_____

これで、ポートフォワードをせずともアクセスできます。

動作確認の際にはhttpでアクセスしているので、テストユーザのパスワードは、メンテナンスモードを解除した後に変更しておきましょう。

おわりに

ここまでの手順で、Railsのサーバを作り、バックアップの仕組みやアプリのリリース時の手順まで整備できました。

思う存分開発してサービスを公開できますね。