2022年11月21日(月)~22日(火)に「CloudNative Days Tokyo 2022」がハイブリッド開催されました。GMOインターネットグループはダイヤモンドスポンサーとして協賛・登壇しました!今回は、CFPセッション「k8s Operatorで運用負担減&ハイブリッドクラウドのコスト最適化をした話」の書き起こし記事となります。ぜひご覧ください。イベント告知:https://developers.gmo.jp/25932/
登壇者(敬称略)
GMOペパボ株式会社 技術部プラットフォームグループ シニアエンジニア/SRE菅原 千晶(@ch11aki)
「k8s Operatorで運用負担減&ハイブリッドクラウドのコスト最適化をした話」
https://speakerdeck.com/ch1aki/k8s-operatordeyun-yong-fu-dan-jian-and-haiburitudokuraudonokosutozui-shi-hua-wositahua
「k8s Operatorで運用負荷軽減とハイブリッドクラウドのコスト最適化をした話」と題しまして、GMOペパボ株式会社 菅原 千晶が発表します。
改めまして、GMOペパボの菅原 千晶と申します。弊社ではあだ名文化があり、社内では「akichan」と呼ばれています。私が所属する技術部プラットフォームグループは、特定のサービスの事業部には所属しない、サービス横断のSRE組織です。サービス運用の効率化、サービスレベル目標設定や、それを達成できるようにするための支援などを行っています。私の簡単な経歴としましては、2018年3月に未経験者向け研修付き採用制度の「ペパボカレッジ」枠で入社しました。昨年までは主にネットショップ作成サービスのカラーミーショップの運営に携わり、k8sの導入支援やGitOpsの推進などを行ってきました。現在はハンドメイドマーケットサービスのminneに注力し、サービスの信頼性とエンジニアの生産性を向上させるあらゆることに取り組んでいます。最近ではArgo Rollouts導入によるプログレッシブデリバリーの実現や、CDNコストの削減、RailsアプリのN+1問題の解消などを行いました。
本日お話しするのは、タイトルにある通り私が担当するminneの運用において、k8s Operatorを開発して運用課題を解消した話です。まず、minneのインフラ構成とそこにあった運用課題について説明します。そして、そこで得られたk8s Operatorで運用課題を解決することのメリットについて説明します。Operatorの詳細な実装方法などについては時間の都合上触れられませんので、発表を聞いてOperatorの開発をやってみたいと思った方は、ご紹介する書籍やWebページ等をご覧ください。
Section1│minneのインフラ構成
それでは、まずminneのインフラ構成から説明いたします。私が担当するminneは、ハンドメイド作品をインターネット上で販売・購入できる国内最大級のハンドメイドマーケットです。数値でみると、作家・ブランド数は80万件以上、作品数は1,500万点以上、モバイルアプリのダウンロード数は1,300万件以上の大規模なサービスとなっています。
そんなminneのインフラは、AWSとプライベートクラウドのハイブリッドクラウドで構成されています。ペパボではNyahと呼ばれるOpenStackベースのプライベートクラウドを持っています。AWSではEKS、Nyahではself-hostedのk8sクラスタを運用しており、ほとんどのアプリケーションはその上で動作しています。それぞれのk8sクラスタで動作しているアプリケーションは同一のものです。NyahはAWS Direct ConnectでAWSへ専用線接続されているため、相互の環境は透過的にアクセス可能になっています。例えばステートフルなDBやCache等はAWSのマネージドサービスを利用していますが、プライベートクラウド環境からもアクセス可能になっています。また、AWSだけでサービス持続可能なように設計されています。
プライベートクラウドNyahについてもう少しご説明します。Nyahの最大の長所は安価であるということです。同程度のスペックのEC2 instanceを利用するのと比較して、利用コストが数分の一で済みます。しかし一方で短所もあり、パブリッククラウドに比べるとスケーラビリティに制約があります。ある程度の余剰はありますが、爆発的なリソース需要の急増には対応することが難しいです。
minneでパブリックとプライベートのクラウドでハイブリッドクラウドの構成を選択している理由としてはいくつかあります。1つはプライベートクラウド自体の障害の対策です。社内で運用しているサービスのため、時には障害が発生し利用できなくなる可能性もあります。その際のリスクを考慮しています。minneではプライベートクラウド側だけにしかないリソースは基本存在せず、万が一の時には前述の通りAWS側だけでサービス継続が可能になっています。
2つ目の理由としては、安価なプライベートクラウドのコンピューティングリソースを最大限に活かしつつ、部分的にマネージドサービスを利用することで運用負荷を軽減できるからです。運用負荷の高いDBやCacheなどはRDSやElastiCacheなどのAWSのマネージドサービスを利用して、ステートレスなリソースに関してはプライベートクラウドを活用しています。
3つ目の理由としては、先ほど述べたプライベートクラウドの短所であるスケーリングの制約をカバーするためです。プライベートクラウド内のスケーリングで間に合わない場合は、Route53の加重レコードでAWS環境へ向くトラフィックの割合を調整し、プライベートクラウドで受けるリクエスト数を抑えます。
Section2│運用上の課題
続いてminneにあった運用上の課題について説明します。先ほど述べたプライベートクラウド内のリソースで間に合わない時にAWSへリクエストをオフロードする運用は、実は都度人力で行っていました。具体的には、割引クーポンやテレビ放映などのリクエストが急増するようなイベントがある度に、次のような作業を行っていました。まず、過去の実績の中から似たような事例を探し、ピーク時のリクエスト数を予測します。次に、過去のキャンペーンやテレビ放映時のレスポンスタイムや負荷状況と照らし合わせて、プライベートクラウド内のリソースだけで間に合うかどうかを試算し、リクエストをオフロードするかを判断します。そして、ピーク時にプライベートクラウド環境のキャパシティオーバーとならないよう、AWS側へオフロードする最適な加重を計算して事前に設定しておきます。ピークが過ぎリクエストが落ち着いたら加重設定を通常の割合に戻します。右のグラフはこの操作を行った際のそれぞれのクラウド環境で処理するリクエスト数の変化のイメージです。プライベートクラウドNyahで2,000リクエストまで許容できるとした時、最大3,000リクエストが予測された場合には、Nyah側へのリクエスト数が2,000リクエスト以下に収まるよう、AWS側で4割のリクエストを処理するよう加重を調整しています。ピークが過ぎた後加重設定を戻しています。
この運用の問題点としては、専門性が高く限られたメンバーしか実施が難しいため、運用作業がスケールしないことが挙げられます。また、実際より需要を多く見積もってしまった場合や、翌日や休み明けに加重設定を戻すまでのアイドルタイムの間、無駄にパブリッククラウドのリソースを利用している状態になっており、クラウドのコスト的に最適な状態であるといえません。さらには、誤って需要を少なく見積もってしまった場合、リソースが足りずレスポンスの遅延などが発生し、サービス障害となってしまう可能性があります。
この運用課題を解決するため、理想状態として自動でリクエスト数に応じた最適な加重が設定されることを目指し取り組みました。実は弊社サービスのSUZURIもminne同様ハイブリッドクラウドで動作して同様の課題を抱えており、LambdaやCloudWatch等のAWSのサービスを活用した先行事例がありました。これと同じ仕組みをminneでも構築することが考えられましたが、minneやSUZURI以外のハイブリッドクラウド構成をとる社内の他のサービスで個別にこれらの仕組みを構築運用していくのは非効率になると考え、全社統一での汎用的な仕組みで解決する道を探りました。
Section3│k8s Operatorによる自動リクエストオフロードの実現
そんな時に思いついたのが、k8s Operatorでこの課題を解決する方法でした。k8s Operatorとは、カスタムリソースを用いてk8sを拡張するコンセプトのことです。例えばDeployment Resourceに対するDeployment ControllerがReplicaSetを管理するように、独自に定義したカスタムリソースに対してCustom Controllerとして任意の動作を行います。有名なOperatorの例としてはカスタムリソースでPrometheusを管理するPrometheus Operatorや、AWSの各種リソースをカスタムリソースで管理できる AWS Controllers for Kubernetesなどがあります。またOperatorはk8sのコア・コンセプトのReconciliation Loopの仕組みに準拠して動作しています。
Reconciliation Loopとは、システムの現在の状態を観察比較して、現在の状態が理想の状態に一致するように変更するということを繰り返し行うループ処理のことです。ReplicaSet Controllerを例にとると、Replica数が3に設定されている時、管理するPodが何かしらの理由によって1つ減ったとしても、Replica数=3を維持するために新しく1つPodを追加するといったような具合です。k8sの様々なControllerはこのReconciliation Loopをもとに設計され動作しており、k8sの特徴である宣言的な設定はこの考えのもとに実現されています。
今回、リクエストオフロードの運用課題解決をOperatorで実装した理由の1つは、プライベートクラウドのキャパシティ不足に陥らないようにプライベートクラウドのリクエスト数を一定以下に抑えるために行うリクエスト数の確認、最適な加重の計算、加重設定の更新の操作の自動化を考えた際、まさに定義された理想状態に収束させるReconciliation Loopのパターンにマッチしそうと考えたからです。また、先ほど紹介した先行事例のSUZURIの件では、AWSのサービスをフル活用していましたが、Operatorとして実装できれば動作プラットフォームがk8sとなるため、クラウドベンダーなどの依存を減らすことができ、その他サービス事業部での活用の幅が広がりそうとも考えました。
Operatorの開発にはkubebuilderというフレームワークが提供されており、実装の型がある程度決まっています。kubebuilderによるOperatorの実装はカスタムリソースの設計とReconcile処理実装に大きく分かれています。カスタムリソースの設計について私はまず前述のプライベートクラウドのキャパシティ不足に陥らないように、プライベートクラウドのリクエスト数を一定以下に抑えるリクエスト数の確認、最適な加重の計算、加重設定の更新の操作を細かく分解しReconcile処理に必要な要素の整理をしてカスタムリソースの型を決定しました。例えば、リクエスト数を知るため、Prometheusからメトリクスを取得する必要があるので、 Prometheusの接続先と認証情報とクエリのフィールドが必要といったような具合です。次に、定義したカスタムリソースの状態を維持するようなReconcile処理を実装していきました。この実装に関しては、既存の多種多様なカスタムコントローラーを参考にしました。例えばPrometheusからメトリクスを取得するような処理はプログレッシブデリバリーコントローラーのArgo Rolloutsに似たような実装があるため参考にしました。
そして完成したのが、Rebalancerと名付けたOperatorです。これは、指定したポリシーに基づいて外部のメトリクスを参照してターゲットの加重を自動で調整します。現在はターゲットとしてRoute53、メトリクスとしてPrometheus、ポリシーはメトリクスが指定した値を維持するように最適値を算出するターゲット追従ポリシーのみに対応しています。弊社内の他のサービス事業部での活用を広げられるよう、ターゲットとしてPowerDNSやAWS ALBの加重ターゲットグループ、メトリクスとしてCloudWatch、Mackerel等への対応を考えています。
こちらが、Rebalanceカスタムリソースのサンプルです。プライベートクラウドでのリクエスト数が一定以下になるよう、AWS環境へ向く加重レコードのweight数を調整する場合の設定です。
簡単に説明するとmetricsフィールドに定義したPrometheusに定期的にクエリを発行して、現在のプライベートクラウド側のリクエスト数を取得しています。policyフィールドで選択した戦略がメトリクスとプライベートクラウド側のレコードのweight数をもとに最適な加重設定を計算します。得られた最適な加重設定を、targetに指定したレコードに設定します。例えばプライベートクラウド側の加重設定が10で、リクエスト数を1,000以下に抑えたい設定の場合、2,000リクエストが来ていたら10:10、3,000リクエストが来ていたら10:20といったように最適なweightを調整します。
このOperatorを作成したことで、月に複数回あった人力でのリクエストオフロード運用が0件になりました。基本的には、Operatorによる自動調整に任せておけば適切にオフロードされています。また、オフロード設定が最適化され、必要ない時にはAWS側へのオフロードが自動で無効に再設定されるため、アイドルタイムに無駄に利用していたAWS側のリソースが約20%削減されました。さらに、汎用的な設計でOperatorとして実装したことで、全社統一の仕組みで自動オフロード機能を提供可能になりました。GMOペパボでは便利ツールが動作する社内共通のk8sクラスタがあり、そこでマネージドで提供することで、カスタムリソースを書けばすぐ利用できるようになります。また、セキュリティ的な要件で、外部からのAPIの操作が難しいような場合でも、サービス事業部管理のクラスタにOperatorをインストールすることでも利用できます。
今回、Operatorによる運用課題解決を実施した結果、複数のメリットがあることが分かりました。1つは、当初の目論見通りクラウドベンダー依存が少なく可搬性が高いことです。システムの設計をする際に、この仕組みによって設計の制約が生まれる可能性が低くなると考えます。また、カスタムリソースのバリデーションはkubebuilderを用いることで簡単に実装できたため、コアなロジックの実装に集中できました。バリデーションがあると利用者は安心して利用することができ、運用者目線からすると設定の説明等に関するコミュニケーションコストも減らせるといったメリットを、低コストで享受できました。さらに、自動化の設定はカスタムリソースとなりk8sのmanifestとして管理されるため、その管理やデプロイ方法は既存のk8sの管理と同じ方法をとることができるのもメリットでした。新たなツールを導入した時に考えないといけない設定の管理回りの考慮を減らすことができました。また、kubebuilderを用いることで実装の型がある程度決まるので、チームメンバーがコードの内容をキャッチアップしやすいといったメリットもありました。
Section4│まとめ
最後にまとめです。この発表では、まずminneにおいて繰り返し発生する運用作業の削減とプライベートクラウドのコストメリットを生かすため、自動でAWSにトラフィックをオフロードしたい課題があったことを説明しました。その実現のため、汎用的でベンダー依存が少なそうなk8s Operatorを作成する方法を選びました。これによって、月数回発生していた運用作業を0件にすることと、アイドルタイムに無駄に利用していたAWS側のリソースを20%削減する効果が得られました。また、これを通して分かった、k8s Operatorで運用作業の自動化を実現する様々なメリットがあったことをご紹介しました。今後、運用課題解決の方法の選択肢の1つとして、Operatorを開発する選択肢をぜひ加えてみてください。
発表は以上となります。ありがとうございました。
アーカイブ映像
映像はアーカイブ公開しておりますので、まだ見ていない方、もう一度見たい方は 是非この機会にご視聴ください!
https://youtu.be/U0_hbrJ44wk