マイクロサービスを Pub/Sub および GKE と統合する

このチュートリアルでは、写真共有アプリを Google Kubernetes Engine(GKE)にデプロイします。ここでは Pub/Sub を使用して、長期実行プロセスを非同期的に起動する方法について説明します。また、Cloud Storage の Pub/Sub 通知を使用して、アプリのアプリケーション コードを変更せずにサイドジョブを追加する方法についても学習します。アプリは Cloud Build によってコンテナ化され、Container Registry に保存されます。アプリは Cloud Vision を使用して、不適切な画像を検出します。

マイクロサービス アーキテクチャを基にしてウェブアプリを設計する場合、アプリの機能をマイクロサービスに分割する方法と、それらのマイクロサービスをアプリから呼び出す方法を決定します。時間のかかるサービスには、非同期のサービス呼び出しを使用できます。このチュートリアルは、GKEPub/Sub などの最新技術を使用して、非同期でマイクロサービスを実装するデベロッパーやアーキテクトを対象としています。

State of DevOps で、ソフトウェア デリバリーのパフォーマンスを向上させると認められた機能が報告されています。このチュートリアルでは、アーキテクチャの機能について説明します。

サムネイル生成アプリのアーキテクチャ パターン

次の図は、アプリがサムネイル画像を生成するシナリオの例を示しています。

Compute Engine にデプロイされたアプリのアーキテクチャ。

上の図では、アプリはクライアントから画像ファイルを受け取り、自動的にサムネイルを生成します。現在、このアプリは Compute Engine の仮想マシン(VM)インスタンス、および Cloud Storage のバックエンド ファイル ストレージで実装されます。Cloud Load Balancing により、リクエストが複数の VM に配信されます。

VM の維持に必要な運用のオーバーヘッドを減らすには、VM を使用しない新しいアーキテクチャにこのシステムを移行します。

下図の新しいアーキテクチャは、複数のマネージド サービスで構成されています。

VM なしでデプロイされたアプリのアーキテクチャ

この新しいアーキテクチャでは、クライアントが画像をアプリに送信することで、Cloud Storage に直接送信されます。その後、Pub/Sub 通知によりメッセージが Pub/Sub メッセージ キューに配置されます。メッセージは、GKE で実行されるマイクロサービスを呼び出します。マイクロサービスは Cloud Storage から画像を取得してサムネイルを生成し、それを Cloud Storage にアップロードします。

この新しいアーキテクチャには次のような利点があります。

  • 独立したスケーラビリティ: 元のアーキテクチャでは、Compute Engine で実行されるアプリには 2 つのコア機能があります。1 つはファイルを受信する機能、もう 1 つは元の画像からサムネイルを生成する機能です。アップロードされたファイルの受信はネットワーク帯域幅を消費する一方、サムネイルの生成は CPU 使用率が非常に高いタスクです。Compute Engine インスタンスに画像を生成する CPU リソースが不足しているものの、ファイルの受信に十分なネットワーク リソースが存在することも考えられます。新しいアーキテクチャでは、これらのタスクは Cloud Storage と GKE によって共有され、独立したスケーラビリティを確保できます。
  • リソースの効率的な利用: 元のアーキテクチャでは、Compute Engine インスタンスをスケールアウトすると、オペレーティング システムの実行により多くのリソースが消費されます。GKE では、少数のサーバーで複数のコンテナを実行することでサーバー リソースを効率的に使用できます(ビンパッキング)。新しいアーキテクチャではコンテナを迅速にスケールアウトおよびスケールインできるため、負荷の短時間での急増に対応でき、増加が落ち着くとすばやくスケールインできます。
  • 簡単な新機能追加: 元のアーキテクチャで機能を追加する場合、機能を同じ Compute Engine インスタンスにデプロイする必要があります。新しいアーキテクチャでは、メーラーなどのアプリを開発して、新しいサムネイルの生成時に通知を受け取ることができます。Pub/Sub は、Compute Engine インスタンスの元のコードを変更することなく、サムネイル生成アプリとメーラーアプリに非同期的に接続できます。
  • 結合の減少: 古いアーキテクチャにおける一般的な問題に、一時的結合 があります。メールリレー サーバーがダウンすると、アプリは通知の送信を試みますが、失敗します。これらのプロセスは密接に関連しており、クライアントはアプリケーションからレスポンスを正常に受け取ることができない可能性があります。新しいアーキテクチャでは、サムネイルの生成と通知の送信が疎結合であるため、クライアントはレスポンスを正常に受信できます。

