2026年8月14日金曜日

Oracle Backend for FirebaseのStorageの構成をDBFSからOCI Object Storageに切り替える

Oracle Backend for Firebase(Fusabase)ではStorageに保存するファイルの実際の保存先として、DBFS(Database File System - つまりOracle Database)またはOCI Object Storageを選択できます。デフォルトではDBFSが構成されます。

一般にファイルとして保存するデータは、PowerPointなどのファイルや画像、音声などサイズが大きいデータです。Oracle Backend for FirebaseのStorageの保存先がDBFSで構成されていると、これらのサイズの大きいデータがデータベースに保存されます。

Fusabase SDKによるStorageへのデータのアップロードでは、クライアント(Web、iOSアプリ、Androidアプリ)からORDSへデータが送信され、次にORDSからデータベースにデータが送信されます。ダウンロードの場合は、データベースからORDSにデータが送信され、次にORDSからクライアントにデータが送信されます。通常、クライアントとORDSの間のネットワークの速度はそれほど速くないため、そこで律速されます。

問題は、ダウンロードが完了するまではORDSとデータベースの間の接続が占有されることです。処理時間はクライアントとORDS間のネットワーク速度に依存します。データベースに負荷はほとんどかかりませんが、ファイルのアップロードまたはダウンロードが完了するまではORDSとデータベース間のセッションが使用中となるため、利用できる接続を確保するにはORDSのコネクション・プールが保持する接続の上限を増やす必要があります。また、データベースからデータを取り出し、クライアントに送信する(またはその逆)間に、転送するデータをORDSが保持するため、ORDSが扱えるメモリの上限も上げる必要があります。Oracle Backend for FirebaseのStorageをDBFSで構成するのはお手軽ですがスケールしないため、利用者が少ないなど負荷がかからない状況でなければ実運用は難しいのではないかと思います。

Oracle Backend for FirebaseではStorageの保存先としてOCI Object Storageを構成することができます。この場合、クライアントからのファイルのアップロードは、クライアント、ORDS、データベース、Object Storageという経路で、最終的にObject Storageにファイルが配置されます。ダウンロードについては、Object Storageから直接クライアントにダウンロードされ、ORDSおよびデータベースは経由しません。ファイルのアップロードよりもダウンロードの方が頻度は高く、その経路からORDSやデータベースが外れるため、ORDSが必要とするリソースも大幅に少なくなります。

本記事ではOracle Backend for FirebaseのStorageの構成を、OCI Object Storageに切り替える手順を紹介します。

検証した範囲では、StorageとしてOCI Object Storageを構成すると、Relational to collection mapping(実体はJSON Duality View)によって作成したコレクションにStorageを紐づけられませんでした。Storageを紐づけるコレクションは、通常のコレクションに限定されます。

構成方法は、以下の公式ドキュメントに記載されています。

Oracle Backend for Firebase 26.1
Developer's Guide
Part IV Storage
25 Storage Setup and Configuration

動作確認に使用するアプリケーションとして、以下のLiveLabsで作成したWebアプリケーションを使用します。

Build a Recipe Web App with Oracle Backend for Firebase
https://livelabs.oracle.com/ords/r/dbpm/livelabs/view-workshop?wid=4404

OCI Object Storageの構成を行う前に、デフォルトで構成されるDBFSについて確認します。


DBFSの構成



Oracle Backend for Firebaseのコンソールに接続し、StorageFile systemを開きます。


Storageの保存先(File system)のTypeDBFSRegiondbfsBucket namedbfs_<任意の文字列>として構成されています。

SQLclでプロジェクトのスキーマに接続し、以下のSELECT文を実行しDBFSに保存されているファイルを確認します。

select store, pathname from dbfs_content;

SQL> select store, pathname from dbfs_content;


STORE                   PATHNAME                                 

_______________________ ________________________________________ 

dbfs_FDNSTBCAVUSCPHZ    /dbfs_FDNSTBCAVUSCPHZ                    

dbfs_FDNSTBCAVUSCPHZ    /dbfs_FDNSTBCAVUSCPHZ/.sfs/tools         

dbfs_FDNSTBCAVUSCPHZ    /dbfs_FDNSTBCAVUSCPHZ/.sfs/snapshots     

dbfs_FDNSTBCAVUSCPHZ    /dbfs_FDNSTBCAVUSCPHZ/.sfs/content       

dbfs_FDNSTBCAVUSCPHZ    /dbfs_FDNSTBCAVUSCPHZ/.sfs/attributes    

dbfs_FDNSTBCAVUSCPHZ    /dbfs_FDNSTBCAVUSCPHZ/.sfs/RECYCLE       

dbfs_FDNSTBCAVUSCPHZ    /dbfs_FDNSTBCAVUSCPHZ/.sfs               


7行が選択されました。 


SQL> 


ビューDBFS_CONETNTのSTORE列の値が、Bucket nameとなっています。Storageにアップロードされたファイルは、このStoreに保存されます。

ファイルが参照される場合は、このStoreからファイルが取り出されます。

すでに作成済みのDBFSのFile systemも、ビューDBFS_CONTENTのSTORE列から確認できます。


