学習プログラム: モノリスを GKE アプリに変換する - モノリスをモジュール化する


これは、モノリシック アプリをモジュール化してコンテナ化する方法を学習する学習プログラムの 2 番目のチュートリアルです。

この学習プログラムは、次のチュートリアルで構成されています。

  1. 概要
  2. モノリスを理解する
  3. モノリスをモジュール化する(このチュートリアル)
  4. モジュラー型のアプリをコンテナ化できるように準備する
  5. モジュラー型のアプリをコンテナ化する
  6. アプリを GKE クラスタにデプロイする

前のチュートリアル モノリスを理解するでは、Cymbal Books というモノリシック アプリについて学習しました。モノリスをローカルマシンで実行し、モノリスのさまざまな部分がエンドポイントを介して相互に通信していることを確認しました。

このチュートリアルでは、モノリスをモジュールに分割してコンテナ化の準備をする方法について説明します。コードはすでに更新されているため、モジュール化の手順を自分で実行する必要はありません。このチュートリアルに沿って、リポジトリ内のアプリのモジュール バージョンを調べ、元のモノリスとの違いを確認します。

料金

このチュートリアルでは費用は発生しません。ただし、このシリーズの最後のチュートリアルの手順に沿って操作すると、Google Cloud アカウントに料金が発生します。費用が発生するのは、GKE を有効にして Cymbal Books アプリを GKE クラスタにデプロイしたときです。これらの費用には、料金ページで説明されている GKE のクラスタごとの料金と、Compute Engine VM の実行料金が含まれます。

不要な料金が発生しないように、このチュートリアルの完了後に GKE を無効にするか、プロジェクトを削除してください。

始める前に

このチュートリアルを始める前に、最初のチュートリアルである モノリスを理解するを完了していることを確認してください。このチュートリアルでは、Cymbal Books のモジュール バージョンをローカルマシンで実行します。これを行うには、事前に環境を設定しておく必要があります。最初のチュートリアルをすでに完了している場合は、GitHub リポジトリのクローンを作成しています。Cymbal Books アプリの 3 つのバージョンはすべて、次のフォルダ内のリポジトリにあります。

  • monolith/
  • modular/
  • containerized/

続行する前に、これらのフォルダがマシンにあることを確認してください。また、仮想環境 book-review-env がアクティブになっていることを確認します。アクティベート方法を忘れた場合は、最初のチュートリアルの 仮想環境を作成してアクティベートするをご覧ください。環境を有効にすると、アプリのモジュール バージョンが実行に必要なものをすべて備えていることが保証されます。

モジュール化とは

このチュートリアルでは、コンテナ化の準備としてモノリシック アプリをモジュール化する方法について説明します。モジュール化とは、モノリスをモジュール式アプリに変えるプロセスです。前のチュートリアルで説明したように、モノリスの特徴は、コンポーネントを個別に実行またはスケーリングできないことです。モジュール式アプリは異なります。機能が、独立して実行およびスケーリングできるモジュールに分割されています。

モジュール化とコンテナ化は同時に行われることが多いですが、このチュートリアル シリーズでは、各コンセプトを明確に理解できるように、別々の手順として扱います。このチュートリアルでは、モノリスをモジュール化する方法について説明します。後のチュートリアルでは、モジュール式アプリをコンテナ化する方法について説明します。

増分モジュール化

通常、本番環境では一度に 1 つのコンポーネントをモジュール化します。コンポーネントをモジュール化し、モジュールをモノリスに統合して、すべてが機能することを確認してから、次のコンポーネントに取り組みます。一部のコンポーネントがモジュール化され、他のコンポーネントがモノリスの一部として残っているこのハイブリッド状態は、マイクロリスと呼ばれます。ただし、このチュートリアルでは、アプリのすべてのコンポーネントを同時にモジュール化して、アプリをモジュール化する方法の完全な例を示します。

モノリスをモジュール化する方法

