フォーム読み込み中
こんにちは。ソフトバンクのKANGです。
最近サーバーレスが人気ですが、RESTだけではなく gRPCも必要なケースが増えています。Alibaba Cloud Function Compute(以下 FC)は最近 gRPC HTTP Trigger をサポートできるようになりましたので、本記事では、gRPC の概要を簡単に紹介したうえで、FCを利用して gRPC API を実装・公開する方法を、実際のコード例とともに解説します。
近年、サーバーレスアーキテクチャが普及しています。それに伴い、「APIといえばREST」という時代も変わりつつあります。特にマイクロサービス間通信では、より低レイテンシで型安全(データ形式を事前に定義し、不整合を防ぐ)な通信を実現できる gRPC を採用するケースが増えています。
gRPCはGoogle によって開発されたHTTP/2上で動くRPCであり、低レイテンシや型定義(*.proto)ができるなどの特徴を持っており、Python/Node.js/Go など多言語に対応しています。
なぜgRPCが必要なのかというと、REST API と比較すると、gRPC は通信効率が高く、マイクロサービス内部の通信や、双方向ストリーミングが必要なユースケース、型安全なAPI設計が必要なシナリオが増えているためです。
Function Compute は、サーバーの管理を行うことなくコードを実行できるフルマネージドのサーバーレスサービスです。HTTP や Timer、OSS など複数のトリガーに対応しており、特に最近、 HTTP Trigger で gRPC を受け付けることも可能になりました。
これにより、サーバーを用意せずに gRPC サービスを公開できるようになり、スケーラブルで低遅延なマイクロサービスをよりシンプルに構築できます。
必要環境
Alicloud CLI or ECS / FC tool
Python 3.9
protoc lib
4.2.2 以下のコマンドを実行し、CLI実行するためのaccess keyなどの情報を設定します。
sudo s config add
注:Account IDは RamアカウントのIDではなく、管理者アカウントのIDを入力する必要があります。
今回は Python を使ってシンプルな gRPC サービスを作成したいと思います。
sudo s init fc3-custom-python-grpc
cd fc3-custom-python-grpc
fc3-custom-python-grpc配下に、以下のファイルをそれぞれ作成します。
fc3-custom-python-grpc/
├─ s.yaml # Serverless Devs 用
├─ Dockerfile
├─ requirements.txt
├─ code/
│ ├─ app.py # gRPC サーバーエントリ
│ ├─ helloworld.proto
│ ├─ helloworld_pb2.py
│ ├─ helloworld_pb2_grpc.py
│ └─ start.sh
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello(HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
(事前に protoc と grpc_python_plugin をインストールする必要があります。)
cd code
python -m pip install grpcio-tools
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. helloworld.proto
上記のコマンドを実行すると、helloworld_pb2.py と helloworld_pb2_grpc.pyのファイルが自動的に作成されます。
helloworld_pb2.py と helloworld_pb2_grpc.pyはサーバ/クライアントで使えます。
(fc3-custom-python-grpc/code/app.py のファイルを作成します。)
# app.py
from concurrent import futures
import os
import grpc
import helloworld_pb2, helloworld_pb2_grpc
PORT = int(os.environ.get("PORT", 8089)) # FC 側は 8089 を推奨
ADDR = f"[::]:{PORT}"
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
name = request.name or "world"
return helloworld_pb2.HelloReply(message=f"Hello {name}")
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port(ADDR) # コンテナ内部ではプレーンでリッスン
print("Starting gRPC server on", ADDR)
server.start()
server.wait_for_termination()
if __name__ == "__main__":
serve()
注:Function Compute では gRPC 用に 8089 ポートの利用が推奨されているため、アプリケーション側も同じポートで待ち受けます。
requirements.txt
grpcio
grpcio-tools
start.sh
#!/bin/sh
# Start gRPC server
python app.py
実行権限を付けておく:
chmod +x code/start.sh
DockerfileではPythonの軽量イメージを利用し、必要な依存関係をインストールしたうえでアプリケーションを起動します。
FROM python:3.9-slim
WORKDIR /app
# 必要なツールを入れる(軽量に)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
# アプリをコピー
COPY code/ /app/
# ポートは内部で 8089 を使う(FC doc 推奨)
ENV PORT=8089
# 起動
CMD ["./start.sh"]
s.yaml ではHTTP Trigger の protocol:grpc を指定し、caPort に8089を設定します。これにより、FC がHTTP/2 ベースで gRPCリクエストを受け付けるようになります。
edition: 1.0.0
name: hello-world-app
access: "default"
vars: # グローバル変数
region: "cn-shanghai" #必要に応じてregionを書き換えてください
service:
name: "hello-world-service-0304"
description: 'hello world by serverless devs'
internetAccess: true
services:
helloworld: # service name / model name
component: fc
actions:
pre-deploy:
- run: docker run --platform linux/amd64 --rm -v `pwd`/code:/code python:3.10-slim bash -c "cd /code && pip3 install -r requirements.txt -t . -i https://pypi.tuna.tsinghua.edu.cn/simple"
path: .
props:
region: ${vars.region}
service: ${vars.service}
function:
name: "fc-custom-python-grpc"
description: 'hello world by serverless devs'
timeout: 90
memorySize: 512
runtime: custom
codeUri: ./code
instanceConcurrency: 3
caPort: 8089
customRuntimeConfig:
command:
- “usr/bin/python3”
- “code/app.py”
triggers:
- name: http2Trigger
type: http
config:
protocol: grpc
authType: anonymous
❋customRuntimeConfig.port: 8089 を明示的に設定します。(FC の gRPC 用ポート)
❋type: http として config.protocol: grpc を指定する必要があります。(これで HTTP トリガーが gRPC を受けるように設定されます)。
❋ Serverless Devs の YAML サンプルは公式ドキュメントや GitHub のサンプルを参照できます。
デプロイは以下のコマンドで実行できます。
s deploy -y
デプロイが完了すると、対象のFunctionがFCコンソール上に作成されます。
またデプロイ後、HTTP Trigger のエンドポイント(例:<name>.<region>.fcapp.run)が払い出されます。このエンドポイントが gRPC クライアントの接続先になります。
ローカル環境では、Docker でコンテナを起動し、grpcurl -plaintext を使って動作確認が可能です。
# プロジェクトルートで
docker build -t grpc-fc-sample .
# コンテナを起動(ポートマップは任意)
docker run -p 8089:8089 grpc-fc-sample
別ターミナルで 以下のコマンドを実行し、動作を確認します。
grpcurl -proto proto/helloworld.proto -plaintext -d '{"name":"Alibaba"}' localhost:8089 helloworld.Greeter/SayHello
期待するレスポンス:
{
"message": "Hello Alibaba"
}
Function Compute 上では TLS が必須となるため、-plaintext は使用できません。検証時には -insecure を指定できますが、本番環境では必ず証明書検証を有効にすることを推奨します。
grpcurl -insecure \
-proto proto/helloworld.proto \
-d '{"name":"Alibaba"}' \
fc-custhon-xxxxxx-shanghai.fcapp.run:8089 \
helloworld.Greeter/SayHello
注:fc-custhon-xxxxxx-shanghai.fcapp.runはFCの HTTP トリガーのパブリックエンドポイントです。
成功すると、以下のレスポンスが返されます。
{
"message": "Hello Alibaba"
}
実運用では、ポート設定の不一致や TLS 設定ミスがトラブルの原因になりやすいポイントです。また、proto の変更がある場合はクライアントとの互換性を慎重に管理する必要があります。
instanceConcurrency の値はワークロードに応じて調整し、コールドスタートの影響を最小化する設計も検討するとよいでしょう。コンテナサイズをできるだけ小さく保つことも、起動時間短縮につながります。
Function Compute の gRPC 対応により、サーバーレス環境でも高性能で型安全な API を実装できるようになりました。Proto の定義から実装、デプロイ、動作確認までの流れは比較的シンプルであり、マイクロサービス基盤として十分実用的です。
今後は ACK や ECI と組み合わせることで、より柔軟なクラウドネイティブ構成を実現できるでしょう。
条件に該当するページがございません