Google Compute Engine と gRPC を使用したモバイルアプリの作成

gRPC フレームワークにより、モバイルアプリはバックエンド サービスのメソッドをローカル オブジェクトと同様に呼び出すことができます。モバイルアプリは、gRPC の使用により通信帯域をより効率的に使用することができ、Google Cloud Platform で動作するバックエンド サービスとアプリ間の通信で発生するレイテンシが削減できます。

Google Compute Engine でモバイル バックエンドを実行し、モバイルアプリとバックエンド サーバー間の通信プロトコルに gRPC を使用すると、以下のような利点があります。

  • オンプレミスまたは仮想マシン上で実行されている既存のサービスを Cloud Platform に移行する最速の方法です。
  • HTTP/S よりも通信帯域をより効率的に使用できます。
  • 仮想マシンとサーバーの構成がすべて管理できます。
  • サードパーティ ライブラリが使用できます。
  • オートスケーラーを構成して、仮想マシンの数を必要な規模にスケーリングできます。

Compute Engine でサービスを実行する場合は、サーバーのメンテナンスと更新を手動で行う必要があります。モバイル バックエンド サービスを作成するその他の方法については、Google Cloud Platform を使用したモバイルアプリの作成をご覧ください。

このチュートリアルでは、例として Stickynotes というモバイルアプリを構築する作業を一通り行います。このアプリでは、Compute Engine で動作するバックエンド サービスとの接続に gRPC を使用します。

Stickynotes には、フロントエンド モバイルアプリとバックエンド サービスのコードが含まれています。モバイルアプリでは、テキスト フィールドにメッセージが入力できます。アプリは gRPC を使用してメッセージをバックエンド サービスに送信します。バックエンド サービスは draw2d を使用してテキスト メッセージを画像に変換し、モバイルアプリに返します。その後、モバイルアプリが黄色の背景上にそのメッセージを画像で表示します。

クライアント アプリは iOS アプリであり、バックエンド サービスは Go で記述されています。

目標

このチュートリアルの学習内容は次のとおりです。

  • バックエンド サービスとの接続に gRPC を使用する iOS モバイルアプリを作成する。
  • Compute Engine 上で gRPC バックエンド サービスを構成し実行する。

費用

このチュートリアルでは、以下を含む、Cloud Platform の課金対象となるコンポーネントを使用しています。

  • Google Compute Engine

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを出すことができます。Cloud Platform を初めて使用する方は、無料トライアルをご利用いただけます。

始める前に

  1. Cloud Console で、[VM インスタンス] ページに移動します。

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

  2. Cloud プロジェクトを選択または作成します。

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

以上の手順を完了したら、次のソフトウェアをインストールします。

  • Git
  • XCode 7.2 以降
  • Go

    Go が PATH 変数で指定されたパスにインストールされていることを確認してください。通常は /usr/local/go/bin です。

    オーナーとしてのユーザー アカウントを使用して Go をインストールします。root としてインストールした場合は、Go がインストールされたディレクトリ内で次のコマンドを実行し、オーナーを変更します(<username> の部分は自身のユーザー名に置き換えてください)。

    sudo chown -R <username> go
    
  • Cocoapods

    sudo gem install cocoapods
    
  • Homebrew

    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    
  • gRPC プラグインを含む protoc

    brew tap grpc/grpc
    brew install grpc
    

サンプルコードのクローンを作成する

git clone https://github.com/GoogleCloudPlatform/ios-docs-samples.git

次に、/solutions/stickynoteapi/gRPC に移動して、このソリューションのサンプルコードを見つけます。

サーバーをローカルで実行する

/stickynoteapi/gRPC/Go ディレクトリで、次のコマンドを実行します。

sh SETUP

次の出力が表示されます。

0. Ensure that protoc is installed.
/usr/local/bin/protoc
OK
1. Set gopath and search path
2. Get the Go plugin for protoc
3. Run protoc to generate the service API code
4. Get the server and client dependencies
5. Build the server and client
6. Stop any previously-running instances of the server
No matching processes belonging to you were found
7. Start the server
8. Run the client
2016/03/03 15:53:21 OK: message.png
9. Open the image in message.png

このセットアップでローカル クライアントも実行され、「Remember the milk.」というフレーズを使用してサーバーがテストされ、そのメッセージを含む画像が生成されます。

Remember the milk.

コマンドライン クライアントを使用して独自のメッセージに基づく画像を生成するには、次のコマンドを実行します。

./client "This is a test..."