このセクションでは、Cymbal Books モノリスが個別のモジュールに分割された方法について説明します。手順は、モジュール化プロセスを理解し、独自のアプリに適用できるようにするために提供されています。ただし、このチュートリアルでは、クローン作成されたリポジトリにアプリのモジュール バージョンがすでに含まれているため、これらの手順を実行する必要はありません

  1. アプリの個別の機能を特定する
  2. モジュールを作成する
  3. モジュール間の通信を有効にする
  4. 各モジュールに必要なデータのみへのアクセス権を付与する

アプリの個別の機能を特定する

Cymbal Books モノリスをモジュール化する最初のステップは、その主な機能を特定することです。Cymbal Books サンプル アプリケーションでは、モノリスに次の 4 つの異なる関数があります。

  • ホームページの配信
  • 書籍の詳細の提供
  • 書籍のレビューの提供
  • 書籍の表紙画像の配信

モジュールを作成する

前のチュートリアルで説明したように、モノリスは、前のセクションで特定した 4 つの関数をルート ハンドラとして実装する単一の Flask アプリです。アプリをモジュール化するには、各ルート ハンドラを取得して、独自の Flask アプリに配置します。4 つのルート ハンドラを含む 1 つの Flask アプリではなく、それぞれに 1 つのルート ハンドラを含む 4 つの Flask アプリを作成します。

次の図は、単一の Flask アプリから 4 つの個別の Flask アプリへの変換を示しています。

モノリスからモジュラー アプリへの変換

モジュラー アプリでは、図に示すように、各 Flask アプリが独立して実行され、異なるポート(8080、8081、8082、8083)でリッスンします。この設定が必要なのは、このチュートリアルの後半でモジュール式アプリをテストする際に、すべてのモジュールを同じマシンで実行するためです。競合を避けるため、アプリごとに異なるポート番号が必要です。

ホームページ モジュールには、ホームページの提供と、ウェブページに表示する必要があるデータを収集するための他のモジュールとの通信という 2 つの役割があります。他の各モジュールは、レビュー、詳細、画像などの単一の機能に焦点を当てています。これらのモジュールは相互に通信せず、ホームページ モジュールからのリクエストにのみ応答します。

ホームページ モジュールには追加の調整ロールがありますが、他のモジュールに影響を与えることなく任意のモジュールを更新できるため、アプリは真にモジュール式です。1 つの大きな Flask アプリケーションが 4 つの部分に分割され、それぞれがアプリケーションの機能の特定の部分を処理します。

モジュール間の通信を有効にする

モジュールを作成したら、次のステップとして、モジュールが相互に通信できることを確認します。Cymbal Books アプリでは、この通信ロジックはすでに実装されています。ダウンロードしたコードの modular/ フォルダを見ると、アプリの主な機能(ホームページ、書籍の詳細、レビュー、画像の提供)がそれぞれ個別の Flask アプリとして実装されていることがわかります。これらのアプリはそれぞれ独自の HTTP エンドポイントを定義しており、モジュールはこれらのエンドポイントに HTTP リクエストを送信することで通信します。

Cymbal Books モノリスのモジュール化は簡単でした。モノリスには、ルートハンドラとして実装される明確に定義されたコンポーネントがあり、各ルートハンドラには明確に定義されたエンドポイントがあります。これらのルート ハンドラを個別の Flask アプリケーションに配置すると、エンドポイントを介して通信する機能が維持されます。ルート ハンドラを個別の Flask アプリに配置するだけで、モジュールが作成され、モジュール間の通信が可能になります。

モジュール間の通信の一般的なアプローチは、REST API を実装することです。これにより、モジュールが互いに HTTP リクエストを送信できるようになります。Cymbal Books では、各モジュールが Flask の組み込みツールを使用して REST エンドポイントを定義します。もう 1 つの一般的なアプローチは gRPC です。これにより、モジュールが互いの関数を直接呼び出すことができます。

Cymbal Books でコミュニケーションがスムーズな理由

