原著者Daniel Bryant氏の許諾を得て翻訳・公開しています。
記事: Using API Gateways to Facilitate Your Transition from Monolith to Microservices
原文公開日: 2018年6月24日
コンサルタントの業務では、モノリシックなアプリケーションからマイクロサービスベースのアプリケーションへ移行している多くのエンジニアリングのチームにぶつかりました。"だから何だ?"と聞く人がいるかも知れません。当たり前のことかもしれません。この移行パターンがほぼきまり文句のようになっていることは理解していますが、移行の側面が忘れ去られてしまうこともしばしばあります。今日はこれらのトピックの1つである、エッジゲートウェイやAPIゲートウェイのロールについて話したいと思います。
マイクロサービスへの移行
通常、移行開始時には、ドメイン駆動設計に影響を受けた"境界づけられたコンテキスト"の定義によるドメインモデリング、継続的デリバリーパイプラインの作成、自動化されたインフラストラクチャのプロビジョニング、強化されたモニタリングやロギング、新技術の投入(Docker、 Kubernetes、おそらく
現在はサービスメッシュや2つのサービスメッシュ)など、明らかなトピックに多くの注意が払われます。しかしあまり目立たない部分は、無視していると痛い目にあうことがあります。システムの進化や既存のユーザトラフィックの移行をどのようにオーケストレーションするかがポイントとなるケースです。既存アプリケーションアーキテクチャをリファクタリングして、潜在的に新技術を導入したいと考えていますが、エンドユーザを混乱させたくありません。
以前、"Continuous Delivery: How Can an API Gateway Help (or Hinder)"の記事で書いたように、"dancing skelton"のようなパターンは、新しいアプリケーションやインフラストラクチャのエンドツーエンドの実行可能性を証明するのに大いに役立ちます。しかし、基礎となる顧客対応の大部分を占めているのは、システム内の単一ポイント、つまりingressやエッジゲートウェイを介して行わます。そのため、既存システムの実験や進化を可能にするためには、多くの時間と労力をここに当てる必要があります。
すべての(ユーザーの)ジャーニーはエッジから始まる
マイクロサービスベースのアプリケーションへ移行する際の効果的なエッジソリューションの必要性について話すのは、明らかに私がはじめての人ではありません。実際、Martin Fowler氏の元記事であるMicroservices Prerequisitesを拡張したCalcado’s Microservices Prerequisitesでは、Phil Calcado氏が提案している5番目の前提条件は"エッジへの簡単なアクセス"です。Phil氏は彼の経験に基づいて、多くの組織がモノリスと一緒に新しいマイクロサービスをデプロイしようとする最初の試みは、単にサービスを直接インターネットに公開することからなると語っています。これは1つの(簡単な)サービスなら上手くいきますが、スケールしないアプローチであり、データの認可や集計において、呼び出したクライアントに困難な作業を強いることもあります。
既存のモノリシックアプリケーションをゲートウェイとして使用することもでき、もし複雑で高結合の認可と認証のコードがある場合、セキュリティコンポーネントが新しいモジュールもしくはサービスにリファクタリングされるまでは、これが唯一の実行可能なソリューションとなります。このアプローチには、新しいルーティング情報をモノリスに"更新"しなければならないという要件(再デプロイを伴う可能性あり)や、すべてのトラフィックがモノリスを通らなければならない事実など、明らかな不利な点があります。後者の問題は、マイクロサービスを別のfabricや(Kubernetesのような)プラットフォームへデプロイする場合にとくにコストがかかる可能性があります。アプリケーションに送信されるどのリクエストも、新しいスタックへ入る前に古いスタックを経由する必要があるためです。
すでにエッジゲートウェイもしくはリバースプロキシ(たとえばNGINXやHAProxy)を使用しているかもしれませんが、これらはあらゆるバックエンドアーキテクチャで作業する際、多くのメリットを提供できます。一般的に提供される機能は、複数のバックエンドコンポーネントへの透過的なルーティングやヘッダーの書き換え、TLS terminationなどがあり、最終的にどのようなリクエストが提供されるにもかかわらず、横断的な懸念があります。このシナリオでの聞きたいことはマイクロサービスの実装のためにこのゲートウェイを使い続けいたいかどうかです。もしそうなら、同じように使うべきでしょうか?
VMsからコンテナへ(オーケストレーション経由)
この記事のイントロダクションでも書いたように、多くのエンジニアリングチームは、アプリケーションアーキテクチャの変更と同時に、新しいインフラストラクチャへ移行する決断を下しています。その際のメリットや課題はコンテキストに大きく依存しますが、多くのチームがVMやInfrastructure as a Service(IaaS)からコンテナやKubernetesへ移行しているのを目にしています。
新しいマイクロサービスをコンテナにパッケージ化し、これらをKubernetesにデプロイするとしたら、エッジ側でのトラフィック処理においてどのような課題に直面するのでしょうか?本質的には3つの選択肢があり、そのうちの1つはすでに読んだことがあるものです。
-
モノリシックもしくは新しいサービスへのどちらかにトラフィックをルーティングするエッジゲートウェイとして機能するために、既存のモノリシックアプリケーションを使用することです。どんな種類のルーティングロジックも実装できます(すべてのリクエストはモノリスを経由しているため)。そしてauthn/authzの呼び出しはプロセス処理中に行うことができます。
-
URIやヘッダーを基にしたトラフィックをモノリスもしくは新しいサービスのどちらかにルーティングするエッジゲートウェイを、既存のインフラストラクチャ内にデプロイ、運用することです。Auth、Authzは通常モノリスやリファクタリングされたセキュリティサービスへの呼び出しを介して行われます。
-
URIとヘッダーに基づいたトラフィックをモノリスもしくは新しいサービスのどちからにルーティングするエッジゲートウェイを、新しいKubernetesインフラストラクチャ内にデプロイ、運用することです。Auth、Authzは通常Kubernetes内で実行されているリファクタリングされたセキュリテイサービスへの呼び出しを介して行われます。
エッジゲートウェイをどこにデプロイして運用するかの選択にはトレードオフが含まれます。
いったんエッジゲートウェイの実装の仕方を決めてしまうと、次に決めなければいけないのはどのようにシステムを進化させるかです。大まかに言えば、モノリスを"strangle"するのか"monolith-in-a-box"を置いて、ここから削っていくかのどちらかです。
Strangling the Monolith
マーティン・ファウラーはStrangler Application Patternの原則についての素晴らしい記事を書いており、執筆から10年以上経っていますが、モノリスからより小さいサービスに機能を移行しようとするときにも同じガイドラインが適用されます。このパターンの核心は、モノリスから機能を抽出して、RPCやRESTのような"seams"を経由して、もしくはメッセージングやイベントを経由してモノリスと相互作用するサービスの形で提供することと説明しています。時間の経過とともに、モノリスに含まれる機能(関連づいたコード)が使われなくなり、新しいマイクロサービスが既存のコードベースを"strangling"することになります。このパターンの主な欠点は、モノリスが稼働している限り、マイクロサービスを新しいプラットフォームにデプロイする傍らで、既存のインフラストラクチャをメンテナンスする必要があることです。
マイクロサービスでこのパターンを使用することについて深く語った最初の会社の1つは、2013年に"I-Tier: Dismantling the Monolith"を発表したGrouponでした。彼らの仕事から学べる教訓は多くありますが、Grouponがもともと"Grout"でやっていたようなカスタムNGINXモジュールを2018年に書く必要はありません。今では、シンプルな宣言的設定を使った機能を提供するAmbassadorやTraeficのようなモダンなオープンソースのAPIゲートウェイがあります。
Monolith-in-a-Box:継続的デリバリーのシンプル化
マイクロサービスへの移行や、Kubernetes上へのデプロイでよく見かけるパターンを、"monolith-in-a-box"として呼んでいるものがあります。2015年のContainerSchedカンファレンスにて、MonoNOTHと呼ばれていたnotonthehighstreet.comのモノリシックなRuby on Railsアプリケーションをマイクロサービスベースのアーキテクチャへ移行した話を共有したときに、Nic Jackson氏と一緒にこのことについて語りました。
一言で言えば、この移行パターンはコンテナ内の既存のモノリシックなアプリケーションをパッケージングし、他の新しいサービスのように稼働させることで構成されています。
Kubernetesのような新しいデプロイメントのプラットフォームを実装する場合は、ここでもモノリスを実行します。このパターンの主なメリットは継続的デリバリーパイプラインの均質化です。コードを正しくコンパイルしパッケージ化するために各アプリやサービスはカスタマイズされたビルドステップ(もしくはコンテナビルド)を必要としています。しかしランタイムコンテナ作成後は、パイプラインのすべてのステップでコンテナの抽象化をデプロイメントの成果物として使用できます。
monolith-in-a-boxパターンの最終的な目標は、新しいインフラストラクチャにモノリスをデプロイし、徐々にすべてのトラフィックを新しいプラットフォームに移動させることです。これにより、モノリスの完全分解の完了前に、古いインフラストラクチャを廃止できます。
このパターンにしたがっているのであれば、最終的にすべてのトラフィックがルーティングされるので、Kubernetes内でエッジゲートウェイを実行することはさらに意味があると私は主張します。
Parting Thoughts
仮想マシン(VM)ベースのインフラストラクチャからKubernetesのようなクラウドネイティブプラットフォームへ移行するとき、移行を支援する効果的なエッジ/イングレスソリューションの実装に時間を投資する価値は十分にあります。これを実装するためには複数のオプションがあります。ゲートウェイとして既存のモノリシックアプリケーションを使用すること、既存のインフラストラクチャ内でエッジゲートウェイをデプロイもしくは使用して現在のサービスと新しいサービス間でトラフィックをルーティングすること、新しいKubernetesプラットフォーム内にエッジゲートウェイをデプロイすることです。
Kubernetes内にエッジゲートウェイをデプロイすることで、"monolith-in-a-box"のような移行パターンを実装する際に、より柔軟性をもたせることができ、完全なマイクロサービスベースのアプリケーションをより迅速に行うことができます。
この記事はgetambassador.ioブログに掲載されたものです。
Kiarash Irandoust氏に感謝します。
翻訳を終えて
マイクロサービスへの移行方法についてあまり知りませんでしたが、この記事にて2パターンの方法があり、それぞれのメリット/デメリットがあることを学べました。
個人の感想として、段階的に移行していく方法が少ないリスクでスムーズに移行しやすいように思えました。
誤訳等ありましたらご指摘をお願いします。