Raspberry PiにGoofys載せてSMB喋るオブジェクトストレージ直結NASにしてみた

# 内容
β版ながら、データアウト無料のCloudflare R2をRaspberry Piに中継させてNAS代わりにできんか？ という実験。
紆余曲折を経たが一応形になったものを紹介。
注意： 速度・安定性などに過度な期待を持ってはいけない。

# 環境
Rapsberry Pi 3 A+
Raspberry pi OS 64bit
AWS環境 （armアーキテクチャのEC2を利用）

# goofysのコンパイル

goofysはLinux用バイナリも提供されているのだが残念ながらx86用のみ。
RaspberryPiに使うためにarm用の実行ファイルをソースからbuildする必要がある。

このコンパイルはそれなりのCPUとメモリを要するためRaspberry Pi3では荷が重かった。そこで今回はAWSのARMアーキテクチャ EC2インスタンスを利用した。
（Raspberry Pi4であれば問題ないかもしれないが、残念ながら手元にない）

## AWSインスタンスの起動

本筋ではないので多くは触れない。
今回はDebian 10の64bit ARMアーキテクチャをOSとし、インスタンスタイプはa1.largeとした。ディスクは30GBのgp2タイプを選択。
DebianイメージにはSSM AgentがプリインストールされていないのでWebコンソールからは接続できず、直接SSHで接続する必要がある。Public Subnetに配置し、SSHポート（22番）に対して操作者のIPアドレスからのアクセスを許可したセキュリティグループを適用した。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554633/11a69baf-11fe-76f1-5e66-f6d6b38a1e27.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554633/c27e29c5-bdca-cd35-d694-027503a11634.png)

## Goの導入
goofysはGoで記述されているので、まずはコンパイルのためにGo環境を導入する。
公式ページより、導入可能なアーキテクチャのアーカイブを探す。

https://go.dev/dl/

今回は64bit ARMを利用するので、go1.18.2.linux-arm64.tar.gzのダウンロード用のURLをメモしておいた。
https://go.dev/dl/go1.18.2.linux-arm64.tar.gz

次に手順に従いインストールを実施。
先程メモしたURLからwgetしたアーカイブを/usr/localに展開する。

https://go.dev/doc/install

```
wget https://go.dev/dl/go1.18.2.linux-arm64.tar.gz
sudo tar -C /usr/local -xzf go1.18.2.linux-arm64.tar.gz
```

ファイルを展開したら、パスを通す。

```
export PATH=$PATH:/usr/local/go/bin
```

その後、'go version'コマンドに対してバージョン情報が返ってくればOK。

```
go version
go version go1.18.2 linux/arm
```

# goofysのコンパイル
今回最大の山場。
ネット上を見ても様々なエラーと対策法、そして試しては散っていった形跡が伺える。
今回はこれでうまくいったが、今後のバージョンでもそうとは言い切れないところ。

まずはaptでgitを導入しておく。
```
sudo apt install git
```

ここから先、公式の手順（※）通りインストールを進めるとうまくいかない。

https://github.com/kahing/goofys

※公式のインストール手順※
```
$ export GOPATH=$HOME/work
$ go get github.com/kahing/goofys
$ go install github.com/kahing/goofys
```

どうも新しいバージョンのGoでは「GOPATHとか環境に依存したような古臭いやり方はもうあかんやろ」となっている様子。普段Go使わないから何言ってるかわからないけど、心で理解。
幸い、過去との互換性をもたらす環境変数があるのでこいつを利用してやる。

環境変数GO111MODULEをoffに設定することで環境変数GOPATHが利用できるよう。
go getに「-d」オプションを加えることで、一旦データのダウンロードのみ行う。（関連するモジュールが多いためそれなりの時間がかかる）

```
export GO111MODULE=off

export GOPATH=$HOME/go
go get -d github.com/kahing/goofys
```

次にGO111MODULEをonにセットし直してからgoofysのソースコードのあるディレクトリに移動してgo installを行う。
成功すれば$GOPATH/bin/goofysが生成されているはず。
こいつを取り出してやればEC2は用済み。無駄な費用を払いたくないならちゃんと終了させておこう。

```
export GO111MODULE=on
cd $GOPATH/src/github.com/kahing/goofys
go install github.com/kahing/goofys
```

# Cloudflare R2
ここでやっとCloudflareの話に至る。
左側のカラムからR2（ベータ版）を選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554633/934bac32-7ed8-23d8-a7f2-c211d8fe4d3b.png)

画面右に表示れている「アカウントID」を控えておく。
これは後ほど、APIのエンドポイントの設定で必要になる。
控えたら、次はその上にある「R2 API トークンの管理」を選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554633/df8f9819-399a-84e5-30e8-72a10e664b33.png)

