配信ページにはタイムアウトが表示され、Jenkins 側には何も記録されませんが、これは接続が一度も届かなかった証拠です。GitHub は Webhook を、自身のインフラから設定した payload URL へ向かう外向きの HTTP POST として送信します。VPN はまさにその種の接続を拒否することで Jenkins を守ります。どちらの側も壊れてはいません。問題はリクエストの向きです。

配信が実際に試みていること

GitHub は payload URL のホスト名を解決し、公開インターネットからそこへ接続します。その URL がプライベートアドレスを指す場合、またはネットワークの内側でしか解決できない名前を指す場合、リクエストが送られる前に試行は失敗します。エッジが破棄する公開名を指す場合は、代わりに試行がタイムアウトします。

この違いは診断で重要です。DNS の失敗とフィルタされたポートはどちらも Jenkins 側で何も起きていないように見え、どちらも GitHub 上では別の理由が添えられた配信失敗として表示されます。URL を変える前にその理由を読んでください。

外向きにダイヤルするトンネルはリスナーを作りません。人々が違う動きを期待するのはまさにこの部分です。

接続の向きを直す三つの方法

どの解決策も接続を始める主体を変えるもので、形は三つしかありません。

ApproachWho initiatesWhat you give up
Relay serviceAn outbound client inside the networkA third party sees every payload
Reverse tunnel or ingressThe public edge, into a controlled listenerAn inbound surface you must secure
Runner or pollingThe agent, outbound to GitHubInstant delivery, replaced by a schedule

ポーリングは最も洗練されていませんが、運用は最も簡単です。relay はポートを開かずにほぼ即時のフィードバックを保ちます。payload の機密性が第三者を排除する場合、ジョブはすでにネットワークの内側にあるマシンで実行できるため、runner が通常は正解です。

運用できるかどうかで選び、モダンに聞こえるかどうかで選ばないでください。

smee で配信を外へ中継する

relay サービスでチャネルを作成し、その URL を保持します。ネットワークの内側でクライアントをインストールし、Jenkins が期待するパスへ配信を転送します。リポジトリ設定の payload URL がチャネルの URL になり、コンテンツタイプは application/json に設定します。

sudo npm install --global smee-client
smee -u CHANNEL_URL --path /github-webhook/ --port 8080

動くかどうかは三つの詳細で決まります。パスは Jenkins が GitHub イベントに期待するものと一致する必要があり、既定では /github-webhook/ です。Jenkins はクライアントに渡したポートで待ち受けている必要があります。そしてジョブに設定された Jenkins URL がそのパスと一致していなければ、イベントは届いた後に破棄されます。

末尾のスラッシュが一致しないと 404 になり、配信失敗のように読めますが失敗ではありません。

一週間もちこたえるように動かす

フォアグラウンドのクライアントはターミナルとともに死に、Webhook は一日動いて止まります。Restart=always を付けた unit を与え、Jenkins ユーザーとして実行し、最初の実際の配信の後に journal を読んでください。最後のこの手順が、動く relay と設定済みの relay を分けます。

[Unit]
Description=smee webhook relay
After=network.target

[Service]
Type=simple
Restart=always
RestartSec=2
User=jenkins
ExecStart=/usr/bin/smee -u CHANNEL_URL --path /github-webhook/ --port 8080

[Install]
WantedBy=multi-user.target

リプレイボタンではなく実際の push でテストしてください。リプレイは relay が保存した payload を動かすだけで、GitHub からチャネルまでの経路を動かさないため、ライブ配信が失敗したままでも通ってしまいます。

unit が止まったら警告を出してください。落ちている relay は構造上無音であり、その無音こそがあなたがすでにデバッグしているものです。

relay が見られるもの、使うべきでないとき

relay は payload を終端するため、リポジトリ名、commit データ、イベントが運ぶその他すべてを見ます。チャネルの URL は公開エンドポイントとして扱ってください。偽の配信が拒否されるよう Jenkins の secret token を設定したままにし、Jenkins が使う token の範囲を必要最小限に限定してください。

payload の機密性がそれを排除するなら、セルフホストの runner または認証済みのリバーストンネルが答えです。

relay はいまやインフラであり、それが起動する build と同じレビューに値します。漏えいしたらチャネルをローテーションし、最後にライブ配信を検証した日付を記録してください。その日付をチャネルの URL の隣の runbook に書きます。一年間誰もレビューしていない relay は、誰も所有していない公開エンドポイントです。

関連記事