この新しいアーキテクチャには、次のようなデメリットがあります。

  • アプリのモダナイゼーションに必要な追加作業: アプリのコンテナ化に、時間と労力が要されます。新しいアーキテクチャでは、より多くのサービスが使用され、アプリのモニタリング、デプロイ プロセス、リソース管理の変更など、オブザーバビリティに対する異なるアプローチが必要になります。
  • アプリ側でのサムネイルの重複処理: Pub/Sub は、at-least-once メッセージ配信を保証します。つまり、重複したメッセージが送信される可能性があります。

フォトアルバム アプリの概要

次の図は、フォトアルバム アプリの最初の設計を示しています。

フォトアルバム アプリのアーキテクチャ

上の図はサムネイルの生成方法を示しています。

  1. クライアントがアプリに画像をアップロードします。
  2. アプリは、Cloud Storage に画像を保存します。
  3. サムネイルに対してリクエストが生成されます。
  4. サムネイル生成ツールでサムネイルが生成されます。
  5. フォトアルバム アプリに正常なレスポンスが送信されます。
  6. 正常なレスポンスがクライアントに送信されます。サムネイルは Cloud Storage で確認できます。

アプリをデプロイした後に、次のような問題が発生します。

  • アプリによるサムネイル生成に時間がかかります。その結果、クライアントに多数のタイムアウトが発生します。
  • サービス管理チームが不適切なアップロード コンテンツを検出したいと考えていますが、現時点ではアプリケーション チームにこの機能を実装できる十分なリソースがありません。

次の図では、サムネイルの生成が非同期的な個別サービスとして抽出されています。

サムネイル抽出のアーキテクチャ。

Pub/Sub を使用してサービス リクエストをサムネイル生成サービスに送信します。この新しいアーキテクチャではサービスを非同期で呼び出すため、アプリがクライアントにレスポンスを返した後に、サムネイルがバックグラウンドで作成されます。また、この設計では複数のジョブを並行して実行できるように、サムネイル生成サービスのスケーリングができます。

目標

  • GKE にサンプルのフォトアルバム アプリをデプロイします。
  • アプリから非同期のサービス呼び出しを行います。
  • Cloud Storage の Pub/Sub 通知を使用して、新しいファイルが Cloud Storage バケットにアップロードされたときにアプリをトリガーします。
  • Pub/Sub を使用して、アプリを変更することなく、より多くのタスクを実行できます。

料金

このチュートリアルでは、課金対象である次の Google Cloud コンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。新しい Google Cloud ユーザーは無料トライアルをご利用いただけます。

このチュートリアルを終了した後、作成したリソースを削除すると、それ以上の請求は発生しません。詳しくは、クリーンアップをご覧ください。

始める前に

  1. Google Cloud アカウントにログインします。Google Cloud を初めて使用する場合は、アカウントを作成して、実際のシナリオでの Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
  2. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  3. Cloud プロジェクトに対して課金が有効になっていることを確認します。プロジェクトに対して課金が有効になっていることを確認する方法を学習する

  4. GKE, Cloud SQL, Cloud Build, and Cloud Vision API を有効にします。

    API を有効にする

  5. Cloud Console で、Cloud Shell をアクティブにします。

    Cloud Shell をアクティブにする

    Cloud Console の下部にある Cloud Shell セッションが開始し、コマンドライン プロンプトが表示されます。Cloud Shell はシェル環境です。gcloud コマンドライン ツールなどの Cloud SDK がすでにインストールされており、現在のプロジェクトの値もすでに設定されています。セッションが初期化されるまで数秒かかることがあります。

環境の設定