ファイル /solutions/stickynoteapi/gRPC/Go/go/src/server/server.go には、gRPC サーバーを実行するコードが含まれています。このコードは、2 つの要素(1 つはリクエストを表し、もう 1 つはレスポンスを表します)を含む構造体 StickyNoteServer も定義します。

type StickyNoteServer struct{}

var stickyNoteServer StickyNoteServer

main 関数によって、ルートレベル ディレクトリの gRPC サーバーが定義され、ポート 8080 でトラフィックがリッスンされます。サーバーでは IP アドレスやドメインは指定されないため、変更せずにこのコードを Compute Engine で実行できます。

func main() {
	var err error
	var lis net.Listener
	var grpcServer *grpc.Server
	if !useSSL {
		lis, err = net.Listen("tcp", ":8080")
		if err != nil {
			log.Fatalf("failed to listen: %v", err)
		}
		grpcServer = grpc.NewServer()
	} else {
		certFile := "ssl.crt"
		keyFile := "ssl.key"
		creds, err := credentials.NewServerTLSFromFile(certFile, keyFile)
		lis, err = net.Listen("tcp", ":443")
		if err != nil {
			log.Fatalf("failed to listen: %v", err)
		}
		grpcServer = grpc.NewServer(grpc.Creds(creds))
	}
	pb.RegisterStickyNoteServer(grpcServer, &stickyNoteServer)
	grpcServer.Serve(lis)
}

Get 関数は gRPC リクエストでメッセージを受け取り、sticky.go に定義された関数を使用して、そのメッセージに基づいて画像を作成し、gRPC レスポンスで画像を返します。

func (s *StickyNoteServer) Get(ctx context.Context, r *pb.StickyNoteRequest) (*pb.StickyNoteResponse, error) {
	var sticky Sticky
	sticky.Message = r.Message
	sticky.Centered = false

	resp := &pb.StickyNoteResponse{}
	stickyBytes, err := sticky.DrawPNG(512, 512)
	resp.Image = *stickyBytes

	return resp, err
}

ローカル サーバーは実行中のままにし、それを使用してクライアント アプリケーションをテストできるようにします。

ローカル サーバーでの iOS クライアントの実行

  1. /stickynoteapi/gRPC/Objective-C ディレクトリで次のコマンドを実行し、BoringSSL、Protobuf、gRPC の依存関係をインストールします。インストールには数分かかります。

    pod install
    

    次の出力が表示されます。

    Analyzing dependencies
    Fetching podspec for `stickynote` from `stickyapi`
    Downloading dependencies
    Installing BoringSSL (2.0)
    Installing Protobuf (3.0.0-beta-2)
    Installing gRPC (0.12.0)
    Installing stickynote (0.0.1)
    Generating Pods project
    Integrating client project
    
    [!] Please close any current Xcode sessions and use
    `stickynotes.xcworkspace` for this project from now on.
    Sending stats
    Pod installation complete! There is 1 dependency from the Podfile and 4
    total pods installed.
    
  2. Xcode で Cocoapods により作成されたワークスペース stickynotes.xcworkspace を開きます。

  3. [Product] > [Scheme] > [stickynotes] をクリックして、現在のスキームを選択します。

  4. [Product] > [Run] を選択し、クライアント アプリケーションをビルドして起動します。Protobuf と gRPC で発生する警告は無視します。

  5. テキスト フィールドにメッセージを入力し、[return] をタップします。

メッセージが表示された黄色の付箋の画像が、テキスト フィールドの下に表示されます。

これはテストです...

クライアント アプリは、バックエンド サービスのロケーションをファイル StickyNotesViewController.m に設定します。テスト用に、これはローカルホストに初期設定されています。

static NSString * const kHostAddress = @"localhost";

テキスト フィールドにメッセージを入力した後、[return] をタップすると、次のアクションが開始されます。メッセージがクエリ文字列にエンコードされます。その後、開いているストリーミング接続にそのクエリが送信されます。

- (IBAction)textDidChange:(UITextField *) sender {
  if ([_streamSwitch isOn]) {
    StickyNoteRequest *request = [StickyNoteRequest message];
    request.message = sender.text;
    [_writer writeValue:request];
  }
}

openStreamingConnection 関数によりストリーミング接続が開きます。

- (void) openStreamingConnection {
  _writer = [[GRXBufferedPipe alloc] init];
  _updateCall = [_client RPCToUpdateWithRequestsWriter:_writer
                                          eventHandler:^(BOOL done, StickyNoteResponse *response, NSError *error) {
                                            [self handleStickynoteResponse:response andError:error];
                                          }];
  [_updateCall start];
}

