プロダクト

Dagu がどこで動いていても、GitHub、Stripe、Slack からワークフローを起動する

Dagu v2.20 では、DAG の Webhook に Dagu Cloud 経由の公開 URL を付けられます。公開アドレスのないサーバーでも、GitHub、Stripe、Slack から DAG を起動できます。サーバーがオフラインの間、リクエストはサーバーを待ちます。

Yota Hamada
Share

TL;DR Dagu v2.20 では、DAG の Webhook に Dagu Cloud 経由の公開 URL を付けられます。GitHub、Stripe、Slack、または Standard Webhooks に対応した送信元から、公開アドレスも、開いたポートも、トンネルもないサーバーの DAG を起動できます。サーバーがオフラインの間に届いたリクエストは、サーバーを待ちます。DAG の Webhook タブからオンにしてください。

Dagu の DAG にはどれも Webhook を付けられ、社内ネットワークの中からはこれまでも簡単に呼び出せました。問題は Webhook を送る側のサービスです。GitHub、Stripe、Slack はインターネット上にあり、Dagu サーバーはたいていそうではありません。プライベートサブネットの VM や、オフィスのマシンや、誰かのノート PC で動いています。

よくある答えは、ポートを開ける、トンネルを動かす、サーバーの前にリバースプロキシを置く、のいずれかです。どれも、動かし、守り、生かし続けるものが 1 つ増えます。しかも、リクエストが届いたちょうどそのときにサーバーが再起動中なら、どれも役に立ちません。

できること

  • インターネット上のアドレス: URL は hooks.dagu.sh にあります。サーバーは HTTPS で Dagu Cloud へ外向きに接続し、サーバーへ内向きに接続するものはありません。
  • 待ってくれるリクエスト: Dagu Cloud は、サーバーが受け取るまで、最大 7 日間リクエストを保持します。デプロイや再起動の最中に届いた push も、サーバーが戻れば実行を開始します。
  • 1 リクエストにつき 1 実行: Dagu Cloud が同じリクエストを再送しても、開始する実行は最大 1 つです。
  • 署名の検証: 送信元に GitHub、Stripe、Slack、Standard Webhooks のいずれかを選ぶと、その送信元の有効な署名がないリクエストを Dagu が拒否します。署名シークレットはサーバーから出ません。
  • 必要なイベントだけ: push や pull_request.opened のようにイベントを並べると、それ以外はスキップされます。
  • すべての配信の記録: カードには最近の配信と、それぞれがどう処理されたか、開始した実行へのリンクが表示されます。
Dagu の DAG の Webhook タブにある Public URL のカード。hooks.dagu.sh の URL、送信元に GitHub、イベントに push だけを選んだ設定と、最近の配信が表示されている。push 2 件が実行を開始し、ping と issues.opened はスキップされ、署名が不正な push は拒否された

GitHub で設定する

  1. サーバーを Dagu v2.20 以降に更新し、プランと機能 から Dagu コンソール に接続します。ワークスペースごとに 1 台は無料で接続できます。
  2. DAG を開いて Webhook タブを開き、Webhook がなければ作成します。
  3. 公開 URL のスイッチをオンにします。数秒で URL が表示されます。
  4. 送信元に GitHub を選び、イベント に push と入力して、送信元を保存 を選びます。Dagu が署名シークレットを作り、一度だけ表示します。
  5. GitHub のリポジトリの Settings › Webhooks で、URL を Payload URL に貼り付け、Content type を application/json にして、シークレットを貼り付けます。

保存すると、GitHub は ping を送ります。ping は実行を開始しないので、カードにはスキップとして表示されます。コミットを push すると、次の行が 開始済み になり、実行へのリンクが付きます。

実行が受け取るもの

実行は、リクエストを 3 つの変数で受け取ります。

  • WEBHOOK_PAYLOAD: 送信元が送ったとおりのボディ。
  • WEBHOOK_PAYLOAD_FILE: 同じボディを保存した非公開ファイルのパス。実行が終わると削除されます。
  • WEBHOOK_HEADERS: webhook.forward_headers に並べたリクエストヘッダー。

ボディが大きくなりうるときは、ファイルを読んでください。Linux と macOS では 1 つの環境変数に入るのは 128 KiB 未満なので、それより大きなボディはファイルとしてだけステップに届きます。

webhook:
  forward_headers:
    - X-GitHub-Event

steps:
  - id: deploy
    run: |
      branch=$(jq -r '.ref' "$WEBHOOK_PAYLOAD_FILE")
      ./scripts/deploy.sh "$branch"

制限

無料モニタリングトライアル、Team、Pro
サーバーごとの公開 URL1 個1,000 個
リクエストボディ512 KiB512 KiB
URL ごとのリクエスト1 分間に 60 件1 分間に 60 件
サーバーごとの待機中のリクエスト1,000 件1,000 件

制限を超えた送信元には、黙って捨てるのではなく、Retry-After 付きの 429 のように、はっきりしたステータスコードが返ります。

Dagu Cloud に見えるもの

Dagu を自分のサーバーで動かすのは、ワークフローを手元に置くためです。だからこそ、途中で Dagu Cloud を通るものが何かは重要です。

  • リクエストは一時的に: Dagu Cloud は、各リクエストのボディとヘッダーを、サーバーが受け取るまで、最長 7 日間だけ保存します。サーバーに渡す前に、Authorization や Cookie などの認証情報とプロキシのヘッダーを取り除きます。
  • トークンは保存しない: URL の末尾はランダムなトークンです。Dagu Cloud が保存するのは、その SHA-256 だけです。
  • シークレットは受け取らない: 署名はサーバー上で、Dagu Cloud が受け取ることのないシークレットで検証します。
  • サーバーから届くのはごくわずか: サーバーが送るのは、サーバー名、Dagu のバージョン、各配信をどう処理したかだけです。ワークフロー、ログ、出力がサーバーから出ることはありません。

URL をオフにすると、約 10 秒以内に URL が無効になり、待っていたリクエストも破棄されます。

試してみる

サーバーを v2.20 に更新して接続し、GitHub のリポジトリを 1 つ向けてみてください。公開 Webhook URL のドキュメントに、すべての送信元、それぞれが送るイベント、うまくいかないときに送信元に返るものをまとめています。質問やアイデアがあれば Discord で教えてください。

· · ·

Written by

Yota Hamada

Daguプロジェクトのコントリビューター。

More from Yota Hamada