OCI Object Storageの準備



OCIのオブジェクト・ストレージにバケットを作成します。Oracle Backend for Firebase向けの特別なバケットというものはありませんが、ポリシーとしてバケットへのファイルの読み書きと事前承認済リクエストの作成を許可する必要があります。

バケットの準備として、以下の作業を行います。
  1. コンパートメントFusabaseの作成
  2. バケットfusabase-storageの作成
  3. APIユーザーfusabase-storage-managerの作成
  4. グループFusabaseStorageManagersの作成
  5. ポリシーFusabaseStoragePolicyの作成
  6. APIユーザーfusabase-storage-userのAPIキーの作成

コンパートメントFusabaseの作成



Oracle Cloudのコンソールに接続し、アイデンティティとセキュリティコンパートメントを開きます。

コンパートメントの作成を実行します。


作成するコンパートメントの名前Fusabaseとします。親コンパートメントルートを選択し、コンパートメントを作成します。


コンパートメントFusabaseが作成されました。



バケットfusabase-storageの作成



作成したコンパートメントFusabaseに、オブジェクト・ストレージのバケットとしてfusabase-storageを作成します。

ストレージバケットを開き、コンパートメントFusabaseを選択します。

バケットの作成を実行します。


作成するバケット名fusabase-storageとします。それ以外はデフォルトのまま、バケットの作成を実行します。


バケットfusabase-storageが作成されました。



APIユーザーfusabase-storage-managerの作成



Object Storageの操作に使用するユーザーとしてfusabase-storage-managerを作成します。ユーザーはルート・コンパートメントに作成済みのDefaultドメインに作成します。

アイデンティティとセキュリティドメインを開き、ルート・コンパートメントを選択します。

作成済みのドメインDefaultを開きます。


ユーザー管理タブを開き、ユーザーの作成を実行します。


ユーザー名として電子メール・アドレスを使用チェックを外します。

Fusabaseユーザー名fusabase-storage-managerとします。電子メールを設定し、ユーザーを作成します。


ユーザーfusabase-storage-managerが作成されました。APIキーの生成は最後に実施します。



グループFusabaseStorageManagersの作成




ポリシーのサブジェクトとして使うグループとしてFusabaseStorageManagersを作成します。

Defaultドメインのユーザー管理より、グループの作成を実行します。


作成するグループの名前FusabaseStorageManagersとします。ユーザーとして先ほど作成したfusabase-storage-managerチェックし、グループに割り当てます。

以上で作成します。


グループFusabaseStorageManagersが作成されました。



ポリシーFusabaseStoragePolicyの作成




グループFusabaseStorageManagersに所属しているユーザーによる、コンパートメントFusabaseにあるバケットfusabase-storageへのオブジェクトの読み書き、および事前認証済リクエストの生成を許可するポリシーを設定します。

アイデンティティとセキュリティポリシーを開き、ルート・コンパートメントを選択します。

ポリシーの作成を実行します。


作成するポリシーの名前FusabaseStoragePolicyとします。コンパートメントルートを選択し、手動エディタに切り替えます。

ポリシーとして以下の3行を記述します。
Allow group FusabaseStorageManagers to read buckets in compartment Fusabase
Allow group FusabaseStorageManagers to manage objects in compartment Fusabase where target.bucket.name = 'fusabase-storage'
Allow group FusabaseStorageManagers to manage buckets in compartment Fusabase where all { request.permission = 'PAR_MANAGE', target.bucket.name = 'fusabase-storage' }
以上で作成します。


ポリシーFusabaseStoragePolicyが作成されました。



APIユーザーfusabase-storage-userのAPIキーの作成




作成済みのユーザーfusabase-storage-managerAPIキーを開きます。

APIキーの作成を実行します。


APIキー・ペアの生成を選択し、秘密キーのダウンロードを実行します。


秘密キーがファイルとしてダウンロードされると、APIキーの追加ができるようになります。

秘密キーのダウンロードだけではAPIキーとして登録されないため、必ず追加をクリックします。


構成ファイルとして、Oracle Backend for FirebaseのStorageをOCI Object Storageとして構成するために必要なパラメータの値が表示されます。

構成ファイルの内容をコピーし保管しておきます。

保管したのち、ドロワーを閉じます


以上でユーザーfusabase-storage-managerAPIキーが作成されました。


最後にプロファイルからテナンシ詳細を開き、オブジェクト・ストレージ・ネームスペースを確認します。


以上でOCI Object Storageへの切り替えに必要な情報がすべて揃いました。


OCI Object Storageへの切り替え



Oracle Backend for Firebaseのコンソールに接続し、StorageFile systemを開きます。

Manage configurationをクリックします。


Link to OCI Object Storageをクリックすると、切り替えに必要な設定値の入力フォームが表示されます。

OCI Object Storageの準備作業で集めた以下の情報を設定します。

Namespace、User OCID、Tenancy OCID、Fingerprint、Private key(ダウンロードしたファイルに記載)、Bucket name(これはfusabase-storage)、Region


Bucket nameとRegionの入力するために、フォームを下にスクロールさせます。

