画像配信サーバーをCloud RunとCloud Storage FUSEで構築する

はじめに

今回は、画像配信サーバーをセルフホストしたいと思います。 単に、画像を配信するだけでなく、画像のリサイズや、画像の圧縮などを行いたいです。 また、この記事ではCDNをつかいませんが、CDNをつかうとオリジンへのアクセスは減るりますので、サーバーレスで構築したいと思います。 そこで、今回は、IPXとCloud RunとCloud Storage FUSEを使って、画像配信サーバーを構築していきます。

IPXとは

ipx

High performance, secure and easy to use image proxy based on Sharp and libvips.

IPXは、画像のリサイズや、画像の圧縮などを行うことができる画像プロキシです。 IPXは、Nuxt.jsのImageモジュールのデフォルトの画像プロキシとしても使われています。

Cloud Storage FUSEとは

Cloud Storage FUSE

Cloud Storage FUSE は、Cloud Storage バケットをローカル ファイル システムとしてマウントしてアクセスできるようにする FUSE アダプタです。これにより、アプリケーションは、標準のファイル システムのセマンティクスを使用して、バケット内のオブジェクトの読み取りと書き込みを行うことができます。Cloud Storage FUSE は、Google がサポートするオープンソース プロダクトです。

チュートリアル: Cloud Run での Cloud Storage FUSE の使用 を参照すると、Cloud Runの第2世代の実行環境では、Cloud Storage FUSEを利用することができます。

IPXのコード

コードは、下記のリポジトリに配置してあります。

https://github.com/cloudandbuild/blog-article-resources/tree/main/content/blog/article-20230916

IPXのコードは、下記のようになります。 簡単ですね。IPXをミドルウェアとしてHTTPサーバーを立てるだけです。

// index.mjs
import { createServer } from 'node:http';
import { createIPX, createIPXMiddleware } from 'ipx';
import { createApp, fromNodeMiddleware, toNodeListener } from 'h3';
const ipx = createIPX({});
const ipxMiddleware = createIPXMiddleware(ipx);
const app = createApp().use('/', fromNodeMiddleware(ipxMiddleware));
createServer(toNodeListener(app)).listen(process.env.PORT || 8080);

ローカルで起動する場合は、下記のように実行します。

npm i
npm start

適当な画像を配置して、アクセスできることを確認します。

mkdir static
curl -s -o static/cat.jpg 'http://placekitten.com/200/300'
# ブラウザで確認
# original
http://localhost:8080/_/static/cat.jpg
# rotate
http://localhost:8080/rotate_45/static/cat.jpg

参考

https://github.com/unjs/ipx/tree/v1#examples

インフラ構成

主に下記の記事を参考にさせていただきました。

https://cloud.google.com/run/docs/tutorials/network-filesystems-fuse?hl=ja#ship-code

Cloud Storage バケットを作成

gsutil mb -l <REGION> gs://BUCKET_NAME

バケットへのアクセス権をサービス アカウントに付与

gcloud iam service-accounts create fs-identity
gcloud projects add-iam-policy-binding <PROJECT_ID> \
     --member "serviceAccount:fs-identity@<PROJECT_ID>.iam.gserviceaccount.com" \
     --role "roles/storage.objectAdmin"

コンテナ イメージをビルドして Cloud Run にデプロイ

gcloud run deploy filesystem-app --source . \
    --execution-environment gen2 \
    --allow-unauthenticated \
    --service-account fs-identity \
    --update-env-vars BUCKET=<BUCKET_NAME>

動作確認

バケットに適当な画像を配置して、アクセスできることを確認します。

FUSEでマウントするディレクトリは、./gcsとしているので、下記のようにアクセスします。

https://<cloud run domain>/_/gcs/cat.jpg

まとめ

今回は、IPXとCloud RunとCloud Storage FUSEを使って、画像配信サーバーを構築してみました。簡単に構築できましたね。 サーバーレスなので、サーバーの管理も不要ですし、アクセスがなければコストも発生しません。(Cloud Storageの画像保存にかかるコストは発生しますが)

次回は、CDNを配置して配信を高速化してみたいと思います。