このセクションでは、ドキュメント全体で使用されるデフォルトの設定値を割り当てます。Cloud Shell セッションを閉じると、これらの環境設定は失われます。

  1. Cloud Shell で、デフォルトの Cloud プロジェクトを設定します。project-id は実際の Google Cloud プロジェクト ID に置き換えます。

    gcloud config set project project-id
    
  2. デフォルトの Compute Engine リージョンを設定します。region は近くのリージョンに置き換えます。詳細については、リージョンとゾーンをご覧ください。

    gcloud config set compute/region region
    export REGION=region
    
  3. デフォルトの Compute Engine ゾーンを設定します。zone は近くのゾーンに置き換えます。

    gcloud config set compute/zone zone
    export ZONE=zone
    
  4. チュートリアル ファイルをダウンロードし、現在のディレクトリを設定します。

    git clone https://github.com/GoogleCloudPlatform/gke-photoalbum-example
    cd gke-photoalbum-example
    

Cloud Storage バケットを作成し、デフォルトのサムネイル画像をアップロードする

  1. Cloud Shell で、元の画像とサムネイルを保存する Cloud Storage バケットを作成します。

    export PROJECT_ID=$(gcloud config get-value project)
    gsutil mb -c regional -l ${REGION} gs://${PROJECT_ID}-photostore
    
  2. デフォルトのサムネイル ファイルをアップロードします。

    gsutil cp ./application/photoalbum/images/default.png \
        gs://${PROJECT_ID}-photostore/thumbnails/default.png
    
    • アップロードされた画像は gs://project-id-photostore/filename の形式で保存されます。ここで、filename は、アップロードする画像ファイルの名前を表します。
    • 生成されたサムネイルは gs://project-id-photostore/thumbnails/filename の形式で保存されます。
    • 元の画像と対応するサムネイルの filename は同じですが、サムネイルは thumbnails バケットに保存されます。
    • サムネイルの作成中は、default.png プレースホルダ サムネイル画像がフォトアルバム アプリに表示されます。

      デフォルトのプレースホルダ サムネイル画像。

  3. サムネイル ファイルを公開します。

    gsutil acl ch -u AllUsers:R \
        gs://${PROJECT_ID}-photostore/thumbnails/default.png
    

Cloud SQL インスタンスと MySQL データベースを作成する

  1. Cloud Shell で、Cloud SQL インスタンスを作成します。

    gcloud sql instances create photoalbum-db --region=${REGION} \
        --database-version=MYSQL_5_7
    
  2. 接続名を取得します。

    gcloud sql instances describe photoalbum-db \
        --format="value(connectionName)"
    

    チュートリアルの後半で使用するため、この名前をメモしておきます。

  3. MySQL ユーザー root@% のパスワードを設定します。

    gcloud sql users set-password root --host=% --instance=photoalbum-db \
        --password=password
    

    passwordroot@% ユーザーの安全なパスワードに置き換えます。

  4. Cloud SQL インスタンスに接続します。

    gcloud sql connect photoalbum-db --user=root --quiet
    

    プロンプトが表示されたら、前の手順で設定した password を入力します。

  5. photo_db というデータベースを作成します。ここで、ユーザーは appuser で、パスワードは pas4appuser です。

    create database photo_db;
    grant all privileges on photo_db.* to appuser@"%" \
        identified by 'pas4appuser' with grant option;
    
  6. 結果を確認して MySQL を終了します。

    show databases;
    select user from mysql.user;
    exit
    

    出力で、photo_db データベースと appuser ユーザーが作成されたことを確認します。

    MySQL [(none)]> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | photo_db           |
    | sys                |
    +--------------------+
    5 rows in set (0.16 sec)
    
    MySQL [(none)]> select user from mysql.user;
    +-----------+
    | user      |
    +-----------+
    | appuser   |
    | root      |
    | mysql.sys |
    +-----------+
    3 rows in set (0.16 sec)
    
    MySQL [(none)]> exit
    Bye
    

