Cloud Run + Cloud Storage FUSE試してみた
Cloud Storage FUSE | Google Cloud
Cloud Storage FUSEとは
FUSE が何か分かっている人は Cloud Storage FUSE という名前だけでピンと来ると思うが、よく分からない人のために乱暴に言うと
アプリケーションから見えるファイルシステムの中に Cloud Storage を mount できるもの
になる。図にするとこんな感じ。
※ もちろん本物のファイルシステムとまったく同じにはならないが。
Cloud Storage FUSE | Google Cloud
これまでのオブジェクトストレージを読み書きするコードの課題
Cloud Storage に限らずオブジェクトストレージは容量を気にする必要がないし、自動でレプリケーションされたり、とても便利な反面、通常はファイルシステムはファイルシステム、オブジェクトストレージはオブジェクトストレージで、それぞれの I/O にそれぞれ異なるコードが必要になる。
ではオブジェクトストレージの読み書きの動作をどう実現してどう確認するかというと、以下のような工夫が必要だった。
- emulator を使う(emulator が用意されていて API Client が emulator に対応していれば簡単)
- API Client を直接利用せず、いい具合に I/O を pluggable に切り替えてくれるライブラリを利用する
- 実際のクラウド環境にコードを deploy する
3 は間違いがないが、何か試すたびにいちいち deploy しないといけないし、クラウドの利用料金が掛かる(微々たるものかもしれないが)。
つまりオブジェクトストレージ(というかクラウドネイティブの機能)の I/O が入ると testability が落ちてしまうという問題を抱えている。
個人的には上の選択肢の 2 を必ず利用するようにしてきた。(自分で書き始めたコードでない場合は 1 もあり得る。)オブジェクトストレージの読み書きのライブラリの選定の際に差し替え可能で安定していそうなものを選ぶところから始め、読み書きの差し替えを行うコードを挟むところから始めるようにしている。
正直面倒ではあるけど、その後何回も結果を確認する際にいちいちクラウド環境で動かさないといけない方が面倒なので仕方がない。
オブジェクトストレージをmountするとはどういうことか
これがオブジェクトストレージをファイルシステムの一部に mount できるということは、インフラ側の設定さえ済めば、アプリケーションコード側からはファイルの読み書きのコードを書けばそれがローカルのファイルシステムに対するものか FUSE を通じたオブジェクトストレージに対するものかは気にする必要がないということを意味する。
ローカルの開発環境で動いている場合はローカルのファイルシステムを読み書きするし、クラウド環境で動いている場合はクラウドのオブジェクトストレージを読み書きしてくれる。
もちろん全部自分で作っているのであればファイルシステムとオブジェクトストレージの切り替えくらい自分でやれば済む、という場合もあると思うが、例えば DBM 的なライブラリを使いたいとか、利用するツールが暗黙のうちにファイルシステムに依存している場合はそうもいかない。以下の GCP 公式の対応状況では Cloud Storage FUSE 自体が AI 向けに売り出しているように見えるが、これにはそういう事情もあるのかもしれない。
GCPでの公式の状況
2024-02-11 時点で
Cloud Storage FUSEとの統合をサポートしている実行環境として挙げられているのは
- GKE
- Vertex AI
- Deep Learning VM Images
- Deep Learning Containers
- Batch jobs
- Cloud Composer
Cloud Storage FUSE と Google Cloud プロダクトの統合
になっているが、Cloud Run 側のドキュメントには
Cloud Storage FUSE と Google Cloud プロダクトの統合
あれもこれも知っていれば使えるよ、という情報がある。
Cloud Runでの利用は実はめちゃくちゃ簡単になっている
公式の GA の状況はまだまだっぽく見えるが、実際には
Cloud Run と Cloud Storage FUSE (GCS FUSE) の基本
にあるように、gcloud SDK では alpha components という扱いだが、
--add-volume
--add-volume-mount
フラグを利用することで gen2 実行環境1においてはめちゃくちゃ簡単に deploy できる
gcloud alpha run deploy | Google Cloud CLI Documentation
し、Cloud Run のコンソール画面では普通に Cloud Storage バケットを Volume に追加する機能がある。
Docker で例えるとホスト OS 側のパスを指定しておくことで Docker 環境からホスト OS のコードを読み込み、ストレージに書き込めるような、あんな感じで利用できる。
自分の感覚では
生のサーバで cron で動作させて、成果や認証の情報なんかをちょろっとファイルに書き出して終わる、みたいな伝統的なツールを Cloud Run に持ってくるとか簡単にできそう
という状態にきている。ようやく VPS を完全に解約してオッケーかも、と考えている。
やってみたこと
以下を組み合わせて試してみた。
- 実行環境
- Cloud Run Service gen2
- Cloud Run Jobs ( gen2 )
- 試したツール
- 生 Ruby
- Rails
- GDBM
- RocksDB
- SQLite
データの整合性のレベルで確認したわけではないし、並列度も全然厳密にテストしていないが、動作するという意味ではどれも問題なく動かすことができた。唯一ダメだったのは
FUSE 上の Cloud Storage に置いた SQLite を利用して Rails で SolidQueue を puma 管理下で動かすこと
だった。これは起動すらしなかった。
development 環境でもたまに SolidQueue worker プロセスがエラーを吐いて再起動するという現象は起きていたので、SQLite + SolidQueue 自体がそこまで実績がなさそうなのと、それをさらに FUSE の制限上で動かそうとするのが無理だったのかと予想している。
使ったコードは以下。
- wtnabe/example-cnbp-builder-extension-and-extended-run-image
- wtnabe/example-rails7-sqlite3-solid-queue
Rails については SolidQueue 云々より FUSE + SQLite というだけで cold start に 15s くらい掛かるので、これはちょっとさすがになんか別な方法考えた方がいいかも。
RocksDB についてはそこそこのサイズのデータベースを作ってもある程度(64MBとか)のサイズの chunk に分割されるので、key-value ストアとして Cloud Run のリソースの制限 ( 512 MB ) 内で利用するにはなかなかよいかも、と思った。当然速さは出ないけど、それでも十分機能します、みたいなシーンはそれなりにありそう。
2023年に GA になった Cloud Run Jobs は最初から gen2 で、従来からある service の方はオプション –execution-environment gen2 を与えると gen2 になる。 ↩