バイセル Tech Blog

バイセル Tech Blogは株式会社BuySell Technologiesのエンジニア達が知見・発見を共有する技術ブログです。

バイセル Tech Blog

Cloud Run で OpenAPI Documentのモックをデプロイする

テクノロジー開発部の村上です。現在はアーキテクチャ周りを担当しています。
弊社ではAPIをOpenAPIで定義し、モックを使いフロントエンドの開発を行っています。
これまではApp EngineのFlexible Environmentを使用していたのですが、
Cloud Next'19で発表されたCloud Runを代わりに使用してみたのでその紹介をしたいと思います。

Cloud Runについて

一言で言うと、Docker コンテナを使用したサーバーレスのサービスです。
AWS LambdaやGCPのCloud Functionsではコード(関数)をデプロイするのですが、
Cloud RunではHTTPサーバーが走るコンテナをデプロイします。
ですので、以下を満たすようなDockerイメージさえ用意できれば、
言語等の制限なしに、基本的には何でも動かすことが可能です。

  1. PORTという環境変数で指定されたポートをlistenするHTTPサーバーが走る
    • 実際には8080が代入される
  2. ステートレス
    • サーバーレスなので当然ですが、ディスク書き込みは実際にはメモリ書き込みになるのは注意です

詳細な制約は、以下の公式ドキュメントに書かれています。
Container runtime contract

ちなみに、技術的にはKubernetes上でKnativeというミドルウェアを使って動作させています。
ですので、自身のGKEクラスタ上にデプロイすることも出来るようになっています。
また、簡単に相互に移行出来ることも公式ドキュメントではメリットに挙げられています

OpenAPIと、そのモックサーバーについて

OpenAPIは、REST APIの定義のためのフォーマットの1つです。現在はVersion 3.0.0が出ています。
APIの定義がしやすくなるのは勿論ですが、そこで定義したインターフェースに従った各種言語・フレームワークのコードを生成出来るという利点があります。
コードの生成には、OpenAPI Generatorというツールを使用します。
多くの言語・フレームワークではインターフェースに沿った雛形が生成されるだけですが、
Spring Bootを指定すると、ドキュメント兼モックサーバーが生成されます。(WEB+DB PRESS Vol.108 で知りました)
ここでいうモックサーバーとは、OpenAPIで定義したAPIの出力例に従ったレスポンスを返してくれるサーバーのことを意味しています。
それを接続先にすることで、フロントエンドの開発がやりやすくなります。

今回のケースでCloud Runを使う理由

使ってみたかったというのもありますが、
今回のケースは以下の理由で、比較的Cloud Runにあっているユースケースだと考えられます。

  1. モックなのでステートレス
  2. モックなのでレイテンシーはさほど気にしない
    • 現在Cloud Runは、us-central1しか対応していないのです
  3. フロントエンド開発時にしか使用しないので、従量課金に向いている
  4. コードは自動生成するので、App Engineに合わせるよりコンテナで走らせるほうが簡単

翻すと、Cloud FunctionsやApp Engineが向いているケースも多くあると思います。

実際にデプロイする

それでは実際にデプロイしてみましょう。 以下の3手順が必要となります。

  1. Spring Bootアプリケーションの生成・ビルド
  2. Docker imageのデプロイ
  3. Cloud Runにデプロイ

1. Spring Bootアプリケーションの生成・ビルド

openapi.yamlにOpenAPI Documentを定義しているとして、まずはSpring Bootのコードを生成します。
Dockerイメージが用意されているので、以下のコマンドを叩けば良いです。
注意点としては、Cloud Runではポート8080をlistenするので、--additional-propertiesで指定する必要があります。

docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate \
    -i /local/openapi.yaml \
    -g spring \
    -o /local/springs_stub \
    --additional-properties returnSuccessCode=true,serverPort=8080

そうすると、springs_stubディレクトリにSpring Bootのアプリケーションのコードが生成されるので、
mavenでアプリケーションをビルドします。

docker run --rm -v ${PWD}/springs_stub:/local/springs_stub -w /local/springs_stub maven mvn package

今回はmavenの公式Dockerイメージを使用しましたが、勿論ローカルのmavenでも問題ないです。
これで、springs_stub/target/openapi-spring-1.0.0.jarにアプリケーションがパッケージされました。

2. Docker imageのデプロイ

Cloud Runでは、コンテナイメージレジストリにDocker imageを上げておく必要があります。
ですので、以下のようなDockerfileを用いてビルドし、Docker HubやGoogle CloudのContainer Registryに上げておきます。

FROM openjdk:8-jdk-alpine
WORKDIR /usr/src/app
COPY openapi-spring-1.0.0.jar /usr/src/app/app.jar
ENTRYPOINT ["java","-jar","-Djava.security.egd=file:/dev/./urandomv", "/usr/src/app/app.jar"]

ちなみに、Spring Bootアプリケーションの生成・ビルドをDockerfile内で定義することも勿論可能です。
ただ、説明がしやすいのと、Cloud Buildを使う場合そこで前工程を行うことが出来る関係上、
今回は手順を分けました。まとめる場合はmulti-stage buildを使うと良いかと思います。

もしContainer Registryに手動でデプロイする場合はCloud Buildを使用すると、
カレントディレクトリ上のDockerfileを読み込んでGCP上でビルドとデプロイが行われます。

gcloud builds submit --tag asia.gcr.io/[PROJECT_ID]/[IMAGE_NAME] .

3. Cloud Runにデプロイ

最後に、gcloudコマンドでCloud Runにデプロイします。

gcloud beta run deploy <サービス名> --image <イメージ> --region us-central1 --memory 512Mi

Spring BootはJavaのアプリケーションで、メモリを多く必要とするので、メモリを明示的に指定しています。
(デフォルトは256MiB)

いかがでしょうか。普段Dockerを使っている方には、非常にシンプルに見えたかと思います。
現在はβ版なので、正式リリースされることとasia-northeast1リージョン対応に期待です。

参考資料