モジュラーアプリの各モジュールは、ウェブサーバー内で実行される個別の Flask アプリケーションです。たとえば、ホームページ モジュールはホームページを提供し、書籍の詳細モジュールは書籍の詳細を提供します。ウェブサーバーは HTTP リクエストとレスポンスを処理するように設計されているため、モジュール間の通信は簡単です。各モジュールは、他のモジュールがデータをリクエストするために使用できるエンドポイントを公開します。

各モジュールに必要なデータのみへのアクセス権を付与する

モノリスを適切にモジュール化するには、各モジュールがアクセスできるデータを必要なデータのみに制限する必要があります。この原則はデータ分離と呼ばれ、真にモジュラー型のアーキテクチャを作成するうえで重要な要素です。

モジュール化でよくある間違いは、複数のモジュールが同じデータ(単一のデータベースなど)にアクセスできるようにすることです。このタイプの実装では、次のような問題が発生します。

  • 密結合: 共有データの構造が変更された場合(データベース テーブルの名前が変更されたり、列が追加されたりした場合など)、そのデータに依存するすべてのモジュールを更新する必要があります。適切なモジュール化により、この問題を回避できます。
  • フォールト トレランスの問題: 複数のモジュールが同じデータソースを使用している場合、1 つのモジュールで無効なクエリや過剰なトラフィックなどのランタイム エラーが発生すると、他のモジュールが中断される可能性があります。システムの一部で障害が発生すると、システムの他の部分で障害がカスケード発生する可能性があります。
  • パフォーマンスのボトルネック: 単一の共有データソースがボトルネックになる可能性があります。つまり、複数のモジュールがデータソースとやり取りしようとすると、アプリケーション全体の速度が低下する可能性があります。

このような問題を回避するため、各モジュールに独自のデータソースを用意する必要があります。

Cymbal Books がデータベースを使用してデータを保存していた場合、データ分離を適用し、各モジュールが必要なデータのみにアクセスできるようにするには、データベースを複製するかパーティショニングする必要があります。レプリケーションでは、各モジュールに対してデータベースの個別のコピーを維持しますが、パーティショニングでは、特定のテーブルまたは行へのアクセスが制限されます。どちらのアプローチでも、モジュールが互いのデータに干渉することを防ぐことができます。

次の図は、モノリシックな書籍アプリのアーキテクチャと、書籍アプリのモジュラー アーキテクチャを比較したものです。

アプリのモノリス バージョンとモジュラー バージョンがデータを処理する方法を示す図

モノリスの関数が単一の data/ ディレクトリにアクセスするため、モノリスの実装はデータ分離の原則に準拠していません。

一方、モジュール型アプリでは、データを個別のディレクトリに分割し、各モジュールが指定されたデータのみとやり取りするようにすることで、ある程度のデータ分離を実現しています。

  • 書籍の詳細モジュールは、details_data/ ディレクトリからのみデータを取得します。
  • 書籍のレビュー モジュールは、reviews_data/ ディレクトリからのみデータを取得します。
  • 画像モジュールは images/ ディレクトリからのみデータを取得します。

後のチュートリアルでは、アプリをコンテナ化することでデータ分離をさらに強化する方法について説明します。

先ほどご覧いただいた

ソフトウェア開発業界では、マイクロサービス分散システムという用語がよく使用されます。このセクションでは、これらの用語が Cymbal Books のモジュール式実装にどのように関連しているかについて説明します。

マイクロサービス

マイクロサービスは、特定のタスクを実行する自律的なモジュールです。これらのモジュールは、エンドポイントなどのインターフェースを介して他のモジュールと通信します。

Cymbal Books のモジュール バージョンの各モジュールはこの定義に適合するため、マイクロサービスと呼ぶことができます。後のチュートリアルでモジュール式アプリをコンテナ化する場合、コンテナ内で実行されるコードは、モジュール内で実行されるコードと同じであるため、マイクロサービスとも呼ばれます。

分散システム

分散システムは、ネットワーク経由で通信して共通の目標を達成する独立したモジュールで構成されます。これらのモジュールは異なるマシンで実行できますが、単一のシステムとして連携して動作します。