Private keyの入力フィールドに、Must start with "-----BEGIN PRIVATE KEY-----" and end with "-----END PRIVATE KEY-----"と表示されています。

秘密キーの入力は-----BEGIN PRIVATE KEY-----から始まり、-----END PRIVATE KEY-----で終わるように入力しますが、形式の認識に問題があり警告が表示されます。


最初の行に続く行を、以下のように連結します。
-----BEGIN PRIVATE KEY-----MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDnxhnPjsuFbOYU
また、-----END PRIVATE KEY-----の後に空行がないことも確認します。

Private keyの入力フィールドからフォーカスが移動すると、入力した秘密キーの検証が行われます。上記の対応をすると、警告が消えます。

以上の入力を行いSaveを実行します。


StorageのFile systemがOCI Object Storageに切り替わると、TypeOCIBucket namefusabase-storageRegionOCIのリージョンNamespaceにテナントのオブジェクト・ストレージ・ネームスペースが表示されます。




動作確認



Oracle Backend for FirebaseのLiveLabsで作成したWebアプリケーションを使用します。

Storageの構成が変わると、Webアプリケーションの構成ファイルの内容も変わります。

Project settingsのApplicationのSDK setup and configurationを確認します。

構成のJSONドキュメントの属性objs_typeocistorage_bucketがfusabase-storageに変更されています。


Webアプリケーションのfusabase-config.jsの内容を更新します。


以上で、WebアプリケーションもOCI Object Storageを使用するように切り替わりました。

Webアプリケーションから写真付きのレシピを作成してみます。

LiveLabsのLab 6: Photo Upload, Task 3: Upload a photo and verifyの操作です。


レシピが登録され、写真も表示されます。


画像がどこから取得されているか確認します。

パスタの画像の上でコンテキスト・メニューを開き、画像アドレスをコピーを実行します。


コピーしたアドレスを確認すると、以下のようにOCI Object Storageから直接画像をダウンロードしていることがわかります。このURLは、Object Storageにアップロードされたファイルlemon-herb-pasta.pngの事前承認済リクエストのURLです。

https://namespace.objectstorage.ca-toronto-1.oci.customer-oci.com/p/6lGeRgyKCYbAe5pXAnEQAUG3UjmnA40G2g0-z4QzxIhcUJopxg3pW06S8CCmxURJ/n/yz2dlxjrvfsc/b/fusabase-storage/o/recipes/58FEF49CF3EA7CCAE063020012ACA499/lemon-herb-pasta.png

バケットfusabase-storageの可視性はプライベートなので、少なくてもオブジェクトのリード権限を持つユーザーで認証していないとファイルは読めません。事前承認済リクエストを生成することにより、認証無しでファイルにアクセスできるようにしています。

写真ファイルのアップロードは、scripts/app.jsの以下のコードで行われています。
        const photoFile = fd.get("photo");
        if (photoFile && photoFile.size > 0) {
          // ── Lab 6 TODO: Upload the new recipe photo with the SDK ──
          // After adding this code, remove hidden from #modalPhotoField in index.html.
          
          storage = getStorage(app);
          const photoRef = ref(storage, `recipes/${recipeRef.id}/${photoFile.name}`);
          await uploadBytes(photoRef, photoFile, { contentType: photoFile.type || "image/png" });
          const photoURL = await getDownloadURL(photoRef);
          await updateDoc(doc(collection(db, "recipes"), recipeRef.id), { photoURL });
        }
        el.recipeForm.reset();
        closeModal();
        await refreshRecipes(recipeRef.id);
      });
uploadBytesで写真をStorageに保存(StorageがOCI Object Storageの場合、Object Storageへのアップロード)した後、getDownloadURLを呼び出してアップロードされたオブジェクトの事前承認済リクエストのURLを取得しています。

このURLは、コレクションrecipesのドキュメントにphotoURLとして保存されます。

Oracle Backend for FirebaseのコンソールのDatabaseより、該当のドキュメントのphotoURLを確認すると、アップロードされたオブジェクトの事前承認済リクエストのURLが保持されていることが確認できます。


事前承認済みリクエストには有効期限があります。

Oracle Cloudのコンソールよりバケットfusabase-storage管理を開きます。

管理のページには作成済みの事前承認済リクエストが一覧されます。この一覧に、先ほどアップロードした写真の事前承認済リクエストも含まれています。

写真の事前承認済リクエストの詳細を表示し、有効期限を確認します。


有効期限は、生成日から7日間のようです。


つまり、コレクションrecipesのドキュメントにphotoURLとして保存されているURLは、生成した7日後には無効(404 Not Foundが発生する)なURLになります。

事前承認済リクエストを自動で更新する機能があるとは思えないため、photoURLの生成日のタイプスタンプも保存し、画面に写真を表示するためにphotoURLが取り出される際には有効期限を超えてないかどうか確認し、超えていたらgetDownloadURLを発行してphotoURLを置き換えるといった処理をWebアプリケーションに組み込む必要があるかもしれません。アプリケーションに組み込むのが大変な場合は、バッチ処理で更新するなども対応も考えられます。

今回の記事は以上になります。