Enjoy Architecting

Twitter: @taisho6339

マルチクラスタKubernetes 3つのパターンと実運用事例

この記事はKubernetes Advent Calendarの7日目の記事です。 今回は、Kubernetesのマルチクラスタ化についての考察記事を書きます。

マルチクラスタの定義

マルチクラスタと一重にいっても色々とありますが、本記事では、「複数のKubernetesクラスタを並列に並べ、トラフィックを特定の条件でそれぞれにルーティングする」構成のことを指すとします。

また常時マルチクラスタではなく、普段はシングルでも、いつでもクラスタを並列に並べることができる構成もマルチクラスタ構成とします。

f:id:taisho6339:20201206170325p:plain

マルチクラスタが必要になるケース

運用する側としては、クラスタの数は少なければ少ないほど嬉しいはずです。

では、どのようなケースでマルチクラスタ構成を取る必要が出てくるのでしょうか?

Multi-cluster use casesにも記載されていますが、コアなものに絞って要約すると、下記のようになると解釈しています。

  • 可用性の向上

  • 地理分散への考慮

    • リクエスト元のロケーションを考慮したルーティング
    • Locationごとの固有サービスのデプロイ
  • セキュリティポリシーへの対応

    • 特別セキュリティが厳しいワークロードとそうでないものを区別して、別々のクラスタで運用
  • パフォーマンス改善

    • master nodeを分離することでクラスタ機能そのものの負荷を分散

私の現場のケースで採用に至った理由

私のケースでは「可用性の向上」が主たる理由になります。

  • Surge Upgrade + Graceful Shutdownを有効にしているものの、Master Upgradeしただけでも一瞬ダウンタイムが挟まってしまっている(原因究明中)

  • アップグレード起因で何か問題があったとしてもFail Over、ないしロールバックはできるようにしておきたい

  • BCP観点でリージョン障害に耐えうる構成を取る必要性

  • マイクロサービスで、各サービスチームがAWSGCPを選択可能な世界観にしておきたかった

これらがマルチクラスタで実現したかった要件になります。

マルチクラスタの実現方法

では、この要件を満たすためにどうすればマルチクラスタ化を実現できるでしょうか?

主に一般的なのはこの3つではないでしょうか。

  1. DNSパターン
  2. HA Proxyパターン
  3. Global Load Balancerパターン

1. DNSパターン

f:id:taisho6339:20201206170311p:plain

これは一番シンプルで運用が楽なパターンではないでしょうか? これはクラスタを指すドメインに対して、複数のクラスタのIPを登録しておく構成になります。 クラスタのIPはNodePortもしくは、L4ないし、L7のLBを払い出すことになります。

  • メリット

    • シンプルで管理運用コストが低い
    • Route53などを使えばGeographic Routingも可能
  • デメリット

    • DNSにはTTLがあるので即時FailOverができない
    • 常にTTLを意識して慎重にオペレーションする必要がある

私のケースでは特にこのTTLの部分で、即時FailOverできない点、ロールバックなどが気軽に行えい点を踏まえてこのパターンは見送りました。

2. HA Proxy パターン

f:id:taisho6339:20201206170342p:plain

このパターンは、前段にHAProxyのクラスタを設置し、そのバックエンドとしてKubernetesクラスタを置くパターンです。 HA Proxy自体を冗長化しておくために、何台かを並列で並べて管理する必要があります。

HAProxy 入門

可用性の文脈ではなく、各コンポーネントごとに配置するクラスタを分散して、そのためのトラフィック制御を行う文脈ですが、コロプラさんがこの構成をとっています。

コロプラさんの事例

  • メリット

    • かなり細かいルーティング制御が可能
    • クラスタごとのカナリアリリースやFail Overなども簡単に実現することができる
  • デメリット

    • Managedなものを使わない限り、HA ProxyがSPOFにならないよう管理運用コストがかかる

このパターンもメリットは大きいものの、HA Proxy自体の可用性、耐障害性への管理運用コストを鑑みて見送りました。

3. Global Load Balancerパターン

f:id:taisho6339:20201206170359p:plain

これは、クラスタの前段にグローバルなLBを配置し、その下にクラスタを置くパターンです。 私のケースでは、前述2パターンのデメリットが許容できず、消去法でこのパターンになっています。

LBそのものの機能性に左右されそうですが、 このパターン自体のメリデメは下記のようになっています。

  • メリット

    • LBからのヘルスチェック機構により、即時でFail Overできる
    • TTLなどに支配されない
    • 管理運用コストが比較的低め
  • デメリット

    • HAProxyのような細かいトラフィックルーティングができない ※1
      • 各ゾーンごとに均等に分散されるだけ

※1 AWSでEKSを使えばできる模様

ALB Weighted Target Groups による EKS Cluster の Canary Switching

Global Load Balancerパターンでの実運用

前述した通り、最終的にはLoadBalancerパターンを用いて対応しました。 このパターンを実現するために、GCPIngress For Anthosの機能を使って実現しており、構成の詳細について、Kubernetes MeetUp Tokyoにて私がLTした資料に記載してあります。

Ingress For Anthosを活用した安全なk8sクラスタ運用

Ingress For Anthosを使うことで、LBの設定は完全に自動化されています。 これにより、

といったことが担保できています。

この構成での惜しいところ

消去法で選んでいるので、当然完璧ではありません。 少なからず辛いところは存在しています。 例えば下記のようなポイントです。

  • Config ClusterというLBの設定同期用のクラスタを用意し、そこにLBの設定をデプロイしなくてはならない

  • 細かいトラフィックルーティングができないので、カナリアリリースのようなことはできない

  • マルチクラウドが実現できることにはできるが、EKSをそのまま突っ込んだりできるわけではなく、それなりに複雑な構成を取る必要がある

実際のクラスタアップグレードについて

実際のアップグレードとしては、

  1. 対象クラスタをサービスアウト
  2. 対象クラスタをアップグレード
  3. 対象クラスタをサービスイン

といったようにローリングアップデートの形をとっています。

ただ、カナリアリリースのようなことはできないので、 いきなりクラスタをサービスアウトし、アップグレードするようなことをやると、一気にトラフィックが片側に流れることになってしまいます。

現在は、ある程度minimumのPod数をある程度積んでおくことで対処していますが、これはリソース効率が悪く、本意ではありません。

よって将来的には、

  • ALB + EKSの構成に寄せる
  • GCPがGCLBにトラフィック制御の機能を出してくれるまで待つ
  • 別のパターンの構成に変える(HA Proxy)

といった対応をする必要が出てくる可能性があります。

(現在はコスト面でもトラフィック面でもゆとりがあるので予定はありません)

マルチクラスタとGitOps

これは余談ですがマルチクラスタ化するにあたり、GitOpsの考え方を取り入れて、ArgoCDによってデプロイパイプラインを組んでいたことにより、ここに関してはほぼノーコストで移行できました。 また、移行後も特に問題なく稼働できています。

ただ、現状各クラスタごとにArgoCDを独立してデプロイしており、各クラスタの状態を見るためには各クラスタ用のダッシュボードをみる必要があります。

一応ArgoCD側でもMultiClusterのための提案がなされていて、一つのApplicationに対して複数クラスタへのデプロイができるような、ApplicationSetというCRDおよびOperatorの開発が進んでいるようです。

まとめ

本記事ではマルチクラスタ化する理由、実運用してみた所感について紹介してきました。 Kubernetesを安全に運用するためのエコシステムはどんどん様々なソリューションが生まれてきており、今後も益々発展していくと思いますが、本記事が何かのお役に立てれば幸いです。