対象: JS7 の基本操作を一度触ったことがある人/運用自動化に興味がある人
題材: ワークフロー /ChatGPT_Worker/helloChatGPT のジョブ job-hello-ChatGPT
やること: WorkerNode01 の直近24時間ログを収集 → OpenAI codex (codex exec) で解析 → /home/user/ITOM に Markdown レポートを出力
前提環境: SETUP-mac-m4.md(Controller/JOC)+ WorkerNode01 に Agent 導入済み、かつ WorkerNode01 上で codex login 済み
このドキュメントは、実際に稼働しているジョブのシェルスクリプトを 1ブロックずつ読み解きながら、
「何のために」「どう動くのか」を説明し、最後に 使い方(実行・確認・カスタマイズ) までまとめた解説記事です。
注: 本記事のホスト名・IPアドレス・認証情報はサンプル用の汎用値です。
(IP はドキュメント用レンジ192.0.2.0/24を使用。実環境の値に読み替えてください。)
0. 全体像(このジョブは何をするか)
JS7 Controller ──(指示)──> WorkerNode01 の Agent (http://192.0.2.10:4445)
│
▼
┌──────────────────────────────────────────────────┐
│ 1. 直近24時間のログを収集 (journalctl / 失敗時は /var/log) │
│ 2. 重要行を抽出して ~120KB に圧縮(トークン超過回避) │
│ 3. codex exec に「運用エンジニアとして解析せよ」と指示 │
│ 4. /home/user/ITOM に Markdown レポートを書き出す │
│ 5. codex が失敗してもシェル集計版レポートを必ず生成 │
└──────────────────────────────────────────────────┘
│
▼
/home/user/ITOM/report_<host>_<日時>.md ← 解析レポート
/home/user/ITOM/workernode01_logs_24h_<日時>.log ← 収集した生ログ
ポイントは 「ただのログ収集スクリプト」ではなく、生成AI(codex)に解析・要約・推奨アクション作成までやらせる こと。
人間が毎朝 journalctl を眺める代わりに、AIが日本語の運用レポートを書いてくれます。
1. 前提・準備
| 項目 | 内容 |
|---|---|
| JOC Cockpit |
http://192.0.2.20:17446/joc/(初期 <JOC_USER> / <JOC_PASSWORD>) |
| Controller ID | jobscheduler |
| 実行エージェント |
WorkerNode01(URL http://192.0.2.10:4445) |
| 必須ツール | WorkerNode01 に codex CLI(または npx @openai/codex)が入っていること |
| 認証 |
JS7 のジョブを実行する OS ユーザで codex login 済みであること(後述の「ハマりどころ」参照) |
| 出力先 |
/home/user/ITOM(無ければ自動作成) |
なぜ codex が必要か:このジョブは生ログを AI に渡して自然言語の運用レポートを作らせます。
codex が使えないと、後段の「フォールバック集計版」(grep ベースの簡易集計)に切り替わります。
2. スクリプト全体の構成
スクリプトは大きく 7つのパート に分かれています。
| # | パート | 役割 |
|---|---|---|
| 0 | PATH 解決 + codex 解決 | JS7 特有の「ログインプロファイルを読まない」問題への対処 |
| 1 | ログ収集 | journalctl を主軸に、権限が無ければ /var/log へフォールバック |
| 2 | 圧縮 | 重要行を優先抽出し、AIに渡すサイズを ~120KB に制限 |
| 3 | フラグ検出 | codex のバージョン差を --help で吸収 |
| 4 | プロンプト組み立て | AIへの指示文(章立て付き)を作る |
| 5 | codex 実行 | 解析を実行し、レポートを書き出す |
| 6 | 検証+フォールバック | 失敗時はシェル集計版レポートを必ず作る |
| 7 | 後始末 | 一時ファイル削除と結果サマリー表示 |
以降、コードを引用しながら順に説明します。
3. パートごとの解説
冒頭:エラーで止まる安全設定
#!/usr/bin/env bash
set -euo pipefail
-
set -e… コマンドが失敗(非ゼロ終了)したらスクリプトを止める -
set -u… 未定義変数を使ったらエラーにする(打ち間違い検出) -
set -o pipefail… パイプ|の途中が失敗しても検知する
JS7 はジョブの終了コードで成功/失敗を判定します。
set -euo pipefailで
「気づかないうちに失敗していた」を防ぎます。ただし後半では一部わざと無効化します(理由は §3.6)。
パート0:PATH 解決と codex の発見
export PATH="/usr/local/bin:/usr/bin:/bin:$HOME/.local/bin:$HOME/.npm-global/bin:/usr/local/lib/node_modules/.bin:$PATH"
[ -s "$HOME/.nvm/nvm.sh" ] && export NVM_DIR="$HOME/.nvm" && . "$HOME/.nvm/nvm.sh" >/dev/null 2>&1 || true
for d in "$HOME"/.nvm/versions/node/*/bin; do [ -d "$d" ] && PATH="$d:$PATH"; done; export PATH
なぜ必要か: JS7 Agent はジョブを実行するとき、.bashrc や .profile を読み込みません。
そのため、手で叩けば動く codex や node が、ジョブからは「コマンドが見つからない」になりがちです。
ここでは よくあるインストール先を明示的に PATH へ足し、nvm(Node バージョン管理)配下の node も拾います。
CODEX="$(command -v codex || true)"
if [ -z "$CODEX" ] && command -v npx >/dev/null 2>&1; then CODEX="npx @openai/codex"; fi
if [ -z "$CODEX" ]; then echo "ERROR: codex/npx が PATH に見つかりません。PATH=$PATH" >&2; exit 127; fi
echo "[INFO] using codex: $CODEX"
- まず
codex本体を探す - 無ければ
npx @openai/codex(都度ダウンロード実行)にフォールバック - どちらも無ければ PATH を表示して終了コード127で停止(127=command not found の慣習)
|| trueは「見つからなくてもここでは止めない」ためのおまじない(set -e対策)。
出力先と作業ファイルの定義
HOST="$(hostname)"
TS="$(date +%Y%m%d_%H%M%S)"
OUTDIR="/home/user/ITOM"
mkdir -p "$OUTDIR"
RAW="$OUTDIR/workernode01_logs_24h_${TS}.log" # 収集した生ログ
TRIM="$OUTDIR/.workernode01_trim_${TS}.log" # codex 投入用に圧縮した抜粋
REPORT="$OUTDIR/report_${HOST}_${TS}.md" # 最終レポート
CODEX_ERR="$OUTDIR/.codex_err_${TS}.log"
SINCE="24 hours ago"
-
TS(タイムスタンプ)をファイル名に入れることで、実行ごとに別ファイルになり履歴が残る -
TRIMとCODEX_ERRは先頭が.の隠しファイル(中間生成物) -
SINCE="24 hours ago"… 収集期間。ここを変えれば対象期間を調整できる(§5 参照)
パート1:ログ収集(フォールバック付き)
if command -v journalctl >/dev/null 2>&1 && journalctl --since "$SINCE" -n 1 --no-pager >/dev/null 2>&1; then
journalctl --since "$SINCE" --no-pager # システム全体
journalctl --since "$SINCE" -p err --no-pager # 優先度 err 以上だけ
systemctl --failed --no-pager # 失敗したサービス
else
# /var/log/syslog, auth.log, kern.log ... を tail
# dmesg -T も取得
fi
設計の肝はフォールバック:
- まず
journalctlが 使えるか&権限があるか を実際に1行取得してテスト - 使えれば systemd ジャーナルを採用(最も網羅的)
- 使えなければ
/var/log配下の主要ファイルとdmesgを採用
さらに JS7 Agent 自身のログも探して添付し、最後に df -h(ディスク)と free -h(メモリ)を記録します。
} > "$RAW" 2>>"$RAW" || true
RAW_LINES=$(wc -l < "$RAW" 2>/dev/null || echo 0)
-
{ ... } > "$RAW"… 中括弧でまとめた全出力を1ファイルにまとめて書き出す - 標準エラーも
2>>"$RAW"で同じファイルに追記 -
|| trueで「収集中に一部失敗しても全体は止めない」
パート2:AIに渡すための圧縮
{
echo "##### 重要行(error/fail/warn/critical 等を抽出, 最大3000行) #####"
grep -iE 'error|fail|failed|warn|critic|fatal|panic|segfault|oom|out of memory|denied|refused|timeout|unreachable|reset|kill' "$RAW" | tail -n 3000
echo "##### 全体の末尾(直近の流れ, 最大2000行) #####"
tail -n 2000 "$RAW"
} > "$TRIM"
if [ "$(wc -c < "$TRIM")" -gt 120000 ]; then
head -c 120000 "$TRIM" > "${TRIM}.cut" && mv "${TRIM}.cut" "$TRIM"
fi
なぜ圧縮するか: 生ログは数千〜数万行になり、そのまま AI に渡すと
トークン上限を超えて失敗したり、コストが膨らみます。そこで、
-
grepで 異常を示すキーワードを含む行だけ抽出(最大3000行) - + ログ全体の末尾2000行(直近の流れを把握するため)
- それでも大きければ 先頭120KBで切り詰め
「重要行+直近の流れ」に絞ることで、少ない入力でも見落としにくいバランスにしています。
パート3:codex のバージョン差を吸収
HELP="$($CODEX exec --help 2>&1 || true)"
OUTFLAG=""
echo "$HELP" | grep -q -- '--output-last-message' && OUTFLAG="--output-last-message $REPORT"
SBXFLAG=""
echo "$HELP" | grep -q -- '--skip-git-repo-check' && SBXFLAG="--skip-git-repo-check"
codex CLI はバージョンによって使えるオプションが違います。そこで codex exec --help を読んで、
-
--output-last-message <file>… AIの最終回答だけをファイルに保存できるか -
--skip-git-repo-check… git リポジトリ外でも実行を許可するフラグがあるか
を実行時に自動判定します。これにより、新旧どちらの codex でも動きます。
パート4:プロンプト(AIへの指示文)
PROMPT="あなたは熟練のITインフラ運用エンジニアです。
... 直近24時間のシステムログ抜粋です。
このログを解析し、運用責任者がそのまま読める日本語の運用レポートを Markdown形式で出力してください。
...
# WorkerNode01 ログ解析レポート(直近24時間)
## 1. サマリー(正常 / 注意 / 警告 / 危険 の4段階で総合判定)
## 2. 検出されたエラー・警告(事象・推定原因・件数・代表ログ行 を表で)
## 3. サービス/デーモンの異常
## 4. セキュリティ関連事象
## 5. リソース状況
## 6. 推奨アクション(優先度 高/中/低)
...
-------------------- LOG START --------------------
$(cat "$TRIM")
--------------------- LOG END ---------------------"
これが このジョブの心臓部です。良いレポートを得るコツが詰まっています:
- 役割を与える:「熟練のITインフラ運用エンジニアです」→ 回答の専門性が上がる
- 章立てを固定:6章のテンプレを指定 → 毎回フォーマットが揃い、比較しやすい
- 健全性を4段階で判定させる:パッと見で危険度が分かる
- 前置き禁止:「了解しました等の挨拶は不要」→ そのままレポートとして保存できる
- ログは LOG START / LOG END で挟む:どこからどこまでが解析対象かをAIに明示
カスタマイズの主戦場はここです。章立てや観点を書き換えれば、レポートの中身を自由に変えられます。
パート5:codex 実行
set +e
if [ -n "$OUTFLAG" ]; then
$CODEX exec $SBXFLAG $OUTFLAG "$PROMPT" >/dev/null 2>"$CODEX_ERR"
CRC=$?
else
$CODEX exec $SBXFLAG "$PROMPT" >"$REPORT" 2>"$CODEX_ERR"
CRC=$?
fi
set -e
-
set +e… ここだけset -eを一時解除。codex が失敗しても即終了させず、後段で自分でフォローするため -
--output-last-messageが使える場合:AIの最終回答を直接$REPORTに保存 - 使えない場合:標準出力(stdout)を
$REPORTにリダイレクトして代用 -
CRC=$?… codex の終了コードを記録(後段の判定に使う) - エラーは
$CODEX_ERRに分離(レポートにエラーログが混ざらないように)
パート6:検証とフォールバック(重要)
if [ ! -s "$REPORT" ] || [ "$CRC" -ne 0 ]; then
# codex が失敗 or 空 → grep ベースの簡易レポートを生成
ERRC=$(grep -icE 'error|fail|failed|fatal|panic' "$RAW")
WRNC=$(grep -icE 'warn|critic' "$RAW")
{
echo "# WorkerNode01 ログ解析レポート(直近24時間 / フォールバック集計版)"
echo "## エラー/警告 件数 ..."
echo "## エラー上位(出現頻度) ..." # sort | uniq -c | sort -rn
echo "## failed systemd ユニット ..."
} > "$REPORT"
fi
ここが運用品質を支える部分です。 AI への依存は便利ですが、
ネットワーク断・認証切れ・モデル障害などで失敗することがあります。
そのときでも 「レポートが1個もできない」事態を避けるため、
-
[ ! -s "$REPORT" ]… レポートが空かどうか(-s=サイズ>0) -
[ "$CRC" -ne 0 ]… codex が異常終了したか
のどちらかなら、grep / sort / uniq による機械集計レポートに切り替えます。
AIほど賢くはありませんが、「エラー件数」「頻出エラー」「failed ユニット」は確実に分かります。
パート7:後始末とサマリー
rm -f "$TRIM"
echo "[INFO] レポート : $REPORT"
echo "[INFO] 生ログ : $RAW"
head -n 40 "$REPORT"
exit 0
- 中間ファイル
$TRIMを削除 - 生成物の場所をログに出す(JOC のログ画面で確認しやすい)
- レポート冒頭40行を表示して、JOC のジョブログだけで結果の雰囲気が分かるようにする
- 最後は
exit 0。レポートさえ作れていればジョブは成功扱いにし、スケジュール運用を妨げない
4. 使い方
4-1. GUI(JOC Cockpit)で手動実行する
- ブラウザで
http://192.0.2.20:17446/joc/にログイン(<JOC_USER>/<JOC_PASSWORD>) - 左メニュー インベントリ →
/ChatGPT_Worker/helloChatGPTを開く - ジョブ
job-hello-ChatGPTのスクリプトを確認・編集できる - 編集したら必ず 配置(Deploy) ボタンで反映(配置しないと Controller では動きません)
- ワークフローを右クリック →「オーダーを追加」→
now(すぐ実行)
4-2. 実行結果を確認する
- JOC の 履歴 / ログ からジョブログを開くと、
[INFO] レポート : ...の行で保存先が分かる - WorkerNode01 上で実物を確認:
ls -lt /home/user/ITOM/ | head
cat /home/user/ITOM/report_*_*.md | head -60
4-3. 定期実行(毎日自動でレポート)
このジョブは既存のスケジュール(ChatGPT_平日 カレンダー+「8時」スケジュール)に紐づけられます。
配置済みであれば、毎朝8時に自動でレポートが /home/user/ITOM に蓄積されていきます。
5. カスタマイズの勘どころ
| 変えたいこと | 触る場所 |
|---|---|
| 解析対象の期間(例:直近7日) |
SINCE="24 hours ago" → "7 days ago"
|
| レポートの章立て・観点 | パート4の PROMPT 内のテンプレ |
| AIに渡すログ量(コスト・精度の調整) | パート2の tail -n 3000 / tail -n 2000 / 120000(バイト上限) |
| 出力先フォルダ | OUTDIR="/home/user/ITOM" |
| 別ホストにも流用 | 文中の WorkerNode01 / IP 表記と、対象ログの選び方を見直す |
古いレポートを自動で消したい場合は、末尾に世代管理を追加する例:
find /home/user/ITOM -name 'report_*_*.md' -mtime +30 -delete
6. ハマりどころ(トラブルシュート)
| 症状 | 原因 | 対処 |
|---|---|---|
ERROR: codex/npx が PATH に見つかりません |
Agent が .bashrc を読まない/codex 未導入 |
WorkerNode01 に codex を入れ、パート0の PATH に実体の場所を追加 |
| レポートが「フォールバック集計版」になる | codex が失敗(認証切れ・ネット断・モデル障害) |
$CODEX_ERR(/home/user/ITOM/.codex_err_*.log)を確認。ジョブ実行ユーザで codex login 済みか確認 |
| ログがほぼ空 | journalctl 権限不足で /var/log にもアクセス不可 | 実行ユーザを adm / systemd-journal グループに追加、または sudo 構成を検討 |
| codex がトークン超過で失敗 | ログが巨大 | パート2の行数・バイト上限を下げる |
| ジョブは成功なのに中身が薄い | 解析期間に異常が少ない(健全) | 正常時はサマリーが「正常」になるのが期待動作 |
7. まとめ
このジョブは「ログ収集スクリプト」に 生成AI(codex)による解析・要約・推奨アクション を組み合わせた、
ITOM(IT運用管理)の自動化サンプルです。設計上の工夫は次の3点に集約されます。
- JS7 特有の環境問題に強い:PATH を明示し、codex のバージョン差も自動吸収
- AIに優しい入力:重要行を抽出・サイズ制限してトークン超過とコストを抑制
-
必ず成果物を残す:codex 失敗時もシェル集計版にフォールバックし、
exit 0で運用を止めない
関連ドキュメント:
実測は総計 約6.4万トークンを消費