実際に systemd で動くのは sidekiq だけですが。
追記:2021/08/18
対応されてなさそうなら fork して修正作るかー、と思って確認したのですが、それっぽい修正が取り込まれていました。
ログ記述の append:
あたりとか、いまだに RHEL7(CentOS7) だと動作しない気がするのですが、少なくとも完全に RHEL 系を考慮していない以前のようなユニットファイルではなくなったようです。
capistrano-sidekiq
こんなエラーが出ることがあります。
Systemctl stderr: Failed to get D-Bus connection: No such file or directory
これは RHEL7 派生ディストリで、 systemctl から --user
オプションを削除されているからのようです。
D-Bus
情報のやり取りを担当するなんか、みたいなふわっとした理解で良いです。 以下にだいぶ頑張ってわかりやすく記述されていますが、読んでも結局よくわかりません。
busctl
で user
system
を可視化できるの初めて知った。
sidekiq_service_unit_user
:sidekiq_service_unit_user
の値によって systemd の起動オプションに --user
が付与されるか否か変わります。
具体的な例は以下。
この --user
オプションが曲者で、 RHEL7 派生、つまり CentOS7 やおそらく同じ派生の AmazonLinux2 では動きません。
Basically we don't know if systemd --user will stay in systemd as is right now. So we have decided to disable it completely so we will not hit regression in future versions of centos.
「systemd の --user
が現在のままであるかどうかわからんので、完全に無効化するわ」とのことです。
参考
どうする
こうする。
- sidekiq を動作させるユーザにパスワードなしで sudo できるように
sudoers
を編集する - config/deploy.rb に
capistrano-sidekiq
systemd 向け設定を追加する bundle exec cap ${RAILS_ENV} sidekiq:install
する/etc/systemd/system/sidekiq.service
を手動で修正daemon-reload
で修正を反映するsidekiq:start
sidekiq:quiet
sidekiq:stop
が動くか確認する
AmazonLinux2 を想定して以下記載します。
0. sidekiq を動作させるユーザにパスワードなしで sudo できるように sudoers
を編集する
AmazonLinux2 は ec2-user
なら最初から sudoers に居るので飛ばしていい。
RHEL 系なら user ALL=NOPASSWD: ALL
のように visudo で記述する。
1. config/deploy.rb に capistrano-sidekiq
systemd 向け設定を追加する
config/deploy.rb
なり RAILS_ENV ごとの設定ファイルに、下記項目に対応する値を設定する。
# sidekiq systemd options set :sidekiq_service_unit_user, :system # これで --user オプションを使わなくなる set :sidekiq_user, -> { "ec2-user" } # sidekiq を動作させるユーザ名、 Rails 動かすユーザと基本は同一
2. bundle exec cap ${RAILS_ENV} sidekiq:install
する
production 対象ならローカルから実行するコマンドはこう。
bundle exec cap production sidekiq:install
これでリモートサーバに /etc/systemd/system/sidekiq.service
が生成されつつ daemon-reload も実行されるので、 systemctl ${ACTION} sidekiq
が使えるようになる。
3. /etc/systemd/system/sidekiq.service
を手動で修正
おおよそ以下ような記述のファイルだと思われるので、これらから ExecStart
の行を変更する。
[Unit] Description=sidekiq for example (staging) After=syslog.target network.target [Service] Type=simple WorkingDirectory=/var/www/example/current ExecStart=/usr/bin/env /usr/local/bin/bundle exec sidekiq -e staging ExecReload=/bin/kill -TSTP $MAINPID ExecStop=/bin/kill -TERM $MAINPID StandardOutput=append:/var/www/example/shared/log/sidekiq.log StandardError=append:/var/www/example/shared/log/sidekiq.error.log User=ec2-user RestartSec=1 Restart=on-failure SyslogIdentifier=sidekiq [Install] WantedBy=default.target
変更前
ExecStart=/usr/bin/env /usr/local/bin/bundle exec sidekiq -e staging
変更後
ExecStart=/bin/bash -lc "cd /var/www/example/current && /usr/bin/env /usr/local/bin/bundle exec sidekiq -e staging"
4. daemon-reload
で修正を反映する
systemd のお約束。
sudo systemctl daemon-reload
sidekiq:start
sidekiq:quiet
sidekiq:stop
が動くか確認する
ローカルからリモートの systemd を操作してそれぞれ動くか確認する。
# 起動 bundle exec cap production sidekiq:start # Start sidekiq # 新しい接続を拒否して今のジョブキューが終了するまで待つ bundle exec cap production sidekiq:quiet # Quiet sidekiq (stop fetching new tasks from Redis) # 終了(処理中のキューは全部 Redis に戻すので、次回起動すると最初から重複実行されると思われる) bundle exec cap production sidekiq:stop # Stop sidekiq (graceful shutdown within timeout, put unfinished tasks back to Redis)
ちなみに何があるかはご存知 -T を利用した bundle exec cap -T sidekiq
で確認できる。
という感じです
一番のメインが ExecStart の編集箇所で、 Capistrano 経由では起動しないけど ssh ログインして RAILS_ROOT 以下に移動して直接 sidekiq
を起動すると動いた。
という感じだったので、おそらく Capistrano 特有のユーザシェルを持たない、という動作が邪悪ねんな? というトコから、 bash -lc
で明示的にユーザシェルを所持してその中で sidekiq を実行、としたところ動作しました。
なんか筋が悪い感じでもやっとするけど rbenv 利用している環境もこんな感じなのでしゃーなし。
おまけ
StandardOutput
StandardError
に append:
がついてるけど、これ AmazonLinux2 の systemd だと verison 219 で動きません。
ので、 syslog
を指定した上で、 syslogidentifer だったかな? で sidekiq
など指定して、 syslog 経由してログを rotate なり分解なりするようにしましょう。
記述を削除するとそのまま journald に格納されるのですが、個人的に journald にデーモンの動作以外のログが入るのはよくないと思っています。 (実装によっては sidekiq ジョブキューの中身がログに出ると思われるので)
急にヒュッと飛んできて丸一日使ってしまった。