インフラ・DevOps
ダウンタイムゼロのKubernetesを実現するためのクラスター統合
Federating Clusters for Zero-Downtime Kubernetes (linkerd.io)
要約
この記事では、Linkerdのマルチクラスター拡張機能を使用して、Kubernetesクラスターを統合し、ダウンタイムゼロを実現する方法について解説します。特に、ゲートウェイ、フラット、フェデレーションという3つの異なるマルチクラスターモードを組み合わせ、複数のGKEクラスター間でサービスを単一のロードバランスされたエンドポイントとして提供するアーキテクチャが示されています。これにより、リージョン全体の障害が発生した場合でも、サービスの継続性を確保し、自動フェイルオーバーを実現します。
全文翻訳
ダウンタイムゼロのKubernetesを実現するためのクラスター統合
Dominik Táskai, Linkerd アンバサダー
2026年6月24日 • 15分読了
すべてのマルチリージョン設定は、いずれ同じ厄介な瞬間に遭遇します。クラスター全体がダウンし、2つのリージョン離れた場所で実行されているサービスとまったく同じコピーは、それらを1つのものとして扱うように何も配線されていないため、存在しないも同然です。フェイルオーバーはランブックになります。復元し、DNSを再設定し、書面上ではすでに生き残るために支払っていたはずの停止を待つことになります。
Linkerdのマルチクラスター拡張機能は、いくつかのクラスターがサービスを単一のロードバランスされたエンドポイントとして提示できるようにすることで、そのギャップを埋めます。公式タスクが軽く扱っている部分は、実際のプラットフォームがほとんど決して1つのマルチクラスターモードを選ばないということです。一部のサービスはフェデレーション(すべての場所で同じサービス、1つのエンドポイント、自動フェイルオーバー)を望んでいます。一方、他のサービスはミラーリング(特定のリモートサービスを名前で到達する)を望んでいます。そして、同じ一連のリンク上で両方のパターンが共存することを頻繁に望んでいます。ドキュメントでは、各モードを単独で説明しています。この投稿では、3つのGKEクラスターにわたって、フルメッシュリンクトポロジー、クラスター全体をダウンさせるカオステスト、そして新しいGCPプロジェクトでクローンして実行できるスクリプトを使って、これら3つすべてを連携させます。
補完リポジトリ: ここで参照されているすべてのスクリプトは、このリポジトリにあります。自由にクローンし、プロジェクトIDを設定して実行してください。
Linkerdマルチクラスターモード: ゲートウェイ、フラット、フェデレーション
Linkerdのマルチクラスター拡張機能は3つのモードをサポートしています。良い点は、それらが相互に排他的ではないことです。同じ一連のリンクされたクラスター上で、モードはサービスごとにラベルを介して選択されます。
Mode Label What happens Network Requirement
階層型 (ゲートウェイ) mirror.linkerd.io/exported=true サービスは<svc>-<cluster>としてミラーリングされ、トラフィックはゲートウェイを介してルーティングされます ゲートウェイIPが到達可能であること
フラット (pod-to-pod) mirror.linkerd.io/exported=remote-discovery サービスは<svc>-<cluster>としてミラーリングされ、トラフィックはリモートPodに直接送られます フラットネットワーク (Pod IPがルーティング可能であること)
フェデレーション mirror.linkerd.io/federated=member 同じ名前のサービスはすべて<svc>-federatedに統合され、すべてのクラスターにわたってロードバランスされます フラットネットワーク (Pod IPがルーティング可能であること)
運用上重要な違いは、階層型ミラーリングはどのネットワークでも機能するということです。ゲートウェイIPのみが到達可能である必要がありますが、フラットモードとフェデレーションモードは実際のPod間接続を必要とします。GCPでは、ピアリングされたVPC上のVPCネイティブGKEクラスターが、そのフラットネットワークを無料で提供します。そのため、フラットネットワーク上でコアワークロード用にフェデレーションサービスを実行し、そのネットワーク上にないクラスターからゲートウェイを介して特殊なサービスをミラーリングすることもできます。私が見てきたほとんどのプラットフォームチームは、まさにこのような組み合わせで終わっています。
マルチリージョンアーキテクチャ: GKEクラスター設定
3つのリージョンにまたがる3つのGKEクラスターがあり、それぞれが完全に相互にリンクされています(合計6つの方向性リンク)。3つのデモサービスがあり、それぞれ異なるマルチクラスターモードを使用しています。
frontendはフェデレーションされ、3つのクラスターすべてで実行されます。各クラスターの単一のフェデレーションされたfrontendサービスは、9つのPodすべて(3レプリカ × 3クラスター)にわたってロードバランスされます。クラスターがダウンしても、残りの6つのPodがアプリケーションの変更なしにトラフィックを吸収します。
apiはフラットミラーリングされ、westとeastで実行されます。northクラスターはそれをapi-westとapi-eastとして消費します。これらは明示的なリモートサービス名であり、トラフィックはリモートPodに直接送信されます。これは、クライアントがどのバックエンドと通信するかを決定する必要がある場合、たとえば、データのローカリティのためにリクエストをリージョン内に保持する場合に採用されます。
analyticsはゲートウェイミラーリングされ、eastでのみ実行されます。Linkerdゲートウェイを介してエクスポートされるため、westとnorthはeastのPodへのフラットネットワーク接続を必要とせずにanalytics-east-gwとしてアクセスできます。これは主に、ゲートウェイモードが同じリンク上でフラットモードおよびフェデレーションモードと共存することを示すためにここにあります。
デプロイの前提条件: GKE、Linkerd、およびCLIツール
GCPアカウント(無料枠のクレジットでカバーされます。小さなノードプールを持つ標準クラスターを3つ使用します)
gcloud CLI、認証済み (gcloud auth login)
kubectl v1.28+
step CLI, brew install step (証明書生成用)
helm v3
フルセットアップには約30分
infraスクリプトは、コンピューティングAPIとコンテナAPIを自動的に有効にするため、新しいプロジェクトでもすぐに使えます。
ステップ0: 設定
リポジトリをクローンし、例のファイルからローカルの.envファイルを作成し、GCPプロジェクトに合わせてカスタマイズします。残りのデモではデフォルトで十分なので、ほとんどの場合、プロジェクトIDを変更するだけで済みます。
```bash
git clone <your-repo-url>
cd blog-linkerd-federation
cp env.example .env
```
.envを開き、少なくともプロジェクトIDを設定します。ファイルには他のすべての項目について適切なデフォルト値が含まれています。
```bash
export GCP_PROJECT="your-project-id"
export REGION_WEST="us-central1"
export REGION_EAST="us-east1"
export REGION_NORTH="europe-west1"
# リージョンごとに1つのゾーン。ノードロケーションを単一ゾーンに固定するため、num-nodesは
# ノードの総数です。これが重要な理由については、下記のコストに関する注意を参照してください。
export ZONE_WEST="us-central1-a"
export ZONE_EAST="us-east1-b"
export ZONE_NORTH="europe-west1-b"
export CLUSTER_MACHINE_TYPE="e2-medium"
export CLUSTER_NODE_COUNT="1"
export FRONTEND_REPLICAS="3"
```
少なくともGCP_PROJECTを設定してください。他のすべては適切なデフォルト値が設定されています。3つのリージョン、リージョンごとに1つのゾーン、コストを抑えるための小さなノードプールです。`cat .env`を実行すると、すべての変数が表示されるはずです。
スクリプトが読み取れるように、変数を現在のシェルにロードします。
```bash
source .env
```
以下のすべてのスクリプトはこのファイルから読み取り、すべて`set -euo pipefail`で実行されるため、変数が欠落していると黙って失敗するのではなく、大きくエラーを吐き出します。そのため、`env.example`にはプロジェクトIDだけでなく、VPC名やクラスター名を含むすべての変数が含まれています。
ステップ1: VPCピアリングを使用して3つのGKEクラスターをプロビジョニングする
インフラストラクチャスクリプトを実行して、ネットワークとクラスターを作成します。これには約10〜15分かかるので、コーヒーを飲むのに良い機会です。
```bash
../scripts/01-infra.sh
```
このスクリプトは次のことを行います。
コンピューティングAPIとコンテナAPIを有効にします(すでにオンになっている場合は何もしません)。
VPCピアリングの厳密な要件である、オーバーラップしないPodおよびサービスCIDRを持つ3つのVPCを作成します。
`--export-custom-routes`と`--import-custom-routes`を使用して、フルメッシュVPCピアリング(west↔east、east↔north、north↔west)を設定し、Pod CIDRが実際にアドバタイズされるようにします。これがフラットネットワークを提供するものです。
各VPC/リージョンに1つずつ、それぞれ単一ゾーンに固定された3つのGKE Standardクラスターを作成します。
kubectlコンテキストをwest、east、northに名前変更します。
スクリプトが使用するアドレスプランは次のとおりです。PodトラフィックをVPCピアリングが正しくルーティングできるように、範囲は意図的にオーバーラップしないようにしています。
Cluster VPC Subnet Pod CIDR Service CIDR
west 10.10.0.0/20 10.100.0.0/14 10.104.0.0/20
east 10.20.0.0/20 10.108.0.0/14 10.112.0.0/20
north 10.30.0.0/20 10.116.0.0/14 10.120.0.0/20
オーバーラップしない範囲は譲歩できません。Pod CIDRがピアリングされたVPC間でオーバーラップすると、ルーティングが静かに中断します。Podは間違ったクラスターから応答を受け取ったり、接続がタイムアウトしたりしても、ログには何も有用な情報が出力されません。私にどうやって知っているか尋ねないでください。
3つのゾーンではなく、1つのゾーン。GKEリージョンクラスターは、デフォルトで3つのゾーンのそれぞれに`--num-nodes`で指定されたノードを配置します。`--num-nodes 1`の場合、クラスターごとに3つのノード、合計9つのノードとなり、費用が3倍になります。このスクリプトは`--node-locations`を単一ゾーンに固定するため、`CLUSTER_NODE_COUNT=1`は本当にクラスターごとに1つのノードを意味します。
コストに関する注意: このデモでは、それぞれe2-mediumノードを1つ持つ3つの標準クラスターは、合計で約10〜15ドル/日かかります(管理費 + ノード + eastの小さなゲートウェイロードバランサー)。ティアダウンスクリプトはすべてを削除します。
ステップ2: 共有トラストアンカーでLinkerdをインストールする
共有トラストアンカーを使用して、3つのクラスターすべてにLinkerdをインストールします。スクリプトは証明書を生成し、コントロールプレーンをインストールし、各クラスターがクロス・クラスターmTLSのために他のクラスターを信頼するように設定します。
```bash
../scripts/02-linkerd-install.sh
```
これにより、ルートCAとクラスターごとの発行者証明書が生成され、Linkerdが3つのクラスターすべてにインストールされます。
```
root.crt (共有トラストアンカー)
├── issuer-west.crt + issuer-west.key
├── issuer-east.crt + issuer-east.key
└── issuer-north.crt + issuer-north.key
```
クラスターごとの発行者証明書は、運用上の習慣として保持する価値があります。1つのクラスターの発行者が侵害された場合、分離してローテーションでき、