「systemdのRestart=alwaysで再起動はされるが、プロセスは生きているのにAPIが応答しない状態で止まることがある」
そんな経験を持つインフラ担当者は少なくない。systemdやDockerのrestartポリシーはプロセスの生死を管理できるが、「プロセスは稼働しているがAPIが応答しない」という半死状態には対応できない。
この記事では、OllamaのAPI応答を直接確認するWatchdogスクリプトをbashで実装し、cronで定期実行する手順を解説する。再起動後の確認・Slackウェブフック通知・多段エスカレーションまで含めた実践的な構成だ。Ubuntu ServerへのローカルLLM構築が完了している前提で進める。
この記事のポイント
・curl --max-timeでAPIタイムアウトを検出し、プロセス死活だけでなく応答不能状態も復旧する
・systemctl restart / docker restartを自動判定付きで実行し、復旧確認まで自動で行う
・Slackウェブフックとlogrotateの二重設定で24時間無人運用に対応する
・再起動回数を記録してフラッピング検出と管理者エスカレーションを実装する
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
OllamaのWatchdogが必要になるケースと自動復旧の設計方針
systemdの`Restart=always`やDockerの`restart: unless-stopped`は、プロセスが**終了した**場合に再起動を試みる仕組みだ。しかし、以下のケースではこれらだけでは不十分なことがある。典型的なケースとして、Ollamaプロセスは稼働しているのにAPIへのリクエストが応答しなくなる状況がある。GPUのデッドロック・メモリリーク・ロードしたモデルの破損などが原因として考えられる。この状態ではsystemdやDockerからはプロセス正常と判定され、自動再起動が走らない。
Watchdogスクリプトはこの隙間を埋める。APIエンドポイントに実際にHTTPリクエストを送り、応答を確認する。タイムアウト・異常レスポンスを検出したら再起動をかけ、成功・失敗を問わず担当者へ通知する設計だ。
本記事で構築するWatchdogの構成は次の通りだ。
・ヘルスチェック: curlでOllama APIに接続確認(タイムアウト検出含む)
・再起動: systemdとDocker両対応(環境に応じて自動判定)
・通知: Slackウェブフック通知
・エスカレーション: 1時間以内に3回再起動→再起動を停止して管理者へ通知
・ロック: 多重実行防止のロックファイル実装
・ログ: /var/log/ollama-watchdog.log にタイムスタンプ付きで記録
ヘルスチェックスクリプトを作成する
1. スクリプト配置ディレクトリの準備
# Watchdogスクリプト用ディレクトリを作成する $ sudo mkdir -p /opt/ollama-watchdog $ sudo chown $(whoami):$(whoami) /opt/ollama-watchdog $ ls -la /opt/ollama-watchdog/ total 8 drwxr-xr-x 2 ubuntu ubuntu 4096 Nov 4 10:00 . drwxr-xr-x 8 root root 4096 Nov 4 10:00 ..
2. ヘルスチェック関数の実装
ヘルスチェックの核心は、`/api/tags`エンドポイントへのHTTPリクエストだ。HTTPステータスコードだけでなく、レスポンスボディにJSONが返ってきているかまで確認する。#!/bin/bash # /opt/ollama-watchdog/ollama-watchdog.sh OLLAMA_HOST="http://localhost:11434" LOG_FILE="/var/log/ollama-watchdog.log" RESTART_COUNT_FILE="/tmp/ollama-restart-count" LOCK_FILE="/tmp/ollama-watchdog.lock" MAX_RESTARTS=3 RESTART_WINDOW=3600 log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE" } check_health() { local http_code http_code=$(curl -s --max-time 10 -o /tmp/ollama-health-response \ -w "%{http_code}" "${OLLAMA_HOST}/api/tags" 2>/dev/null) if [ "$http_code" != "200" ]; then log "WARN: API returned HTTP ${http_code} (expected 200)" return 1 fi if ! python3 -c "import json,sys; json.load(sys.stdin)" \ < /tmp/ollama-health-response 2>/dev/null; then log "WARN: API response is not valid JSON" return 1 fi return 0 }
3. ヘルスチェックのみ動作確認
スクリプト作成後、ヘルスチェック部分を単体でテストする。Ollamaが稼働中であれば`HTTP_STATUS: 200`が返る。# curlでOllama APIの応答を直接確認する $ curl -s --max-time 10 -w "\nHTTP_STATUS: %{http_code}\n" \ http://localhost:11434/api/tags {"models":[{"name":"llama3.3:8b-instruct-q4_K_M","model":"llama3.3:8b-instruct-q4_K_M","modified_at":"...","size":4920753664}]} HTTP_STATUS: 200
systemd・Docker両対応の自動再起動ロジックを実装する
1. 管理方式の自動判定ロジック
Ollamaがsystemdで管理されているかDockerで管理されているかを判定する関数を実装する。両方に対応しておくと、サーバーの運用方針変更時にWatchdogを修正せずに済む。# 管理方式の判定(ollama-watchdog.shに追記する) detect_manager() { if systemctl is-active --quiet ollama 2>/dev/null; then echo "systemd" elif docker inspect ollama --format '{{.State.Status}}' \ 2>/dev/null | grep -q "running"; then echo "docker" else echo "unknown" fi } restart_ollama() { local manager manager=$(detect_manager) log "INFO: Detected manager: ${manager}" case "$manager" in systemd) log "INFO: Restarting via systemctl..." sudo systemctl restart ollama ;; docker) log "INFO: Restarting via docker restart..." docker restart ollama ;; *) log "ERROR: Cannot detect Ollama manager. Manual intervention required." return 1 ;; esac }
2. 再起動後の復旧確認ロジック
再起動直後にヘルスチェックを実行しても起動途中で失敗することがある。起動完了を待つ関数を追加する。# 起動完了待機ロジック(60秒タイムアウト・5秒間隔で確認) wait_for_recovery() { local max_wait=60 local elapsed=0 local interval=5 log "INFO: Waiting for Ollama to become healthy (max ${max_wait}s)..." while [ $elapsed -lt $max_wait ]; do sleep $interval elapsed=$((elapsed + interval)) if check_health; then log "INFO: Recovery confirmed after ${elapsed}s" return 0 fi log "INFO: Still waiting... (${elapsed}s elapsed)" done log "ERROR: Recovery failed after ${max_wait}s" return 1 }
3. sudoers設定(非rootユーザー用)
cronをrootユーザーで実行しない場合、`systemctl restart ollama`にsudo権限が必要だ。# /etc/sudoers.d/ollama-watchdogをvisudoで作成する $ sudo visudo -f /etc/sudoers.d/ollama-watchdog # 以下を追加する(usernameは実際の実行ユーザー名に変える) username ALL=(root) NOPASSWD: /usr/bin/systemctl restart ollama username ALL=(root) NOPASSWD: /usr/bin/touch /var/log/ollama-watchdog.log username ALL=(root) NOPASSWD: /usr/bin/chmod 644 /var/log/ollama-watchdog.log
社内でのローカルLLM導入判断については社内でChatGPTが使えないときの代替手段も参考にしてほしい。
Slackウェブフックでアラート通知とフラッピング検出を実装する
1. Slack通知関数の実装
SlackのIncoming Webhookを使ってアラートを送る。事前にSlackのアプリ管理画面でIncoming Webhookを有効にし、URLを取得しておく必要がある。# Slack通知関数(ollama-watchdog.shに追記する) SLACK_WEBHOOK_URL="${SLACK_WEBHOOK_URL:-}" send_slack_notification() { local message="$1" local color="${2:-danger}" [ -z "$SLACK_WEBHOOK_URL" ] && return 0 local payload payload=$(printf '{"attachments":[{"color":"%s","text":"%s","footer":"Ollama Watchdog @ %s"}]}' \ "$color" "$message" "$(hostname)") curl -s -X POST -H 'Content-type: application/json' \ --data "$payload" "$SLACK_WEBHOOK_URL" > /dev/null }
2. フラッピング検出ロジックの実装
短時間に繰り返し再起動が走る「フラッピング」状態では、単純な再起動ループに入るリスクがある。再起動回数を記録し、一定回数を超えたら再起動を停止して管理者に通知する。# フラッピング検出ロジック check_flapping() { local now now=$(date +%s) local count=0 local last_reset=$now if [ -f "$RESTART_COUNT_FILE" ]; then last_reset=$(awk '{print $1}' "$RESTART_COUNT_FILE") count=$(awk '{print $2}' "$RESTART_COUNT_FILE") # ウィンドウ(1時間)をリセットする if [ $((now - last_reset)) -gt $RESTART_WINDOW ]; then count=0 last_reset=$now fi fi local new_count=$((count + 1)) echo "$last_reset $new_count" > "$RESTART_COUNT_FILE" if [ $new_count -gt $MAX_RESTARTS ]; then log "CRITICAL: Restart count ${new_count} exceeded ${MAX_RESTARTS} in ${RESTART_WINDOW}s" send_slack_notification \ "CRITICAL: Ollama restart loop on $(hostname). Manual intervention required." \ "danger" return 1 fi return 0 }
3. Webhook動作テスト
# Slackウェブフックの動作確認(URLは実際のものに差し替える) $ curl -s -X POST -H 'Content-type: application/json' \ --data '{"text":"Watchdog test from '"$(hostname)"'"}' \ "https://hooks.slack.com/services/XXXXX/YYYYY/ZZZZZ" ok
cronで定期実行を設定する
1. 完成版スクリプトのメイン処理
ここまでの関数を組み合わせて、メイン処理と多重実行防止ロックを実装する。# メイン処理(ollama-watchdog.shの末尾に追記する) main() { # 多重実行防止ロック if [ -f "$LOCK_FILE" ]; then local pid pid=$(cat "$LOCK_FILE") if kill -0 "$pid" 2>/dev/null; then log "INFO: Another watchdog (PID ${pid}) is running. Exiting." exit 0 fi fi echo $$ > "$LOCK_FILE" trap "rm -f $LOCK_FILE" EXIT sudo touch "$LOG_FILE" 2>/dev/null sudo chmod 644 "$LOG_FILE" 2>/dev/null if check_health; then log "INFO: Ollama is healthy. No action required." exit 0 fi log "WARN: Ollama health check failed. Starting recovery process." send_slack_notification \ "WARNING: Ollama health check failed on $(hostname). Attempting restart..." \ "warning" if ! check_flapping; then log "ERROR: Flapping detected. Skipping restart." exit 1 fi if restart_ollama && wait_for_recovery; then log "INFO: Ollama recovery successful." send_slack_notification \ "OK: Ollama recovered successfully on $(hostname)." \ "good" exit 0 else log "ERROR: Recovery failed. Manual intervention required." send_slack_notification \ "CRITICAL: Ollama recovery FAILED on $(hostname). Manual intervention required." \ "danger" exit 1 fi } main "$@"
2. スクリプトへの実行権限付与
# 実行権限を付与して動作確認する $ chmod +x /opt/ollama-watchdog/ollama-watchdog.sh # 手動実行でヘルスチェックを通す(Ollamaが稼働中) $ /opt/ollama-watchdog/ollama-watchdog.sh 2026-11-04 10:05:00 INFO: Ollama is healthy. No action required.
3. cronジョブの登録
# crontabを編集する(Ollamaを実行するユーザーで実施する) $ crontab -e # 5分ごとにWatchdogを実行する設定を追加する */5 * * * * SLACK_WEBHOOK_URL='https://hooks.slack.com/services/XXX/YYY/ZZZ' \ /opt/ollama-watchdog/ollama-watchdog.sh >> /var/log/ollama-watchdog-cron.log 2>&1 # 設定確認 $ crontab -l */5 * * * * SLACK_WEBHOOK_URL='https://hooks.slack.com/services/...' \ /opt/ollama-watchdog/ollama-watchdog.sh >> /var/log/ollama-watchdog-cron.log 2>&1
よくあるトラブルと対処法
1. curlがタイムアウトする前に次のcronジョブが起動してしまう
**症状**: Ollamaが重い処理中だとAPIの応答に10秒以上かかることがある。5分間隔のcronで複数のWatchdogが並走すると、再起動が重複して発生する場合がある。対処: 上記で実装したロックファイル機能が多重実行を防ぐ。ロックファイルが残ったまま(Watchdogがクラッシュ等)の場合は手動で削除する。
# ロックファイルが残っている場合は削除する $ ls -la /tmp/ollama-watchdog.lock -rw-r--r-- 1 ubuntu ubuntu 5 Nov 4 10:00 /tmp/ollama-watchdog.lock $ cat /tmp/ollama-watchdog.lock 12345 # そのPIDが存在しないなら削除して良い $ kill -0 12345 2>/dev/null || echo "PID not running, safe to remove" PID not running, safe to remove $ rm /tmp/ollama-watchdog.lock
2. Slack通知が届かない
**症状**: Ollamaが再起動されたがSlackに通知が来ない。確認手順: Webhook URLを直接curlでテストする。`ok`が返れば接続は正常だ。エラーが出る場合はSlackアプリの設定(Webhook有効化・チャンネル指定)を再確認する。
crontab上でWebhook URLを渡す場合、URLにシングルクォートを使うと`&`が解釈されずに済む。
3. logrotateでWatchdogログを管理する
# /etc/logrotate.d/ollama-watchdog に設定する $ sudo tee /etc/logrotate.d/ollama-watchdog << 'CONF' /var/log/ollama-watchdog.log { weekly rotate 4 compress missingok notifempty create 644 root root } CONF # logrotateの設定テスト(--debug でdry-run確認) $ sudo logrotate --debug /etc/logrotate.d/ollama-watchdog reading config file /etc/logrotate.d/ollama-watchdog Allocating hash table... ...
まとめ
OllamaのWatchdogスクリプトについて、ヘルスチェックから通知・エスカレーションまでを実装した。systemdやDockerのrestartポリシーでは補えない「APIが応答しない半死状態」を検知して自動復旧できる体制が整う。主要な設定をまとめると以下の通りだ。| 実装項目 | 実装方法 | 主要コマンド・パラメータ |
|---|---|---|
| ヘルスチェック | curlでAPIエンドポイントを直接確認 | curl -s --max-time 10 http://localhost:11434/api/tags |
| 管理方式判定 | systemctlとdocker inspectで自動判定 | systemctl is-active ollama / docker inspect ollama |
| 自動再起動 | 管理方式に応じてrestart実行 | sudo systemctl restart ollama / docker restart ollama |
| 復旧確認 | 60秒間ヘルスチェックを繰り返す | 5秒間隔×12回 |
| アラート通知 | Slackウェブフック | curl -X POST -H 'Content-type: application/json' |
| フラッピング防止 | 1時間内の再起動回数を記録 | MAX_RESTARTS=3 / RESTART_WINDOW=3600 |
| 多重実行防止 | ロックファイル | /tmp/ollama-watchdog.lock |
| 定期実行 | cronで5分間隔 | */5 * * * * |
OllamaのLinux本番運用スキルを2日間のハンズオンで習得する
WatchdogスクリプトからGPU環境でのOllama本番デプロイまで、実機GPU環境で手を動かしながら習得したい方向けに、「ローカルAIマスターセミナー」を開催しています。
少人数(最大8名)ZOOMハンズオン形式で実施しています。
・Ubuntu ServerでローカルLLMを構築する方法|Ollamaで機密データを外に出さず業務AIを動かす完全ガイド
・社内でChatGPTが使えないときの代替手段|機密データを守るローカルLLMという選択肢
・ローカルLLMのモデルを比較する方法|Llama3.3・Mistral・Gemma・Phi-4をUbuntuで使い分けるポイント
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:OllamaのログをGrafana Lokiで収集・監視する方法|PromtailでAIサーバーの稼働状況を可視化する手順
- この記事の属するカテゴリ:ローカルLLMへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます