コアユニットの起動時間を数時間から数分に短縮した方法
Cloudflareのコアは、コントロールプレーン、課金、分析を実行する集中型データセンター群であり、ユーザートラフィックを処理するグローバルに分散したエッジとは別物です。コアサーバはベアメタルで稼働しており、再起動時の問題は迅速に連鎖的な影響を及ぼします。起動シーケンスは UEFI によってオーケストレーションされ、ハードウェアを初期化してOSに制御を渡します。この引き渡しにおける小さな挙動の違いが大きな影響を生じさせることがあります。
ルーチンなファームウェア更新の後、一部のコアサーバは以前のように数分で戻るのではなく、復旧に4時間かかることがありました。本来1日で終わるはずのフリート全体のロールアウトが複数日にわたる作業に伸び、新しいノードは初回ブートで完全なタイムアウト地獄にさらされ、メンテナンスウィンドウは膨張し、エンジニアは無人で済むはずのアップグレードに付き添わなければなりませんでした。この問題はGen12フリートほぼ2,000台に影響しました。
これは、ファームウェアの挙動と利用可能なすべてのネットワークブートインターフェースを過剰に線形検索してしまう自動化の組み合わせが原因で、合計のブート/アップグレード時間を数時間から数分に戻した経緯の記録です。途中でUEFI内部やベンダー固有の動作、最終的に問題を解決した自動化戦略についての学びも共有します。
ネットワークブートインターフェース
ネットワークブートインターフェースは、サーバがローカルストレージではなくネットワーク経由でOSを起動することを可能にします。これは、集中管理された自動化された大規模な起動制御に不可欠で、異なる環境・用途に設置されたサーバに対して柔軟に対応できます。
主なインターフェースは以下です。
- PXE (Preboot Execution Environment)
- UEFI HTTPS boot
Cloudflareでは、iPXE(HTTP/HTTPSなどのモダンプロトコルをサポートするオープンソースのネットワークブートファームウェア)を使用しています。iPXEにより、OSイメージをウェブサーバやクラウド、エンタープライズストレージから直接ブートでき、高速かつ信頼性の高い起動が可能になります。iPXEは起動プロセスをプログラム可能なワークフローに変え、ハードウェア構成に応じたプロビジョニングやセキュアなディスクレスワークステーションの管理といった複雑な展開を自動化できます。
一部ハードウェアはHTTPSベースのUEFIネットワークブートをネイティブにサポートしており、マザーボードのファームウェアが安全にOSファイルをダウンロードできます。
線形探索(The linear search)
問題の発端は、あるファームウェア更新でした。更新後、内部チャネルに「サーバが戻らない」という報告が入り、監視ダッシュボードは機器が予想より遥かに長くpre-OS状態で止まっていることを示していました。
まずはファームウェアのリグレッションを疑い、影響を受けたマシンのシリアルコンソールを開いてブートをリアルタイムで観察しました。POSTは正常、ハードウェア初期化も問題ありませんでした。しかし、素早くネットワークブート段階に進んでOSイメージを取得する代わりに、サーバはただ待ち続けていました。
コンソール出力はこう語っていました: システムはIPv4 HTTPSネットワークブートを試み、数分でタイムアウトし、次にIPv4 iPXEを試みてまたタイムアウトし、それを繰り返した後でようやく成功するIPv6 HTTPSブートインターフェースに到達していました。失敗するネットワークブート試行ごとに約5分のタイムアウト待ちが発生し、正しいインターフェースに到達するまでに4回分が積み重なると、単一のブートで約20分が無駄になっていました。
ルーチンな再起動でも痛手ですが、各コンポーネントごとに再起動が必要なファームウェアアップグレード自動化では、これらの20分ペナルティが重なって1台あたりほぼ4時間のアイドル待ちになっていました。
インターフェースを明示する — 探索をやめる
ブートシーケンスを追跡しタイムアウトパターンを特定すると、原因は明白でした: サーバが利用可能なすべてのネットワークブートインターフェースを順に盲目的に探しており、応答しないインターフェースごとに待ち時間を消費していたのです。解決策は推測を排し、正しいブートインターフェースを事前に宣言して、応答しないインターフェースに時間を浪費させないことでした。
ただし、実際にこれを運用に落とし込むにはいくつかの障害がありました:
- ブート自動化ワークフローの順序
- 変更がブロックされている設定
- NICベンダー間での文字列フォーマットの違い
ブート自動化ワークフロー
我々のブート自動化は大きく3つの段階に分かれます: ファームウェア初期化、プリブート、カーネル起動。電源投入後、UEFIファームウェアがハードウェアと周辺機器の初期化を行い、PXEプリブート環境に移ります。プリブートはNICをセットアップし、bootloaderと呼ばれる小さなプログラムを実行してカーネルを起動します。このPXE段階で適切なネットワークインターフェースがプローブされます。
初回ブート時にはファームウェアアップグレードが自動化フローに含まれており、各アップグレードが再起動を必要とするため、合計でほぼ4時間になっていました。プリブート(PXE)段階の早い段階で各ハードウェア/ユースケースに対してネットワークブートの優先順序を明示するよう自動化を再構成することで、それぞれのファームウェアアップグレードで20分を費やして探索する必要がなくなり、合計で約1時間分の短縮が得られました。
ネットワークブート順序を設定しようとした際に生じた2つの制約:
- Legacy Support: 古いUEFIバージョンではブート順序設定がサポートされていない
- Persistence: UEFIファームウェアのアップグレード後に設定がリセットされることがある
これらのエッジケースに対処するため、状態検証のステップを実装しました。ファームウェア自動化は変更後に設定を検証し、設定が変更されていることを検出した場合は再適用して再起動をトリガします。初回ブートはわずかに長くなる可能性がありますが、この変更により以降の起動時間は大幅に短縮され、約20分が1分未満に改善されます。
ベンダーにより無効化されていたブート順設定
ネットワークブート設定の内部データ構造はEFI_IFR_REF3で、遅延ロード(lazy loaded)されていました。つまり、そのデータはGUIのコールバックで明示的にアクセスされるまでインスタンス化されません。
typedef struct _EFI_IFR_REF3 {
EFI_IFR_OP_HEADER Header
EFI_IFR_QUESTION_HEADER Question
EFI_QUESTION_ID QuestionId
EFI_GUID FormSetId
} EFI_IFR_REF3
この手法はBIOSブート時間を短くするための業界的な一般手法ですが、結果として「Network Boot Interface」がプログラムによるスキャンから見えなくなっていました。構造体がまだ“ロードされていない”ため、我々の自動化は優先順位を検出できませんでした。
これに対して我々はベンダーと連携し、固定の"Boot Order Module"内の特定のトークンを有効化してもらいました。これにより、GUI操作を不要にしてブートシーケンス中にNetwork Boot Interfaceが発見されるようになりました。
さらに、我々の機器向けUEFIには Force Priority Httpv4 Httpv6 Pxev4 Pxev6 という不変設定があり、ブート順の変更を阻害していました。これを解決するためにベンダーから新しいBIOSバージョンを提供してもらい、設定時にデバッグセッションを実施しました。
NICベンダーごとの文字列差異
NICベンダーによってUEFIに表示される文字列が異なり、iPXE経由でブート順を設定する際に不一致が発生しました。例:
- UEFI: HTTPS IPv4 Ethernet Network Adapter XXX-XXX-Y for OCP 3.0 P1
- UEFI: HTTPS IPv4 Network Adapter - 50:00:E6:8F:4F:32 P1
回避策として、CfHIIConfig_Appツールに部分一致で設定できる機能を実装しました。例えば:
.*HTTP.*IPv4.*P1
このパターンで許容される設定文字列にマッチさせ、正しいブート順を選択できるようにしました。現在はUEFIベンダーと協力して、ネットワークインターフェース文字列をプロトコル、転送タイプ、ポート番号、物理スロットインデックスといった関連情報のみに標準化し、MACアドレスなどのプロダクト詳細は除外する方向で調整中です。必要であれば製品詳細はNICの埋め込みVPD(vital product detail)から読み取れるようにします。これにより設定のドリフトやワイルドカードの使用を排除できます。
iPXE経由での設定確認不可への対処
iPXEはこの変数をHEXとして読み取るため、文字列出力をそのまま16進で読んでいました。ネットワークブート設定が変更されたかを確認し、ブート時間を短縮するために(設定前に変数を出力して比較する必要がないように)論理フラグ uefi-same-hex を実装しました。これにより、まず show で比較してから set するのではなく、単一の set コマンドを実行するかどうかを決めることができるようになりました。
以下は実際に使っているコマンド例です:
set buffer-var-guid 91468514-75bc-4bb5-8f33-91efff9e9b1f
set var-upd-path efivar/CfHIIVarUpd-${buffer-var-guid}
imgexec <signed CF UEFI configuration App> set ${uefi-setting}=${uefi-value}
iseq ${uefi-same-hex} ${${var-upd-path}} || set has-changed ${uefi-diff-hex}
結果: より動的なシステム
ネットワークブートシーケンスから推測を排除することで、我々は4時間に及ぶ苦闘を再び3分のプロセスに戻しました。これにより、変更は動的になり、手動でBIOSを操作する必要はなくなりました。単一のBIOSファームウェアイメージがすべてのSKUに対応し、設定更新は既存のリリースパイプラインで大規模にデプロイされ、ワークフロー全体がiPXE上で動作します。
| Metric | Before ordering change | After ordering change |
|---|
| Firmware Upgrade Automation | Nearly 4 hours | 3 minutes |
| Subsequent Single Boot | About 20 minutes | Less than a minute |
これらはUEFIの深掘り、OEMベンダーとの緊密な連携(プログラム的なブート順制御を解放するため)、およびiPXEのようなオープンソースツールを活用してスケーラブルな自動化を構築した結果です。CloudflareのOpenBMCチームは日々、コアフリートのブートプロセスについて学び、実験し、最適化を続けています。
ベアメタルインフラを管理していてサーバの起動が遅く悩んでいる方には、本ポストがネットワークブートシーケンスにおける不必要な遅延を特定・排除するための実践的なフレームワークを提供できれば幸いです。
iPXEやネットワークブート自動化に興味がある方は、check it out here !
タグ: server-island-start Infrastructure Engineering Networking Core