Compute Engine でのサーバーの実行

  1. Google Cloud Console で [インスタンスの作成] ページに移動します。

    [インスタンスの作成] ページに移動

    1. [名前] を sticky-grpc に設定します。
    2. [作成] を選択します。

    インスタンスの作成

  2. Cloud Console の [ファイアウォール ルールの作成] ページに移動します。

    [ファイアウォール ルールの作成] ページに移動

    1. [名前] に「default-allow-grpc」と入力します。
    2. [ソースフィルタ] で、[すべてのソースから許可 (0.0.0.0./0)] を選択します。
    3. [許可対象プロトコル / ポート] に「tcp:8080」と入力します。
    4. [作成] を選択します。

    SSH の選択

  3. Cloud Console の [VM インスタンスの表示] ページに移動します。

    [VM インスタンスを表示] ページに移動

    1. sticky-grpc の横に表示された外部 IP アドレスを書き留めます。
    2. SSH の選択

    SSH の選択

  4. インスタンスに Git をインストールします。

    sudo apt-get update
    sudo apt-get install git
    
  5. Stickynotes サーバーコードのクローンを作成します。

    git clone https://github.com/GoogleCloudPlatform/ios-docs-samples.git
    
  6. Go と protoc をインストールします。/solutions/stickynoteapi/gRPC/Go/ ディレクトリで、次のコマンドを実行します。

    sh INSTALL
    
  7. INSTALL スクリプトにより設定された新しい環境変数を読み込みます。

    source $HOME/.bash_profile
    
  8. インスタンスで Stickynotes サーバーを開始します。/solutions/stickynoteapi/gRPC/Go/ ディレクトリで、次のコマンドを実行します。

    sh SETUP
    
  9. Xcode で、StickyNotesViewController.m を編集し、ステップ 2 で書き留めた Compute Engine の外部 IP アドレスにローカルホストを変更します。

    // static NSString \* const kHostAddress = @"localhost";
    static NSString \* const kHostAddress = @"198.51.100.0";
    
  10. [File] > [Save] を選択して、変更内容を保存します。

  11. [Product] > [Scheme] > [stickynotes] をクリックして、現在のスキームを選択します。

  12. [Product] > [Run] を選択し、クライアント アプリケーションをビルドして起動します。

  13. テキスト フィールドにメッセージを入力し、[return] をタップします。

グレーの背景が置き換えられ、メッセージが表示された黄色の付箋の画像が表示されます。

リモート サーバーでテスト中...

クリーンアップ

このチュートリアルで使用するリソースについて、Google Cloud Platform アカウントへの課金が発生しないようにする手順は次のとおりです。

プロジェクトの削除

課金をなくす最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。

プロジェクトを削除するには:

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

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

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

インスタンスの削除

Compute Engine インスタンスを削除するには:

  1. Cloud Console で、[VM インスタンス] ページに移動します。

    [VM インスタンス] ページに移動

  2. 削除するインスタンスをクリックします。
  3. [削除] をクリックしてインスタンスを削除します。

デフォルトのネットワークのファイアウォール ルールの削除

ファイアウォール ルールを削除するには:

  1. Cloud Console で、[ファイアウォール ルール] ページに移動します。

    [ファイアウォール ルール] ページに移動

  2. 削除するファイアウォール ルールのチェックボックスをクリックします。
  3. [削除] をクリックして、ファイアウォール ルールを削除します。

次のステップ

このサンプルは、gRPC を介して、Compute Engine で実行されるコードにモバイルアプリを接続する基本的な方法を示しています。このサンプルの機能を拡張して実際のアプリに使用する場合は、次の拡張を追加することを検討してください。

  • 静的 IP アドレスをサーバーに追加する -- デフォルトで、Compute Engine インスタンスに関連付けられた外部アドレスは一時的なものです。本番環境のアプリの場合、静的 IP アドレスをインスタンスに追加する必要があります。詳細については、インスタンスの IP アドレスの構成をご覧ください。

  • 負荷分散と自動スケーリングを追加する - ロードバランサとオートスケーラーを設定して、要求が増加したときに超過インスタンスをすばやく処理し、インスタンス間で均等にトラフィックを転送することで、トラフィックの急上昇を適切に処理します。詳細については、HTTP(S) 負荷分散の設定インスタンスのグループの自動スケーリングをご覧ください。

  • バックエンド サービスに他のホスティング オプションを検討する -- Compute Engine では、仮想マシンの制御を最大限に行うことができますが、その代わりに、インスタンスを手動で更新および管理する必要があります。Cloud Platform でモバイル バックエンド サービスをホストするその他の方法については、Google Cloud Platform を使用したモバイルアプリの作成をご覧ください。