他と区別できるような適当なトークン名を記入、アクセス許可はEditを選択して「APIトークンを作成する」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554633/eb93900d-4ce2-f31b-0640-03123f04358d.png)

「トークンが正常に作成されました」が確認できたら、下記の２つの値を控えておく。
（重要。警告も表示されるが、これらは後で確認することはできない）

- アクセスキーID
- シークレットアクセスキー 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554633/9880592c-acc9-25a2-c06f-1de38484c3f9.png)

あとは、RaspberryPiからアクセスするためのバケットを作成しておこう。
名前を決めるだけで、設定項目は何もない。名前についてもAWS S3と違ってアカウント内でUniqueであれば良い。


# Raspberry Pi上の環境構築
あなたが無事にgoofysの実行バイナリを入手できたこと（そしてCloudflare R2のAPIトークンを取得できたこと）を祈ってやまない。
これらをRaspberryPiにコピーしてやろう。
goofysは実行ファイルなのでchmodでファイルモードを変更しておくことをお忘れなく。
変更したら早速実行してみて、操作説明が出るようであれば問題ない。

```
$ chmod 755 goofys
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554633/21d5addd-2338-0ef6-5f8d-e7632534c166.png)


問題なさそうであればファイルパスの通った/usr/local/binなどに移動しておこう。

```
sudo mv goofys /usr/local/bin/goofys
```

## R2のmount

次にCloudflareのAPIキーをRaspberry Pi上に保存する必要がある。AWS CLIが導入されていれば aws configureから設定してもよいのだが、今回は未導入のため直接記述する。
（下記の例はAWS CLI未導入が前提なので注意。.aws/credentialsがすでに存在するのであればvimなどで適当に追記してね）

```
mkdir ~/.aws
cat <<EOS > ~/.aws/credentials
[default]
aws_access_key_id     = <CloudflareのアクセスキーID>
aws_secret_access_key = <Cloudflareのシークレットアクセスキー>
EOS
```

まずはmount pointを作ってやり、そこにgoofysでマウントする。
ここでは「/mnt/storage」としたがもちろん何でも良い。

```
sudo mkdir /mnt/storage
sudo chmod 777 /mnt/storage

goofys --endpoint https://<CloudflareAccountId>.r2.cloudflarestorage.com/ <BucketName> /mnt/storage
```

エラーが表示されずにmountできれば良し。
上記の例であれば/mnt/storageに対して読み書きが出来ることを確認してみよう。
mountを解除する場合は以下のコマンドで。

```
fusermount -u /mnt/storage
```

## Rootでのmount

fuseはデフォルトではroot以外のallow_other（実行ユーザ以外へのマウントしたボリュームへのアクセス許可）を許していない。オプションで許すようにもできるのだが、今回は以後のこともあり素直にrootでのmountを目指す。

まずはユーザpiで作成した.aws/credentialsについてrootでも利用できるようリンクを張る。
これでrootでも同じcredentialsでアクセスできるはずだ。あとは他のユーザからアクセスできるよう、若干のオプションを増した状態でgoofysでマウントしてやればOK。

```
sudo ln -s /home/pi/.aws /root/.aws
sudo goofys -o allow_other --file-mode=0666 --dir-mode=0777 --endpoint https://<CloudflareAccountId>.r2.cloudflarestorage.com/ <BucketName> /mnt/storage
```

:::note info
本当はここでfstabに書いて起動時にマウントするようにすべき。
ちょっと力尽きた。誰か書いて。
:::


# Sambaの導入


```
sudo apt update
sudo apt install samba
```

ここから先はsamba導入したことがある人ならば容易い話だし、人によって設定の趣味嗜好も違うので一概に言えないところだと思いつつ、一例として。

まずは適当なユーザを作成してやる。

```
$ sudo adduser nasuser
Adding user `nasuser' ...
Adding new group `nasuser' (1001) ...
Adding new user `nasuser' (1001) with group `nasuser' ...
Creating home directory `/home/nasuser' ...
Copying files from `/etc/skel' ...
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for nasuser
Enter the new value, or press ENTER for the default
	Full Name []:
	Room Number []:
	Work Phone []:
	Home Phone []:
	Other []:
Is the information correct? [Y/n] y
```

「/etc/samba/smb/conf」をsudoで編集。
末尾に以下の設定を追記。
[]内が接続したユーザに見える名称になる。

```
[storage]
   comment = network storage space
   path = /mnt/storage
   force user = nasuser
   guest ok = no
   create mask = 0666
   directory mask = 0777
   read only = no
```

そして、先程作成したユーザをSMB用のユーザとして追加してやる。

```
$ sudo smbpasswd -a nasuser
New SMB password:
Retype new SMB password:
Added user nasuser.
```

準備ができたらsmbdを再起動して完了。
```
sudo systemctl restart smbd
```

これでWindowsからもNAS的にR2にアクセスできるようになったはず！
お疲れさまでした。