Skip to content

systemd で Bot を常駐させる

関連: Bot の構成 / Bot の更新 / 運用

日常のコード反映は Bot の更新(git pull + systemctl restart)。 unit の正は deploy/finance-manager.service である。

systemd の役割

常駐プロセスは、OS 起動後も動かし続け、落ちたら戻す。 Linux では systemd がその管理を担う。

用語 意味
unit systemd が扱う設定の1単位。今回は .service
service 長く動くプロセス(Bot、DB、Web サーバなど)
systemctl 起動、停止、有効化を操作するコマンド
journald / journalctl サービスの標準出力と標準エラーを集めるログ

手動起動だと次の形になる。

SSH ログイン → ./scripts/run.sh → SSH 切断 → プロセスも死ぬ

systemd に載せると次の形になる。

OS 起動 → systemd が Bot を起動 → SSH なしでも動き続ける
落ちたら自動で再起動

前提

VM 上で次を確認する。

whoami
# → debian であること(違うなら User= を合わせる)

pwd
ls ~/finance-manager/scripts/run.sh
ls ~/finance-manager/.venv
ls ~/finance-manager/.env

二重起動しない

別ターミナルで ./scripts/run.sh しているなら Ctrl+C で止める。 同じ Bot を二重起動すると Discord 側で変なことが起きやすい。

手動起動が通ることも確認する。

cd ~/finance-manager
./scripts/run.sh
# Logged in as ... を見たら Ctrl+C

手順 1: unit ファイルを置く

システム全体のサービス定義は次に置く。

/etc/systemd/system/名前.service

リポジトリの unit をコピーする。

sudo cp ~/finance-manager/deploy/finance-manager.service \
  /etc/systemd/system/finance-manager.service

内容は次のとおりである。

[Unit]

[Unit]
Description=finance-manager Discord bot
Documentation=https://github.com/nakajima923/finance-manager
After=network-online.target
Wants=network-online.target
行 意味
[Unit] 共通メタ情報のセクション開始
Description= systemctl status に出る説明
Documentation= ドキュメント URL(任意)
After=network-online.target ネットワークが上がってから起動を始める(順序)
Wants=network-online.target 可能ならネットワーク待ちを一緒に引っ張る(必須依存より弱い)

After= は順序だけで、相手が成功したことは保証しない。 Discord Bot は外向き接続が要るので、ネットワーク後起動にする。

[Service]

[Service]
Type=simple
User=debian
Group=debian
WorkingDirectory=/home/debian/finance-manager
ExecStart=/home/debian/finance-manager/scripts/run.sh
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1
NoNewPrivileges=true
PrivateTmp=true
行 意味
[Service] 実行方法のセクション
Type=simple ExecStart のプロセス自体が本体。すぐ終わるワンショットではない
User= / Group= root ではなく一般ユーザーで動かす
WorkingDirectory= カレントディレクトリ。.env や相対パスの基準になる
ExecStart= 起動するコマンド(絶対パス)
Restart=always 落ちても再起動する
RestartSec=5 再起動までの待ち秒
Environment=PYTHONUNBUFFERED=1 Python の出力をバッファせず journal に出す
NoNewPrivileges=true 権限昇格しにくくする
PrivateTmp=true /tmp をサービス専用にする

ExecStart に source .venv/bin/activate && python ... と書かなくてよい。 scripts/run.sh が venv と PYTHONPATH を面倒を見る。

Restart=on-failure にすると正常終了(0)では再起動しない。 Bot は意図せず終了しがちなので、always を使う。

[Install]

[Install]
WantedBy=multi-user.target
行 意味
[Install] systemctl enable 用の情報
WantedBy=multi-user.target 通常のマルチユーザー起動に入れる

enable すると、だいたい次のシンボリックリンクが作られる。

/etc/systemd/system/multi-user.target.wants/finance-manager.service
  → /etc/systemd/system/finance-manager.service

手順 2: systemd に読み込ませる

sudo systemctl daemon-reload
コマンド 意味
daemon-reload unit ファイルの追加、変更を再読み込み

手順 3: 起動する

まず一回動かして設定を確認する。

sudo systemctl start finance-manager
sudo systemctl status finance-manager
コマンド 意味
start 今この瞬間だけ起動(再起動後は自動では上がらない)
status 動いているか、最近のログ数行

active (running) ならよい。

ログを追う。

journalctl -u finance-manager -f
オプション 意味
-u finance-manager この unit のログだけ
-f follow(更新を追い続ける)。止めるのは Ctrl+C

Logged in as ... が見えたら成功である。 Discord に一言送って応答も確認する。

手順 4: 起動時に自動起動させる

sudo systemctl enable finance-manager
コマンド 意味
enable ブート時に自動で start されるよう登録
disable その登録を外す(今動いているプロセスは止めない)

start と enable を同時にやる短縮形:

sudo systemctl enable --now finance-manager

日常運用

やりたいこと コマンド
状態 sudo systemctl status finance-manager
止める sudo systemctl stop finance-manager
起動 sudo systemctl start finance-manager
再起動 sudo systemctl restart finance-manager
コード更新後 cd ~/finance-manager && git pull && sudo systemctl restart finance-manager
直近100行 journalctl -u finance-manager -n 100 --no-pager
追いかけ journalctl -u finance-manager -f

pip で依存を足したあと:

cd ~/finance-manager
source .venv/bin/activate
pip install -r requirements.txt
sudo systemctl restart finance-manager

よくある失敗

症状 見ること
status が activating / すぐ死ぬ journalctl -u finance-manager -n 50 --no-pager
.env が読めない WorkingDirectory とファイル権限(debian が読めるか)
Permission denied on run.sh chmod +x ~/finance-manager/scripts/run.sh
Discord に二重反応 手動 run.sh がまだ生きていないか ps aux \| grep finance
unit を直したのに変わらない sudo systemctl daemon-reload を忘れていないか

unit の正

deploy/finance-manager.service が正である。 再インストール時も同じファイルを使う。

ダッシュボード

LAN 向け Streamlit は別 unit finance-dashboard.service である。 手順は Streamlit ダッシュボード。