Pub/Sub トピックとサブスクリプションを作成する

  1. Cloud Shell で、thumbnail-service という Pub/Sub トピックを作成します。

    gcloud pubsub topics create thumbnail-service
    

    フォトアルバム アプリは、thumbnail-service トピックでメッセージを公開して、サムネイル生成サービスにリクエストを送信します。

  2. thumbnail-workers という Pub/Sub サブスクリプションを作成します。

    gcloud pubsub subscriptions create --topic thumbnail-service thumbnail-workers
    

    サムネイル生成サービスは、thumbnail-workers サブスクリプションからリクエストを受け取ります。

GKE クラスタの作成

  1. Cloud Shell で、API を呼び出す権限を持つ GKE クラスタを作成します。

    gcloud container clusters create "photoalbum-cluster" \
        --scopes "https://www.googleapis.com/auth/cloud-platform" \
        --num-nodes "5"
    
  2. 後の手順で kubectl コマンドを使用してクラスタを管理できるように、アクセス認証情報を構成します。

    gcloud container clusters get-credentials photoalbum-cluster
    
  3. ノードのリストを表示します。

    kubectl get nodes
    

    出力で、STATUSReady のノードが 5 つあることを確認します。

    NAME                                                STATUS    ROLES     AGE       VERSION
    gke-photoalbum-cluster-default-pool-0912a91a-24vt   Ready     <none>    6m        v1.9.7-gke.6
    gke-photoalbum-cluster-default-pool-0912a91a-5h1n   Ready     <none>    6m        v1.9.7-gke.6
    gke-photoalbum-cluster-default-pool-0912a91a-gdm9   Ready     <none>    6m        v1.9.7-gke.6
    gke-photoalbum-cluster-default-pool-0912a91a-swv6   Ready     <none>    6m        v1.9.7-gke.6
    gke-photoalbum-cluster-default-pool-0912a91a-thv8   Ready     <none>    6m        v1.9.7-gke.6
    

アプリの画像をビルドする

  1. テキスト エディタで application/photoalbum/src/auth_decorator.py ファイルを開き、ユーザー名とパスワードを更新します。

    USERNAME = 'username'
    PASSWORD = 'passw0rd'
    
  2. Cloud Shell で、Cloud Build サービスを使用してフォトアルバム アプリの画像をビルドします。

    gcloud builds submit ./application/photoalbum -t \
        gcr.io/${PROJECT_ID}/photoalbum-app
    
  3. Cloud Build サービスを使用して、thumbnail-worker サムネイル生成サービスの画像をビルドします。

    gcloud builds submit ./application/thumbnail -t \
        gcr.io/${PROJECT_ID}/thumbnail-worker
    

