Sidekiq を Capistrano でデプロイ
Sidekiq を EC2 で作った本番環境上で稼働させるために systemd で管理する必要があったので、
その方法と、Capistrano で再起動させる方法を忘備録としてまとめました🙌
前提
- ruby 2.6.3
- Rails 6.0.3
- Sidekiq 6.4.1
- Capistrano 3.14.1
目次
- systemd で Sidekiq を管理する
-
sudoをパスワードなしで実行出来るようにする - Capistrano をインストール
- Capfile を修正
systemd で Sidekiq を管理する
Sidekiq6 以降デーモンとして動作するのではなく、 systemd などで管理する方針に変更された
ので、まず systemd で管理するため Unit を定義します。Unit の内容に関しては こちら を参考にしました。
# /etc/systemd/system/sidekiq.service
[Unit]
Description=sidekiq
After=syslog.target network.target
[Service]
Type=notify
WatchdogSec=10
WorkingDirectory=/var/www/example/staging/current
ExecStart=/bin/bash -lc 'exec /home/deploy/.rbenv/shims/bundle exec sidekiq -e staging -C config/sidekiq.yml'
ExecReload=/bin/kill -TSTP $MAINPID
Environment=MALLOC_ARENA_MAX=2
RestartSec=1
Restart=always
[Install]
WantedBy=multi-user.target
この記事ではこの Unit で使われているオプションのみ簡単に解説します。
Unit ファイルは「Unit」「Service」「Install」という3つのセクションで構成され、各セクションの役割は以下の様になります。
| セクション | 説明 |
|---|---|
| Unit | Unit の説明・依存関係を記述する |
| Service | 固有の設定項目 |
| Install | systemctl enable/disable の動作に影響する設定項目 |
次に上記の Unit で使われているオプションについてまとめていきます。
Unit
| オプション | 説明 |
|---|---|
| Description | Unit の説明 |
| After | この Unit より先に起動する Unit |
Service
| オプション | 説明 |
|---|---|
| Type | この Unit のプロセス起動タイプを設定する。 notify は exec (fork()→execve() で新しいプロセスが実行される)と似ていますが、 sd_notify(3) を介してメッセージが通されることが期待される |
| WatchdogSec | WatchDog はサービスを定期的に監視して稼働状況をチェックしてくれる機能。 WatchdogSec で指定した時間内に応答がなければ WatchdogSignal で指定した Signal でサービスを停止する |
| WorkingDirectory | コマンドを実行するディレクトリを指定 |
| ExecStart | このサービスの start 時に実行されるコマンド |
| ExecReload | このサービスの reload 時に実行されるコマンド |
| Environment | 環境変数を定義する。今回はスレッドあたりのメモリアリーナを制限するため MALLOC_ARENA_MAX を指定しています。(こちら の記事 も合わせて読むのが良いと思います) |
| RestartSec | サービスを再起動する前にスリープする時間を指定する |
| Restart | プロセスが終了、強制終了、またはタイムアウトした時に再起動するかどうか指定する。no on-success on-failure on-abnormal on-watchdog on-abort always が指定出来る。no の時は再起動しない |
こちら には ExecReload の指定はありませんが、 capistrano-sidekiq でデプロイする際、このオプションの指定がないと
00:02 sidekiq:quiet
01 sudo systemctl reload sidekiq.service
01 Failed to reload sidekiq.service: Job type reload is not applicable for unit sidekiq.service.
01 See system logs and 'systemctl status sidekiq.service' for details.
✘ 01 hoge@i-05413653a3f710cc8 0.077s
というエラーが発生したため指定しました。プロセスの PID は環境変数 $MAINPID で参照でき、
TSTP シグナルは一時停止を意味します。
Install
| オプション | 説明 |
|---|---|
| WantedBy |
enable 時にこのUnitの .wants ディレクトリにシンボリックリンクを作成する。今回の場合 multi-user.target.wants 内にシンボリックリンクが作成される |
以上が Sidekiq の Unit の解説となりますが、さらに Systemd について学びたい方には こちら の記事が参考になるかと思うのでご一読ください。
sudo をパスワードなしで実行出来るようにする
capistrano-sidekiq を使って Sidekiq を再起動する際、 systemctl を sudo で実行します
が、パスワードを要求されてしまうので、パスワードなしで実行出来るように修正して行きます。
$ sudo visudo
で visudo を開きます。
## Allow root to run any commands anywhere
root ALL=(ALL:ALL) ALL
こちらの部分の下の行に新しい権限を追加していきますが、その前にこの ALL が何を意味しているのかまとめておきます。
| # | 説明 |
|---|---|
| =の左側のALL | 許可するホスト |
| ()の中の左側のALL | ここにユーザー名を指定するとそのユーザーと同じ権限を得られる。ALLを指定するとどのユーザーにもなれる |
| ()の中の右側のALL | 上記のグループバージョン |
| 最後のALL | 実行出来るコマンド。コマンドを複数指定したい時は、, で区切る |
今回の場合、ユーザー名が hoge だとして、「パスワードなしで /usr/bin/systemctl のみ実行出来る」という権限にしたいので以下の様になります。
hoge ALL=(ALL) NOPASSWD: /usr/bin/systemctl
Capfile を修正
既に capistrano はインストールされている前提として、 capistrano-sidekiq をインストールします。
# Gemfile
group 'development' do
gem 'capistrano-sidekiq'
end
さらに Capfile に以下を追加します。
# Capfile
require 'capistrano/sidekiq'
install_plugin Capistrano::Sidekiq
install_plugin Capistrano::Sidekiq::Systemd
capistrano-sidekiq のコードを読んでみると、次のメソッドで systemctl コマンドを組み立てているのですが、 sidekiq_service_unit_user に :system を設定しない場合、 systemctl --user を実行してしまいます。
def systemctl_command(*args, process: nil)
execute_array =
if fetch(:sidekiq_service_unit_user) == :system
[:sudo, :systemctl]
else
[:systemctl, '--user']
end
if process
execute_array.push(
*args, sidekiq_service_unit_name(process: process)
).flatten
backend.execute(*execute_array, raise_on_non_zero_exit: false)
else
execute_array.push(*args, sidekiq_service_unit_name).flatten
backend.execute(*execute_array, raise_on_non_zero_exit: false)
end
end
今回はシステム全体でサービスを起動したいので、 sidekiq_service_unit_user に :system を指定して sudo で systemctl を実行出来るように config/deploy.rb に以下を追加します。
# config/deploy.rb
set :sidekiq_service_unit_user, :system
ここまで完了すれば次のタスクが実行出来るはずです。
bundle exec cap production sidekiq:stop
bundle exec cap production sidekiq:start
bundle exec cap production sidekiq:quiet
bundle exec cap production sidekiq:restart
参考資料
Discussion