自分用の簡易なWeb APIが必要になり、GCPのCloud Runを初めて触ったので、記録として手順をまとめて公開しておくことにしました。
この記事で作るもの
GCP初心者向けの記事です。Cloud RunをWeb APIとして使用し、ローカルから**「こんにちは」とPOSTリクエストすると「こんにちはと言いましたね。」と返してくる超簡単なWeb API**を作ります。
ここで作るのは簡単なAPIですが、要するに入力と出力を整えれば、あとはいくらでも応用して処理が書けるので、その重要なインターフェース部分を作る手順です。
はじめに ~Cloud Runとは~
Web APIをサーバーレスで簡単に実現するには、AWS LambdaとAPI Gatewayを組み合わせる、またはGCP Cloud FunctionsやGAEという場合が多いかと思います。
ただしカスタムのライブラリが必要となる場合はAWS Fargate、更に無料でやるのはGCP Cloud Runという選択肢になります。
Cloud Runは呼び出されたときにコンテナを実行するというサービスです。要は、カスタムのライブラリを詰め込んだり、カスタムのデータを持たせて読み込ませて処理させる、といった使い方が可能です。またWeb API化でき、公開可能です。
AWSでいうとFargateやLambda(コンテナ)とAPI Gatewayが一緒になったサービスで、GCPの場合は永久無料枠が用意されているといった感覚です。なお詳しいユースケースは以下に記載されてます。
https://cloud.google.com/serverless-options/?hl=ja
ただし公開するWeb APIとなると、永久無料枠の場合はアクセス過多の際にスペックが貧弱すぎるため向いていません。
そこで自分がバッチ処理で使うWeb APIとして、Cloud Runを使うまでの手順を記載していきます。
Cloud Runの永久無料枠
Cloud Runは永久無料枠が用意されています。他のクラウドサービスはここまで太っ腹じゃないですね。
200 万リクエスト(1 か月あたり)
360,000 GB 秒のメモリ、180,000 vCPU 秒のコンピューティング時間
1 GB の北米からの下り(外向き)ネットワーク(1 か月あたり)
コンテナをずっと起動させておく場合はお金がかかってしまいますが、呼び出されたときのみコンテナを起動させる、1日に数回走るバッチ処理で使用するといった使い方であれば無料でいけるでしょう。
Cloud RunでWeb APIを作ろう
実際にCloud RunをWeb APIとして動かすまでには、以下の手順が必要になります。
- POSTリクエストを受け付けるコードを書く
- Web APIサーバーとしてのDockerfileを書く
- GCP上でDockerコンテナイメージをビルド+プッシュする(Container Registory)
- Cloud Runで新規サービスを作成し、イメージをデプロイする
PythonスクリプトとDockerfileについては、以下のとても分かりやすい記事をベースにして、POSTリクエストに対応させるために書き換えています。
Cloud Runに入門してみる
POSTリクエストを受け付けるコードを書く
まずは簡単に、POSTリクエストで送られてきたデータを処理し、返却するコードを書きます。json形式でリクエストされたdataキーの値を読み、「あなたは○○と送ってきましたね。」と返してきます。Python+flaskで書きます。
例えばローカルに./run-webapi
ディレクトリを作り、その配下に、以下のコードが書かれたhello-api.py
を配置しておきます。
import os
from flask import Flask, request
app = Flask(__name__)
@app.route('/', methods=['POST'])
def post_response():
request_dict = request.get_json()
req_data = str(request_dict['data'])
res_message = f'あなたは{req_data}と送ってきましたね。'
return res_message
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 5000)))
Web APIサーバーとしてのDockerfileを書く
次に./run-webapi
配下に、以下のDockerfile
を配置します。これでコンテナ起動時にhello-api.py
が実行され、コンテナはWeb APIサーバーとなります。
FROM python:3.7
ENV APP_HOME /hello-api
WORKDIR $APP_HOME
COPY . .
RUN pip install Flask gunicorn
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 hello-api:app
GCP上でのコンテナイメージのビルド
プロジェクト作成
まずはGCPのコンソールから新しいプロジェクトを作成します。(既存のプロジェクトにコンテナをビルドしたい人はもちろんスキップ)
プロジェクト名はhellowebapi
になりました。
コンテナイメージのビルド+ブッシュ
次にGCP上にコンテナイメージをビルドし、保存します。ローカルでビルドする必要はありません。
コンソールで、./run-webapi
配下に移動し、Google Cloud SDKのコマンドを入力します。
(※Google Cloud SDKがインストールされている前提です。詳しくはこちら https://cloud.google.com/sdk/docs/install?hl=JA )
$ cd ./run-webapi
$ gcloud builds submit --tag gcr.io/hellowebapi/hello-api --project hellowebapi
ビルド+プッシュが完了した段階で、Container Registory上にhello-api
の名前でコンテナイメージが保存されます。
Cloud Runに登録済みコンテナをデプロイする
最後に、Container Registoryに登録したコンテナをCloud Run上にデプロイし、ようやくWeb APIを作ります。
ウェブコンソール画面上の「サービスの作成」をクリックします。
①サービスの設定
デプロイメント プラットフォーム:Cloud Run(フルマネージド)
リージョン:us-central1 (Iowa)
サービス名:webapi-test
②サービスの最初のリビジョンの構成
既存のコンテナ イメージから 1 つのリビジョンをデプロイする:hello-api
のlatest
③このサービスをトリガーする方法の構成
HTTP上り(内向き):全てのトラフィックを許可する
認証:未認証の呼び出しを許可
なおここでは一旦、全ての認証を許可します。当然ですがセキュリティ上、本来は自分用のAPIの場合には認証をつけた方が良いですが、認証手順をすっ飛ばして使うために、アドレスを公開しないことを前提に未認証を許可します。
上記の設定を入力後、「作成」ボタンをクリックします。
1分後くらいに、ステータスが緑色になってURL「https://webapi-test-xxxxxx.a.run.app
」が表示されます。これがWeb APIのURLとなります。
Web APIを試す
ではローカル環境から、いま作ったCloud Run上のWeb APIを呼び出してみましょう。
JupyterNotebook上で以下のコードを実行してみます。
import requests
import json
json_data = json.dumps({'data':'「ローカル環境からこんにちは」'})
response = requests.post(
'https://webapi-test-xxxxxx.a.run.app', # 自分のWeb APIのURLに書き換え
json_data,
headers={'Content-Type': 'application/json'}
)
print(response.text)
以下の結果が返ってくれば成功です。
あなたは「ローカル環境からこんにちは」と送ってきましたね。
ちなみにコンテナの初回起動には数秒くらいかかります。初回から連続でリクエストを送る場合は、既にコンテナが起動しているのでレスポンスは速いです。
コンテナはしばらくすると自動で停止します。そうして料金が抑えられるわけですね。
コンテナが自動でスケールしないようにするために
Cloud Runの標準スペックは貧弱で、vCPU 1コア、RAMが256MBが標準です。そのため重い処理が走る場合、自動でスペックをスケールさせる機能があります。
まったりでもよいから無料の範囲で抑えたい、という場合は、スケールをさせないようにする必要があります。
ウェブコンソール画面上の「新しいリビジョンの編集とデプロイ」を押します。
「自動スケーリング」の「インスタンスの最大数」を1
に設定し、「デプロイ」を押します。
そうすることで、重い処理だとしてもスケールせずに1インスタンスで処理をするようになります。
注意事項:ストレージ容量に気を付けましょう
Cloud Runが無料とは言え、気を付けなければいけないちょっとした落とし穴があります。
登録済みのコンテナイメージはContainer Registoryで見られますが、実際のファイルはCloud Storageに保存されています。
Cloud Storageの永久無料枠は5GBですので、ポンポンとコンテナイメージを作っているとすぐに一杯になるので気を付けた方が良いですね。
おわりに
Cloud Runを利用すればものすごく簡単にWeb APIが無料で作れます。
私は「コンテナに簡易DBのような割と大きめのデータを持たせておき処理をする」という必要があり、Cloud FunctionsではなくCloud Runを使う場面があり、重宝しました。
2020年12月現在、AWS Lambdaでもコンテナに対応したそうですので試してみたいですが、外部公開のAPIまでとなるとまだAPI Gatewayが必要なので、どうしてもコストがかかります。その点、Cloud Runの無料枠は外部APIさえ作れてしまいますので、0円アプリを作るのに良いですね。