はじめに
株式会社トラストバンクで地域通貨プラットフォーム chiica(チーカ)の開発責任者をしております湊(みなと)(@karura618)です。
この記事は トラストバンクAdvent Calender 2024 の記事です。
今回は昨年の記事に関連して、GCPのCloudRun + Memorystore Cloud Storage FUSE を使用したコンテナ間でのキャッシュ保持についての話を。
タイトルの件
「はじめに」にすでに記載しててネタバレですが。
CloudRunにてある画面を作成した際、入力画面した情報をSessionで保持させようとしたのですが、CloudRun自体は最小インスタンス数をデフォルトの「0」に設定しているため一定時間経過すると自動的に停止します。
そもそもオートスケーリングも設定してるのでセッションアフェニティを設定しても同一コンテナで処理されるかどうかどうかは担保されない。。。
さてどうしたものかと思いとりあえずMemorystore(Redis)上にSessionを保存しようかなと思ったら
(10/3~12の青色箇所がMemorystoreのコスト)
...( ゚д゚) ...(つд⊂)ゴシゴシ(;゚д゚)oh...
他コストを余裕で追い抜いた。。。
まあ、それまで一番コストかかってたのってContainer Registry Vulnerability Scanningなのでほんとに小規模なものしか作っていないのですがそれにしても。。。
わかってはいたけど改めてみると高い。。。マイクロサービスのSession保存するのに使うにしては高い。。。
代替案(Cloud Storage FUSE)
どうしたものかと思ったら知らないうちにCloudRunでCloud Storage FUSEが使えるようになってた。
のでちょっと試しに使ってみました。
設定手順(for Laravel)
LaravelのSession、Cacheの各ファイルをGCS上にマウントするにあたり、以下のような設定をしました。
config/session.php
<?php
use Illuminate\Support\Str;
$file_path = !empty(env('STORAGE_PATH')) ? env('STORAGE_PATH') . env('APP_ENV') . '/framework/sessions' : storage_path(env('APP_ENV') . '/framework/sessions');
// 一時保存用ディレクトリがなければ作成
if (!file_exists($file_path)) {
try {
if (!mkdir($file_path, 0775, true) && !is_dir($file_path) && !touch($file_path . '/.ignore', time())) {
throw new RuntimeException(sprintf('Directory "%s" was not created', $file_path));
}
} catch (Throwable $e) {
Log::info($e->getMessage());
}
}
return [
// 中略
'files' => $file_path, // 変更
config/cache.php
<?php
use Illuminate\Support\Str;
$file_path = !empty(env('STORAGE_PATH')) ? env('STORAGE_PATH') . env('APP_ENV') . '/framework/cache/data' : storage_path(env('APP_ENV') . '/framework/cache/data');
// 一時保存用ディレクトリがなければ作成
if (!file_exists($file_path)) {
try {
if (!mkdir($file_path, 0775, true) && !is_dir($file_path) && !touch($file_path . '/.ignore', time())) {
throw new RuntimeException(sprintf('Directory "%s" was not created', $file_path));
}
} catch (Throwable $e) {
Log::info($e->getMessage());
}
}
return [
// 中略
'stores' => [
'apc' => [
'driver' => 'apc',
],
'array' => [
'driver' => 'array',
'serialize' => false,
],
'database' => [
'driver' => 'database',
'table' => 'cache',
'connection' => null,
'lock_connection' => null,
],
'file' => [
'driver' => 'file',
'path' => $file_path, // 変更
],
CloudRunの設定
ボリューム設定で「Cloud Storageバケット」を指定し、ボリュームマウントしたいバケットを選択
あとは「コンテナ」⇒「ボリュームのマウント」からボリューム設定で追加したボリューム名を選択
マウント先となるパスを指定(特にこだわりなければ「mnt/gcs」が無難)
これだけ。
劇的Before After
切り替え後は当然ながらMemorystoreのコストは消え且つ、FUSEによるコストが増えたりすることもない状態。
そもそもFUSE自体は料金が発生せず、あくまでCloudStorageに関する料金しか発生しません。
やだ、めちゃくちゃお買い得。。。
注意点(宣言事項)
とはいえFUSEにも制限事項があり、以下のような用途には向かないです。
メタデータ
Cloud Storage FUSE は、mtime および symlink ターゲットを除き、Cloud Storage にファイルをアップロードするときにオブジェクト メタデータを転送しません。つまり、 Cloud Storage FUSE を使用してファイルをアップロードするときにオブジェクト メタデータを設定することはできません。オブジェクト メタデータを保持する必要がある場合は、 Google Cloud CLI、JSON API、または Google Cloud コンソールを使用してファイルをアップロードすることを検討してください 。
同時実行
Cloud Storage FUSE では、同じファイルへの複数の書き込みに対して同時実行制御は提供されません。複数の書き込みがファイルを置き換えようとすると、最後の書き込みが優先され、それ以前の書き込みはすべて失われます。後続の上書きについては、マージ、バージョン管理、ユーザーへの通知は行われません。
リンク
Cloud Storage FUSE はハードリンクをサポートしていません。
ファイルのロックとファイルのパッチ適用: Cloud Storage FUSE は、ファイルのロックやファイルのパッチ適用をサポートしていません。バージョン管理システムはファイルのロックとパッチ適用に依存しているため、バージョン管理システム リポジトリを Cloud Storage FUSE マウント ポイントに保存しないでください。また、Cloud Storage FUSE をファイルの代替として使用しないでください。
おわりに
ちょこちょこCloudRunでマイクロサービス作ってますがどんどん便利になってきてますね。
自分が使い始めのころはマルチステージビルドも対応してなかったのに(しみじみ
エンジニア募集
弊社では絶賛エンジニア募集中です!
気になった方、是非お気軽にWantedlyからご連絡ください!