フォトアルバム アプリをデプロイする

  1. Cloud Shell で、フォトアルバムとサムネイル生成ツールの Kubernetes Deployment マニフェストを実際の環境に応じた値で更新します。

    connection_name=$(gcloud sql instances describe photoalbum-db \
        --format "value(connectionName)")
    
    digest_photoalbum=$(gcloud container images describe \
        gcr.io/${PROJECT_ID}/photoalbum-app:latest --format \
        "value(image_summary.digest)")
    
    sed -i.bak -e "s/\[PROJECT_ID\]/${PROJECT_ID}/" \
        -e "s/\[CONNECTION_NAME\]/${connection_name}/" \
        -e "s/\[DIGEST\]/${digest_photoalbum}/" \
        config/photoalbum-deployment.yaml
    
    digest_thumbnail=$(gcloud container images describe \
        gcr.io/${PROJECT_ID}/thumbnail-worker:latest --format \
        "value(image_summary.digest)")
    
    sed -i.bak -e "s/\[PROJECT_ID\]/${PROJECT_ID}/" \
        -e "s/\[CONNECTION_NAME\]/${connection_name}/" \
        -e "s/\[DIGEST\]/${digest_thumbnail}/" \
            config/thumbnail-deployment.yaml
    
  2. Deployment リソースを作成して、フォトアルバム アプリとサムネイル生成サービスを起動します。

    kubectl create -f config/photoalbum-deployment.yaml
    kubectl create -f config/thumbnail-deployment.yaml
    
  3. アプリに外部 IP アドレスを割り当てる Service リソースを作成します。

    kubectl create -f config/photoalbum-service.yaml
    
  4. Pod の結果を確認します。

    kubectl get pods
    

    出力で、STATUSRunningphotoalbum-appthumbail-worker がそれぞれ 3 つあることを確認します。

    NAME                                READY     STATUS    RESTARTS   AGE
    photoalbum-app-555f7cbdb7-cp8nw     2/2       Running   0          2m
    photoalbum-app-555f7cbdb7-ftlc6     2/2       Running   0          2m
    photoalbum-app-555f7cbdb7-xsr4b     2/2       Running   0          2m
    thumbnail-worker-86bd95cd68-728k5   2/2       Running   0          2m
    thumbnail-worker-86bd95cd68-hqxqr   2/2       Running   0          2m
    thumbnail-worker-86bd95cd68-xnxhc   2/2       Running   0          2m
    
  5. Service の結果を確認します。

    kubectl get services
    

    出力で、photoalbum-serviceEXTERNAL-IP 列に外部 IP アドレスがあることを確認します。すべての設定が完了するまで数分かかることがあります。

    NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP       PORT(S)        AGE
    kubernetes           ClusterIP      10.23.240.1     <none>            443/TCP        20m
    photoalbum-service   LoadBalancer   10.23.253.241   146.148.111.115   80:32657/TCP   2m
    

    外部 IP アドレスはこのチュートリアルの後半で使用するため、メモしておきます。この例では、146.148.111.115 です。

フォトアルバム アプリをテストする

  1. デプロイされたアプリにウェブブラウザでアクセスするには、次の URL に移動して、前の手順で設定したユーザー名とパスワードを入力します。

    http://external-ip
    

    external-ip は、前の手順でコピーした IP アドレスに置き換えます。

  2. 任意の画像ファイルをアップロードするには、[Upload] をクリックします。サムネイル プレースホルダが画面に表示されます。

    サービスが個別のサムネイルを生成するまでの間に表示されるプレースホルダのサムネイル。

    バックグラウンドで、サムネイル生成サービスがアップロードされた画像のサムネイルを作成します。生成されたサムネイルを表示するには、[Refresh] をクリックします。Cloud Vision API が、検出した画像ラベルを追加します。

    関連する画像ラベルが付いたサムネイル

    元の画像を表示するには、サムネイルをクリックします。

不適切な画像の検出機能を追加する

次の図は、Cloud Storage の Pub/Sub 通知を使用して、不適切なコンテンツを検出するサービスをトリガーする方法を示しています。不適切なコンテンツを含む新しいファイルが Cloud Storage バケットに保存されると、この機能が画像をぼかします。

不適切なコンテンツ検出機能のアーキテクチャ

上の図のように、サービスは Vision API のセーフサーチ検出機能を使用して、画像内の不適切なコンテンツを検出します。

Pub/Sub トピック、サブスクリプション、通知を作成する

  1. Cloud Shell で、safeimage-service という Pub/Sub トピックを作成します。

    gcloud pubsub topics create safeimage-service
    
  2. safeimage-workers という Pub/Sub サブスクリプションを作成します。

    gcloud pubsub subscriptions create --topic safeimage-service \
        safeimage-workers
    
  3. Pub/Sub 通知を構成して、新しいファイルが Cloud Storage バケットにアップロードされたときに safeimage-service トピックにメッセージが送信されるようにします。

    gsutil notification create -t safeimage-service -f json \
        gs://${PROJECT_ID}-photostore
    

ワーカー イメージをビルドし、デプロイする

  1. Cloud Shell で、Cloud Build を使用して safeimage-workers サブスクリプションのコンテナ イメージをビルドします。

    gcloud builds submit ./application/safeimage \
        -t gcr.io/${PROJECT_ID}/safeimage-worker
    
  2. セーフイメージ サービスの Kubernetes Deployment マニフェストを、実際の Cloud プロジェクト ID、Cloud SQL 接続名、コンテナ イメージのダイジェストで更新します。

    digest_safeimage=$(gcloud container images describe \
        gcr.io/${PROJECT_ID}/safeimage-worker:latest --format \
        "value(image_summary.digest)")
    sed -i.bak -e "s/\[PROJECT_ID\]/${PROJECT_ID}/" \
        -e "s/\[CONNECTION_NAME\]/${connection_name}/" \
        -e "s/\[DIGEST\]/${digest_safeimage}/" \
        config/safeimage-deployment.yaml
    

