macOS · コマンド一つ · 127.0.0.1
Launchd に dashboard はない。自分の launchd service をブラウザで管理する console で、Prometheus metrics も出す。
コマンド一つで入る。ブラウザで status、log、alert を見る。
| ラベル | PID | 終了 | 再起動 | 操作 | |
|---|---|---|---|---|---|
サンプルアプリ3105 件 | |||||
com.example.app.api自前記載あり | 730872h 14m | 0 | 28 | 🔔再起動ログ | |
com.example.app.web自前自動(パス)↻ 再起動多発 | 730916d 3h | 0 | 1207↻ | 🔔再起動ログ | |
com.example.app.collector自前自動(パス) | 7310418m | 0 | 21 | 🔔再起動ログ | |
com.example.worker.nightly自前記載あり | — | 1 | 3 | 🔔開始ログ | |
com.example.backup.weekly自前自動(パス)次回 · Sun 03:00 | — | 0 | 0 | 🔔開始ログ | |
運用0012 件 | |||||
com.example.worker.old自前記載あり⏹ 退役 12日 | — | — | 0 | 有効化ログ | |
com.example.legacy.agent自前自動(パス) | — | 0 | 0 | 開始ログ | |
自前・その他・ノイズをクリック。それから /metrics と Telegram 通知。
理由
launchctl は全部出す。だから、何も見えない。
標準のツールが答えるのは「何が読み込まれているか」であり、「何をデプロイし、それは健全か」ではありません。ユーザードメインで絞り込んでも同じです。動いている Mac では、「自分の」ジョブに見えるものの大半が Dropbox、Google のアップデータ、Spotify、Tailscale、ブラウザのヘルパーです。1,207 回再起動しているジョブは、その真ん中に埋まっています。
Deployboard は、明示的な台帳から始めます。自分で書く許可リストと、パスからの導出です。plist のログパス、作業ディレクトリ、program、引数のいずれかがプロジェクトツリーの中にあれば、そのジョブは自動的に自分のものです。それ以外はシステムの用事であり、ワンクリックで届きますが、邪魔にはしません。
- launchctl list — 545 行。どれが自分のものか分からない
- 静かに 1,207 回再起動した開発サーバーが、正常に見える
- 意図して無効にした plist が、いつまでも障害に見える
- 履歴がない。「これは平常か?」に答えがない
- 何かが死んだことに、偶然気づくまで分からない
- 自前 / その他 / ノイズ — 初期表示は自分のデプロイ
- launchctl print の runs(再起動回数)。閾値を超えると印が付く
- disabled は状態であり、エラーではない。退役は退役のまま
- Prometheus の /metrics。Grafana で「いつから」が見える
- 遷移のときに Telegram 通知。アプリごと、クールダウン付き
状態
状態は七つ。その一つは「自分で退役させた」。
多くのツールは running / stopped / error に潰してしまいます。すると、何ヶ月も前に自分で止めた plist が、永遠に障害として表示されます。Deployboard は launchd が実際に区別している状態を保ち、launchctl print-disabled を読むので、意図も答えの一部になります。
PID > 0 — launchd print も生存に同意している
PID = 0、正常終了、スケジュールあり、直近のログなし
PID = 0、正常終了、ログの mtime が --recent-window 以内
PID = 0、正常終了、スケジュールなし、直近のログなし
直前の終了ステータスが非ゼロ
launchctl print-disabled が disabled、生きている pid はない — 退役であり、故障ではない
plist ファイルはあるが、launchctl list がラベルを返さない
このフォークが足すもの
本家が答えるのは「何が読み込まれているか」。こちらが答えるのは「何をデプロイしたか」。
追加は四つ。どれも launchctl 自身の出力の上に乗せてあり、ジョブがどのベンダーのものかを推測しません。
launchctl print を使う。launchctl list ではない。
launchctl list には再起動回数も disabled フラグもありません。Deployboard は runs と pid を launchctl print から、意図を launchctl print-disabled から読みます。回転が見え、意図して退役させたジョブが故障に見えなくなります。
台帳は、自分で決める。
自前 / その他 / ノイズ。各行に出処があります(記載あり、自動(パス)、未分類)。分類の操作は config.json に書き戻され、約 2 秒でホットリロードされます。新しいアプリを教えるのに再起動は要りません。
launchd のための Prometheus メトリクス。
deployboard_job_up、_runs、_last_exit_code、_disabled に加え、IPv4/IPv6 のポートプローブがあります。ダッシュボードが言えるのは「今落ちている」までです。時系列なら「03:10 から回転し始めた」と言えます。
アプリごとの切替が付いた Telegram 通知。
通知するのは遷移だけです。error、offline、ポート到達不能、再起動ストーム、そして復旧。アプリごとのスイッチ、クールダウン、静音時間があり、ボットのトークンは macOS のキーチェーンに置きます。ファイルには書きません。
ジョブごとの stdout と stderr。最大 10,000 行、ライブで絞り込めます。
終了コード、program の存在、実行権限、plist の所有者、plist のパーミッション、ログパス。
GET /api/events が、ジョブ一覧全体を 5 秒ごとに送ります。
launchctl 経由の start / stop / reload。確認ダイアログ付きです。
UI が使っているのと同じ面。文書化されていて、curl で触れます。
Go のバイナリ一つ。フロントは go:embed。常駐デーモンもテレメトリもありません。
メトリクス
この領域で、唯一の launchd exporter。
Prometheus には、UI と同じポートを向けてください。ラベルのカーディナリティは有界です。一度も終了していないジョブに last-exit の系列は出さず、ポートを公開しているジョブにだけ probe の系列を出します。一部の開発サーバーは IPv6 の ::1 にしかバインドしないため、プローブはそこも試します。
# HELP deployboard_job_up 1 when the launchd job is running.# TYPE deployboard_job_up gaugedeployboard_job_up{label="com.example.app.api",category="ours",group="Example App"} 1deployboard_job_runs{label="com.example.app.web",category="ours",group="Example App"} 1207deployboard_job_disabled{label="com.example.worker.old",category="ours"} 1deployboard_job_probe_reachable{label="com.example.app.api",port="8001"} 1deployboard_job_probe_latency_seconds{label="com.example.app.api",port="8001"} 0.003deployboard_jobs_total{category="ours"} 16deployboard_jobs_total{category="noise"} 528
# restart churn, per job, over 6hderiv(deployboard_job_runs{category="ours"}[6h]) * 3600# anything of yours that is not runningdeployboard_job_up{category="ours"} == 0
UI を配信しているのと同じプロセスからスクレイプできます。別の exporter も sidecar も要りません。出せない系列は省き、値は作りません。一度も終了していないジョブに last_exit の行はなく、ポートのないジョブに probe の行はありません。
アラート
Telegram に、一度だけ知らせます。
遷移ベースなので、フラッピングするジョブが通知を埋め尽くすことはありません。壊れたときに一通、再起動が続くときはレート制限された一通、戻ったときに一通です。復旧の通知は静音時間でも抑止しません。ボットのトークンは macOS のキーチェーンにあり、ダッシュボード自身が書き込みます。ファイルにも、ログ行にも、ページの応答にも出しません。
API
UI が使っているものは、スクリプトからも使えます。
Web UI は /api/jobs と /api/events の利用者の一つです。curl も同じです。サーバーをバインドし、エンドポイントを向き、JSON を解析してください。
インストール
コマンド一つ。設定ファイル一つ。タブ一つ。
導入は3通りで同じバイナリ: Homebrew cask(ヒーローのコマンド)、Go なしで LaunchAgent まで入れる curl install-release.sh、クローンからの bash install.sh。sudo 不要。スクリプトは --dry-run と --uninstall 対応。
$ brew install --cask francistse/tap/deployboardHomebrew の cask でバイナリを入れるか、install-release.sh / install.sh で RunAtLoad + KeepAlive の LaunchAgent まで入れます。sudo 不要。スクリプトには --dry-run と --uninstall もあります。
$ open ~/.config/deployboard/config.jsonconfig.json の inventory.ours に名前空間を書くか、derive_roots にプロジェクトのフォルダを足して、plist のパスに分類させます。未分類のものは「その他」に出ます。UI でワンクリックすれば固定でき、config.json はホットリロードされます。
ダッシュボードは 127.0.0.1 で開きます。Prometheus から /metrics をスクレイプし、ベルでアプリごとの通知を切り替え、テーマをシステム、ライト、ダークから選べます。
状態の値
本家の六つ + disabled
設定のホットリロード
再起動なしで新しいアプリを分類
Prometheus の系列ファミリー
ジョブ、runs、終了コード、プローブ
バインドする唯一のアドレス
クラウドなし、テレメトリなし、更新確認の通信なし
FAQ
フォークなら、答えておくべき質問。
本家とどういう関係か、も含みます。
フォーク元の launch-pilot と、何が違いますか?
本家ができることは、そのまま残しています。ジョブ表、ログの追尾、六つの診断、start/stop/reload です。Deployboard が足すのは、台帳ビュー(パス導出付きの自前 / その他 / ノイズ)、launchctl print による補強(runs と disabled)、Prometheus のエンドポイント、アプリごとに切り替えられる Telegram 通知、コマンド一つの macOS インストール、そして読み取り専用モードです。
どのジョブが自分のものか、どうやって分かりますか?
規則は二つで、この順です。まず自分で書く許可リスト(inventory.ours)。次に導出です。plist のログパス、作業ディレクトリ、program、引数のいずれかが derive_roots に挙げたディレクトリの中にあれば、そのジョブは自分のものです。plist が指しているものはすべて証拠なので、推測もドメインの経験則も使いません。
ジョブを間違えたらどうなりますか?
「その他」に出てきて、「未分類」と付きます。行から自動 / 自前 / 隠すを選べます。それが config.json に書き込まれ、サーバーは約 2 秒でホットリロードします。静かに隠すことはありません。launchd の全一覧は、常にチップ一つ先にあります。
このうち何かが、自分のマシンの外に出ますか?
出ません。HTTP サーバーは 127.0.0.1 にだけバインドし、分析も電話ホームもありません。プロジェクト全体が外に出せる通信は、明示的に有効にした Telegram メッセージだけです。トークンは自分のキーチェーンにあります。
通知なしで、メトリクスだけ使えますか?
使えます。通知の初期値は、自分のアプリではオン、それ以外ではオフです。アプリごと、カテゴリごと、または全体で止められます。/metrics と JSON API はそのまま動き、--read-only は変更を伴う呼び出しをすべて拒否します。
なぜ plist を決して編集しないのですか?
意図的です。Deployboard は launchd の状態を読み、launchctl にラベルの start、stop、reload を頼めますが、ディスク上の plist は書き換えません。plist エディタが必要なら、定番の有料オプションは LaunchControl です。このツールが扱うのは、デプロイが何をしているかを知ることです。