モジュール式の Cymbal Books アプリもこの定義に当てはまります。モジュールは独立して実行され、HTTP 経由でデータを交換しますが、全体としては 1 つのシステムとして機能します。次のセクションでは、わかりやすくするために、すべてのモジュールを単一のマシンで実行しますが、これは必須ではありません。各モジュールは別のサーバーで簡単に実行できます。そのため、Cymbal Books アプリのモジュール バージョンは分散システムとして分類できます。

モジュール実装をテストする

Cymbal Books モノリスが、モジュールが Flask アプリであるモジュラー アプリに変換される方法を確認したので、アプリケーションをテストして、各モジュールが独立して実行されることを確認できます。

このチュートリアルでは、同じマシンでモジュールを実行します。ただし、各モジュールは自律的であるため、エンドポイントを介して他のモジュールと通信できます。そのため、各モジュールを個別のサーバーで実行することもできます。

環境の設定

テストの準備を行う手順は次のとおりです。

  1. ターミナルで、クローン作成されたリポジトリの modular ディレクトリに移動します。

    cd modular
    
  2. 仮想環境 book-review-env がアクティブであることを確認します。有効化の手順について確認する必要がある場合は、仮想環境を作成して有効にするをご覧ください。

Flask アプリを起動する

/modular フォルダには、すべての Flask アプリケーションを同時に起動する bash スクリプトが含まれています。アプリの各モジュールは、8080 や 8081 などの一意のポートをリッスンします。

  • ホームページの Flask アプリ(home.py): ポート 8080
  • 書籍の詳細 Flask アプリ(book_details.py): ポート 8081
  • 書籍レビューの Flask アプリ(book_reviews.py): ポート 8082
  • Images Flask アプリ(images.py): ポート 8083

モジュールはすべて同じマシンで実行されるため、各モジュールは一意のポート番号でリッスンする必要があります。各モジュールが異なるサーバーにある場合、ポートの競合を発生させることなく、同じポート番号でリッスンできます。

次のコマンドで bash スクリプトを実行します。

bash ./start_services.sh

このスクリプトは、起動に関する問題を特定できるように、各 Flask アプリ(home.py.logbook_details.py.log など)用に個別のログファイルを作成します。スクリプトが正常に完了すると、次のメッセージが表示されます。

All services have been started. Access the app at http://localhost:8080/

各 Flask アプリをテストする

ブラウザで次の URL にアクセスして、モジュールをテストします。

  • ホームページ: http://localhost:8080/ は、モジュール化された Cymbal Books アプリケーションのホームページを表示します。このページは、他のモジュールにリクエストを送信して、書籍の詳細、レビュー、画像を取得します。
  • 書籍の詳細: http://localhost:8081/book/1 は、ID 1 の書籍の詳細を返します。このレスポンスは JSON データであり、アプリはこれをフォーマットして、人が読みやすい形式で表示します。
  • 書籍のレビュー: http://localhost:8082/book/1/reviews は、ID 1 の書籍のレビューを取得して返します。レビューは JSON 形式です。ホームページ モジュールはこのデータをリクエストし、書籍の詳細ページに統合します。
  • 画像: http://localhost:8083/images/fungi_frontier.jpg は、Fungi Frontier の書籍の表紙画像を提供します。URL が正しければ、画像がブラウザに直接読み込まれます。

Flask アプリを停止する

テストが完了したら、次のコマンドを使用してすべての Flask アプリを停止します。

kill $(cat home.py.pid book_details.py.pid book_reviews.py.pid images.py.pid)

概要

このチュートリアルでは、Cymbal Books モノリスをモジュール化する方法について説明しました。このプロセスは次の手順で構成されます。

  1. アプリの個別のコンポーネントを特定する
  2. モジュールの作成
  3. 各モジュールが、必要なデータにのみアクセスできるようにする

その後、ローカルマシンでモジュール実装をテストしました。

次のステップ

次のチュートリアル モジュラー型のアプリをコンテナ化できるように準備するでは、localhost ではなく Kubernetes Service 名を使用するようにエンドポイントを更新して、モジュラー型のアプリをコンテナ化できるように準備する方法について説明します。