Deployment リソースを作成する

  1. safeimage-service トピックをデプロイするため、safeimage-deployment という Deployment リソースを作成します。

    kubectl create -f config/safeimage-deployment.yaml
    
  2. 結果を確認します。

    kubectl get pods
    

    出力で、STATUSRunning の 3 つの safeimage-worker Pod があることを確認します。

    NAME                                READY     STATUS    RESTARTS   AGE
    photoalbum-app-555f7cbdb7-cp8nw     2/2       Running   0          30m
    photoalbum-app-555f7cbdb7-ftlc6     2/2       Running   0          30m
    photoalbum-app-555f7cbdb7-xsr4b     2/2       Running   8          30m
    safeimage-worker-7dc8c84f54-6sqzs   1/1       Running   0          2m
    safeimage-worker-7dc8c84f54-9bskw   1/1       Running   0          2m
    safeimage-worker-7dc8c84f54-b7gtp   1/1       Running   0          2m
    thumbnail-worker-86bd95cd68-9wrpv   2/2       Running   0          30m
    thumbnail-worker-86bd95cd68-kbhsn   2/2       Running   2          30m
    thumbnail-worker-86bd95cd68-n4rj7   2/2       Running   0          30m
    

不適切な画像の検出機能をテストする

このセクションでは、テスト画像をアップロードし、セーフサーチ検出不適切な画像が機能によってぼかし処理されることを確認します。テスト画像は、ゾンビ姿の女の子の画像です(Pixaby CC0 ライセンス取得済み)。

  1. テスト画像をダウンロードします
  2. 画像をアップロードするには、http://external-ip に移動して [Upload] をクリックします。
  3. [Refresh] をクリックします。ぼかし処理が施されたサムネイルがアプリに表示されます。

    ぼかし処理を施したサムネイル

    アップロードした画像にもぼかし処理が施されていることを確認するには、サムネイルをクリックします。

クリーンアップ

課金を停止する最も簡単な方法は、チュートリアル用に作成した Cloud プロジェクトを削除することです。また、リソースを個別に削除することもできます。

プロジェクトの削除

  1. Cloud Console で [リソースの管理] ページに移動します。

    [リソースの管理] に移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

個々のリソースの削除

プロジェクトを削除する代わりに、このチュートリアルで作成したリソースを削除できます。

  1. GKE からリソースを削除します。

    kubectl delete -f config/safeimage-deployment.yaml
    kubectl delete -f config/photoalbum-service.yaml
    kubectl delete -f config/thumbnail-deployment.yaml
    kubectl delete -f config/photoalbum-deployment.yaml
    
  2. GKE からクラスタを削除します。

    gcloud container clusters delete photoalbum-cluster --quiet
    
  3. Container Registry から画像を削除します。

    gcloud container images delete safeimage-worker
    gcloud container images delete thumbnail-worker
    gcloud container images delete photoalbum-app
    
  4. Pub/Sub からサブスクリプションとトピックを削除します。

    gcloud pubsub subscriptions delete safeimage-workers
    gcloud pubsub topics delete safeimage-service
    gcloud pubsub subscriptions delete thumbnail-workers
    gcloud pubsub topics delete thumbnail-service
    
  5. Cloud SQL インスタンスを削除します。

    gcloud sql instances delete photoalbum-db --quiet
    
  6. Cloud Storage バケットを削除します。

    gsutil rm -r gs://${PROJECT_ID}-photostore
    gsutil rm -r gs://${PROJECT_ID}_cloudbuild
    
  7. ファイルを削除します。

    cd ..
    rm -rf gke-photoalbum-example
    

次のステップ