🛠️

Cloud Runをコマンドやスクリプトを実行するサーバレスジョブ基盤として使う

2021/06/05に公開

はじめに

リアルタイム処理がもてはやされてから何十年もたちますが、それでもなんだかんだで無くならないのがバッチ処理です。
今回は小さなバッチをCloud Runで実行する方法を紹介します。

なぜCloud Runでバッチなのか?

GCPのCloud RunはLibreOfficeを実行してPDFを生成したりだとか、AWS LambdaやCloud Functionsとは異なりDockerゆえになんでも実行できる、という特性を持っています。これを使う事でJSやPythonを実行する代わりにBashベースで様々なワークロードを動かすことが出来ます。私も上述のPDF変換や逆にImageMagicを使ってPDFを画像に変換したりとか便利に使っています。

バッチというのはその特性上 「動いて無い時間」 の方が圧倒的に長いです。そのためVMインスタンスを専用で作ると少し非効率なのですがCloud RunやLambdaのようなFaaSを使う事で効率的に運用できます。

Cloud Runはタイムアウトがあるので所謂夜間バッチのような長時間なバッチを単純に実行には不向きですが 「比較的軽い処理を実行するにはとても良いバッチ基盤 「となります。

http-wrapperでスクリプト/コマンドのHTTP化

Cloud Runは上記の通り便利なのですが、基本的にPubSubだったりHTTPだったりでキックするので、通常のLinuxのCLIのままでは使えません。そのため実行したいShellなどを 「Webアプリケーション等を作成して包んでやる必要 があります。

昔懐かしCGIをApacheなどで使っても良いですし、RubyやPython、あるいはJSなどお気に入りのコードでHTTPサーバを書くのも良いでしょう。ほんの数行から数十行で目的は達成できるはずです。とても簡単。

ただ、いくら簡単でも毎回書くのはやはり面倒なので引数に渡したコマンドをHTTP化するhttp-wrapperというコマンドを書いてみました。

https://github.com/koduki/http-wrapper

使い方は非常にシンプルで以下のように実行します。

$ hwrap -p 5000 ls
command: ls, port: 5000
.
.
.
⇨ http server started on [::]:5000

これでポート5000番でリクエストを受けたらlsコマンドを実行するWebサーバが起動しました。以下のようにargsにカンマ区切りで渡す事でコマンドライン引数とすることが出来ます。

$ curl "localhost:5000?args=-l,/home"
hwrap側の標準出力には以下のように出ます。
cmd: ls, args: [-l /home]
total 8
drwxr-xr-x 30 koduki  koduki  4096 Jun  4 20:58 koduki
status: success

これで簡単にコマンドやシェルをWebアプリ化する事が出来ます。便利ですね!(自画自賛

なおユーザのリクエストをそのままこのアプリに渡すような実装にしてしまうとOSコマンドインジェクションの恐れがあるので決してやらないでください。

実行のイベントトリガーを作る

さてCloud Runにバッチを実行する仕組みを作ることは出来ましたが、バッチなので時間などイベントに応じて実行される必要があります。

まず実行のイベントトリガーから考えます。通常考慮するのは下記あたりでしょう。

  • 毎日0時に実行とか毎分実行とか時間をトリガー
  • 特定のファイルの更新やDBへの書き込みなどをトリガーにして実行

簡単なのは時間をトリガーにする方式ですね。
https://cloud.google.com/scheduler

Cloud Schdulerを使う事でcronの同じフォーマットで好きなタイミングで実行する事が出来ます。祝日とかまでは考慮出来ないと思いますが、多くのパターンはこちらで十分でしょう。

つづいて、特定のファイル更新やDBへの書き込みをトリガーにする場合です。これには最近導入されたEventarcを使います。
https://cloud.google.com/eventarc/docs/overview

こちらはCNCFで策定されているCloudEventsをベースにした仕組みで、ストアドのトリガーやAWS Lambda/Cloud Functionsのようにイベントに応じて処理を実行するための仕組みです。GCPの場合はaudit logをベースにしてるためDBへの書き込みやファイルのアップロードの検知など様々なイベントをトリガーにすることが出来ます。

ワークフロー/ジョブネットを作る

本当にシンプルなバッチであれば先ほどまでの機能で十分なのですが、もう少し本格的なジョブだと並列処理や後続処理などのワークフローをジョブネットとして管理したくなりますよね?
それを可能にするのが最近導入されたWorkflowです。
https://cloud.google.com/workflows

GCPにはこのようなワークフローを実装できる仕組みはいくつかありますが、Workflowが最も手軽かつシンプルに利用できると思います。

まとめ

個人的に以前より自作のhttp-wrapperを使ってCloud Runのバッチ利用はしてたのですがここ最近はEventarcやWorkflowが導入されてより使いやすくなったと思います。

サーバレスなバッチは本格的に組めば大量並列で動かして大規模なデータを処理することもできますが、まずは日々のバッチを低コストで運用するために使うのが良いかと思っています。

それではHappy Hacking!

Discussion