systemd で 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 | サービスの標準出力と標準エラーを集めるログ |
手動起動だと次の形になる。
systemd に載せると次の形になる。
前提¶
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 側で変なことが起きやすい。
手動起動が通ることも確認する。
手順 1: unit ファイルを置く¶
システム全体のサービス定義は次に置く。
リポジトリの 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] |
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 に読み込ませる¶
| コマンド | 意味 |
|---|---|
daemon-reload |
unit ファイルの追加、変更を再読み込み |
手順 3: 起動する¶
まず一回動かして設定を確認する。
| コマンド | 意味 |
|---|---|
start |
今この瞬間だけ起動(再起動後は自動では上がらない) |
status |
動いているか、最近のログ数行 |
active (running) ならよい。
ログを追う。
| オプション | 意味 |
|---|---|
-u finance-manager |
この unit のログだけ |
-f |
follow(更新を追い続ける)。止めるのは Ctrl+C |
Logged in as ... が見えたら成功である。
Discord に一言送って応答も確認する。
手順 4: 起動時に自動起動させる¶
| コマンド | 意味 |
|---|---|
enable |
ブート時に自動で start されるよう登録 |
disable |
その登録を外す(今動いているプロセスは止めない) |
start と enable を同時にやる短縮形:
日常運用¶
| やりたいこと | コマンド |
|---|---|
| 状態 | 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 ダッシュボード。