OCIFSユーティリティについてのちょっとした検証

本記事は[Oracle Cloud Infrastructure Advent Calendar 2023](https://qiita.com/advent-calendar/2023/oci)の16日目の記事です。

Advent Calendarのテーマとして他の皆様の記事に比べると、大変地味なんですが、毎日ホリデーのごちそうを食べてるとこにふとお茶漬けとほうれん草のおひたしを晩ご飯にしたら、これはこれでいいなと思った、みたいなところを狙っていきたいと思います･･･！

## はじめに
OCIFSユーティリティは、Oracle Linux8以降で利用可能なObject Storageをファイルシステムとして使うためのユーティリティです。
OS上にインストールして、Object Storageをローカルのファイルシステムとして使うことができ、OS上からObject Storageにデータを転送したり、Object Storage上のデータを読み込んだりするために利用することができます。

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131447/0d7e52bb-2e3e-5f18-a183-6a3cca7586bb.png)

OCI CLIでもOS上からのアップロードはできますが、ファイルシステムとして扱えることによるメリットも多いと考えています。

セットアップの仕方については@kenwatanさんの記事がわかりやすいです。
[[Oracle Cloud] OCIFS ユーティリティをつかってObject Storageのバケットをマウントしてみた。(2023/08/02)](https://qiita.com/kenwatan/items/e7ee8c50b4e70cf012a2)

上記記事にそってセットアップし、その挙動を見ていきたい、というのが本記事の趣旨です。
[ドキュメントはこちら](https://docs.oracle.com/ja-jp/iaas/oracle-linux/ocifs/index.htm)です。

### オブジェクトはどういう感じに見えるのか
osdirというディレクトリを作成して、ocifsコマンドでObject Storage(ocifs-bucket)をマウントします。dfコマンドで見てみると、Filesystem欄にバケットの名前が表示されます。
```
[opc@ocifs-poc ~]$ mkdir osdir
[opc@ocifs-poc ~]$ ocifs --auth=instance_principal ocifs-bucket osdir
[opc@ocifs-poc ~]$ df -h ~/osdir
Filesystem      Size  Used Avail Use% Mounted on
ocifs-bucket       0     0     0    - /home/opc/osdir
```
testfileというファイルを作成してみると、inode番号も特殊な感じです。
```
[opc@ocifs-poc ~]$ cd osdir
[opc@ocifs-poc osdir]$ echo test >> testfile
[opc@ocifs-poc osdir]$ ls -ail
total 4
    1 drwxr-xr-x. 2 opc opc   6 Dec 15 16:07 .
11926 drwx------. 6 opc opc 129 Dec 15 16:38 ..
    2 -rw-rw-r--. 1 opc opc  15 Dec 15 17:13 testfile
```
また、デフォルトでは~/.ocifs/以下にキャッシュが作成されます。＜バケット名＞/cache/＜ファイル名＞という形になるようです。
```
[opc@ocifs-poc osdir]$ ls -ail ~/.ocifs/ocifs-bucket/cache/testfile 
970497 -rw-rw-r--. 1 opc opc 15 Dec 15 17:13 /home/opc/.ocifs/ocifs-bucket/cache/testfile
```
そしてこのキャッシュ自体も開けます。このキャッシュが実体のようです。
```
[opc@ocifs-poc osdir]$ more ~/.ocifs/ocifs-bucket/cache/testfile
test
```

### キャッシュ容量を超えるサイズのファイルを書くとどうなるのか

先述の通り、OCIFSではローカルのディスク上にキャッシュを保持する形となっています。
ドキュメントによると、キャッシュできない場合、書き込み操作などが失敗する場合があるようです。
>OCIFSでデータをキャッシュできない場合、一部のOCIFS操作(書込み操作など)が失敗する可能性があります。

そして、デフォルトはキャッシュファイルシステムの空き容量が5％になるまで、キャッシュを作成できるようです。
>デフォルト設定はcache-fsfree=5%です。

cache-fsfreeオプションでcache-fsfree=100%、と指定するとキャッシュされなくなるため、その際に書き込みした際の動作を試してみたいと思います。

以下のコマンドでcache-fsfreeを指定してマウントします。
```
[opc@ocifs-poc ~]$ ocifs --auth=instance_principal --cache-fsfree=100% ocifs-bucket osdir
```

書き込みしてみると以下の通り、No space left on deviceでエラーになりました。「一部のOCIFS操作(書込み操作など)が失敗する可能性があります。」とありましたが、キャッシュができないと書込みは失敗する、と考えてよさそうです。
```
[opc@ocifs-poc ~]$ cd osdir
[opc@ocifs-poc osdir]$ echo cachetest >> cachetest
-bash: echo: write error: No space left on device
```

キャッシュできない状態で読み込みはできます。キャッシュなしだと、Read Onlyで使えるよ！という感じでしょうか。
```
[opc@ocifs-poc osdir]$ ls -ail
total 0
    1 drwxr-xr-x. 2 opc opc   6 Dec 16 13:58 .
11926 drwx------. 6 opc opc 150 Dec 16 13:42 ..
    2 -rw-rw-r--. 1 opc opc   0 Dec 16 13:58 cachetest
    3 -rw-r--r--. 1 opc opc  15 Dec 16 14:00 testfile
[opc@ocifs-poc osdir]$ more testfile
test
test
test
```

### 50GBを超えるサイズのファイルを書くとどうなるのか

ドキュメントには以下の記載があり、OCIFSでは扱えるサイズが50GBまでとなっています。
>OCIFS書込みは50 GBに制限されています。このため、サイズが50 GBより大きいファイルを作成または変更することはできません。

この制約を確認してみたいと思います。

まずddで52GB/49GiBのファイルを作成してみたところ、これは成功しました。50GBではなく、50GiBまでは行けそうです。
```
[opc@ocifs-poc osdir]$ dd if=/dev/zero of=50gbtest bs=1M count=50000
50000+0 records in
50000+0 records out
52428800000 bytes (52 GB, 49 GiB) copied, 1216.11 s, 43.1 MB/s
```
サイズを大きくして、100GBのファイルを作成してみたところ、File too large errorが出力され、50GiBまでしか書き込みができませんでした。明確な制限のようです。
```
[opc@ocifs-poc osdir]$ dd if=/dev/zero of=50gbtest3 bs=1M count=1000000
dd: error writing '50gbtest3': File too large
51201+0 records in
51200+0 records out
53687091200 bytes (54 GB, 50 GiB) copied, 1282.54 s, 41.9 MB/s
```

### Object Storageへの同期の仕方

Object Storageへの同期のされ方を確認してみたいと思います。

最初に作成した小さいファイルをOCI CLIで参照してみます。OS上のファイルおよびキャッシュのstatと見比べてみるとcreated/modifiedの時間がほぼ一致しています。
ファイルサイズが極めて小さいこともあり、ほぼラグ無く同期されているようです。
```
[opc@ocifs-poc osdir]$ oci os object list -bn ocifs-bucket
{
  "data": [
    {
      "archival-state": null,
      "etag": "be5f8893-3855-4956-8a25-134267c2629d",
      "md5": "2Oj8otwPiW/Xy0ywAxuiSQ==",
      "name": "testfile",
      "size": 5,
      "storage-tier": "Standard",
      "time-created": "2023-12-15T16:09:34.375000+00:00",
      "time-modified": "2023-12-15T16:09:59.161000+00:00"
    }
  ],
  "prefixes": []
}
[opc@ocifs-poc osdir]$ stat testfile
  File: testfile
  Size: 5         	Blocks: 8          IO Block: 4096   regular file
Device: 34h/52d	Inode: 2           Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/     opc)   Gid: ( 1000/     opc)
Context: system_u:object_r:fusefs_t:s0
Access: 2023-12-15 16:09:59.045718244 +0000
Modify: 2023-12-15 16:09:58.918715445 +0000
Change: 2023-12-15 16:09:58.918715445 +0000
 Birth: -
[opc@ocifs-poc osdir]$ stat ~/.ocifs/ocifs-bucket/cache/testfile 
  File: /home/opc/.ocifs/ocifs-bucket/cache/testfile
  Size: 5         	Blocks: 8          IO Block: 4096   regular file
Device: fc00h/64512d	Inode: 970497      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/     opc)   Gid: ( 1000/     opc)
Context: unconfined_u:object_r:user_home_t:s0
Access: 2023-12-15 16:09:59.045718244 +0000
Modify: 2023-12-15 16:09:58.918715445 +0000
Change: 2023-12-15 16:09:58.918715445 +0000
 Birth: 2023-12-15 16:09:34.293172649 +0000
```
では、先ほど作成した50GBのファイルではどうでしょうか。ddを実行したタイミング（14:09）にObject Storage上にファイルが作られ、14:18にstat上では更新が完了、Object Storageには14:29に同期されたようです。
動き的にはOS上に書き込み完了した後でObject Storageに同期されるようです。
```
[opc@ocifs-poc osdir]$  oci os object list -bn ocifs-bucket
{
  "data": [
    {
      "archival-state": null,
      "etag": "7b64c929-4628-4ae2-9ee9-4ec477354fe7",
      "md5": "dlVuNbJKYn5QcS+xXZZ2jg==",
      "name": "50gbtest",
      "size": 52428800000,
      "storage-tier": "Standard",
      "time-created": "2023-12-16T14:09:21.104000+00:00",
      "time-modified": "2023-12-16T14:29:37.205000+00:00"
    }
  ],
  "prefixes": []
}
[opc@ocifs-poc osdir]$ stat 50gbtest
  File: 50gbtest
  Size: 52428800000	Blocks: 102400000  IO Block: 4096   regular file
Device: 34h/52d	Inode: 2           Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/     opc)   Gid: ( 1000/     opc)
Context: system_u:object_r:fusefs_t:s0
Access: 2023-12-16 14:18:57.358009056 +0000
Modify: 2023-12-16 14:18:57.186005272 +0000
Change: 2023-12-16 14:18:57.186005272 +0000
 Birth: -
[opc@ocifs-poc osdir]$ 
```
### Object Storageから消すとどうなるのか

ドキュメントの上のほうに、青囲みで以下のような記載があります。
>また、Object Storageバケットがマウントされている間は、バケット・オブジェクト(コンソール、CLIまたはAPIなど)を直接変更しないでください。

やるな、と言われるとやりたくなるものなので、マウントした状態でoci cliでファイルを消してみたいと思います。以下のとおり、testfileがある状態で、これをcliから消してみます。
```
[opc@ocifs-poc osdir]$ ls -al
atotal 4
drwxr-xr-x. 2 opc opc   6 Dec 15 16:07 .
drwx------. 6 opc opc 129 Dec 15 16:38 ..
-rw-rw-r--. 1 opc opc  10 Dec 15 17:08 testfile
[opc@ocifs-poc osdir]$ oci os object delete -bn ocifs-bucket --name testfile
Are you sure you want to delete this resource? [y/N]: y
```
すると、OCIFSユーティリティ上も消えました。
```
[opc@ocifs-poc osdir]$ ls -al
total 0
drwxr-xr-x. 2 opc opc   6 Dec 15 16:07 .
drwx------. 6 opc opc 129 Dec 15 16:38 ..
```
すぐに反映された感じがするので、このあたりはほぼリアルタイムで同期されているように見えますが、排他制御等はできなさそうので、CLIとOCIFSユーティリティで同時に更新された場合等を想定して、ドキュメント上は「マウント中は別の経路で変更するな」と書いてあるのかなと思われます。


## まとめ

OCIFSユーティリティについての気になる点を検証してみました。いろいろと試してみたところ動きはとても素直に感じましたので、ファイルシステムとしてObject Storageを扱いたいケースで便利に使えるのではと思います。

よいホリデーシーズンをお過ごしください！