CI ランナーの VPN:トンネルはビルドより長生きするか
共有 CI ランナーはジョブ間でルートとプロセスを保持します。VPN の作業前・作業中・作業後の状態を設計し、ジョブが所有する接続だけを片付けます。
デプロイのジョブは接続し、成果物をコピーして成功を報告します。そのジョブが開いたトンネルは、次のジョブが始まる時点でもまだ上がっていることがあり、変更したルートはホスト全体に属します。ビルドの結果が語るのはコマンドであり、残された状態ではありません。VPN は寿命を持つ資源として扱い、ステージ冒頭の一行として扱わないでください。
このホストで他に動いているもの
Jenkins のノードは複数のエグゼキューターを同時に動かせます。ホストのルート、リゾルバーの設定、システム全体の接続を変えるジョブは、それらを全員のために変えてしまいます。他のジョブが気づくかどうかはルートとフィルタリングの方針次第であり、VPN 一般の決まりではありません。リポジトリへのアクセス、成果物へのアクセス、制御チャネルは別々の要件で、ランナーはどれも必要とします。完全なトンネルを選ぶ前に、それらをデプロイ先の一覧に加えてください。
制御チャネルがトンネルを横切るなら、設計はそれを意図して明記しなければなりません。ロールバック中に気づくのは計画ではありません。二つの一覧を書き出します。ジョブが私的に到達すべきものと、ランナーが何があっても到達すべきものです。
このジョブに私的なアクセスは本当に必要なのか
トンネルを足す前に、ビルドのステージにそれが必要かを問い合わせてください。専用のデプロイエージェントが承認済みの成果物を取得してデプロイを実行すれば、一般的なビルドのステージを私的なネットワークの外に保てます。その分離は、ビルドの各手順にトンネル経由のルーティングを教えるより、たいてい安く済みます。
境界は習慣ではなくワークフローから選んでください。答えが不要なら、このページの残りは不要であり、それが得られる最良の結果です。
次のジョブが引き継ぐ状態
ジョブの前、私的なアクセスを持っている間、そして終了後に何が成り立つべきかを、キャンセルも含めて書きます。終了時の状態こそが最も暗黙に残されがちで、次のジョブが引き継ぐのはそれです。誰かの記憶に残すのではなく、パイプラインの隣に書き留めてください。
| Moment | What proves it | What leaks if it is skipped |
|---|---|---|
| Job start: pre-flight route check | The route table shows no tunnel from an earlier job, and the profile list is empty | A stale route sends deployment traffic into a dead tunnel |
| Job end: disconnect and shred | The profile is down and the temporary key file is gone | The next job inherits an open tunnel and a usable credential |
| Cancelled job: reboot or disposal | The host is replaced or rebooted before the next job starts | A killed process leaves the tunnel up with no owner |
専用または使い捨てのエージェントは、その境界を強制しやすくします。コンテナや名前空間が役立つのは、そのネットワークと権限の配置が変更を実際に隔離する場合だけです。
プログラムではなく接続を止める
このジョブが開始した接続を閉じ、一時的な資格情報を削除するには、パイプラインの終了処理の経路を使います。他のジョブが使うホストで、プログラム名によるプロセスの照合をしないでください。代わりにその特定の接続を止めます。下の二つのコマンドが片付けのすべてで、どちらもプロセスを探すことに依存しません。
vpn-cli disconnect --profile "$PROFILE"
rm -f "$RUNNER_TEMP/client.key"
終了処理は隔離ではありません。死んだランナーは開いたトンネルを残し、強制停止されたプロセスはそのブロックを丸ごと飛ばします。だから片付けのコマンドだけでは設計の全体になりえません。実際にはこう失敗します。デプロイのジョブがコピーの手順でキャンセルされ、終了処理のブロックは一度も走らず、同じホストの次のジョブが生きたトンネルと、到達できないネットワークを指すルートを抱えて始まります。その障害は次のビルドで 'DNS' の問題のように見え、原因となったジョブが終わってから数時間後に現れます。
プロファイル名と資格情報のパスをジョブの出力に記録します。識別子のない裸の切断コマンドは、後から監査しにくいものです。後日の調査が問い合わせたときに、そのブロックが走ったことを証明するのもログの一行です。
誰も使っていないホストをジョブに与える
使い捨ての基盤は、引き継ぎの問題を管理するのではなく取り除きます。ジョブごとに新しいエージェントは、ルートもプロファイルも他人の資格情報もない状態で始まり、破棄されればジョブが残したものを片付けます。ビルドあたりの費用は増えますが、片付けのコードに依存しない境界の正直な代価です。本番ネットワークに触れるジョブでは、インシデントを数えればたいてい安い選択になります。
共有ランナーを残さざるを得ない場所では、失敗とキャンセルを成功したコピーと同じだけ丁寧に試験します。試験は、このジョブが途中でキャンセルされたら次のジョブが何を見るかを示すべきです。ジョブが終わるのは、そのアクセスと一時的な状態が終わったときであり、コピーのコマンドがゼロを返したときではありません。