GCE内部に作られたmastodonの画像ファイルを外部(Google Croud Storage)に任せる方法。

#きっかけ#

やっぱり画像ファイルといえば**S3に退避する**がトレンドですよね。正直それやったらどれだけ得になるんだとかどれだけ速くなるんだとかよくわかってないんですが、Google Compute EngineでもAmazon S3に相当するパッケージ**Google Cloud Storage**があるそうなんです。Google Driveには私いろいろお世話になっていますが、こちらも相当なものだそうで、いろいろ変態的な使い方(~~性的~~静的なWebサイトを作って公開するとか)が検索すると見つかります。

今回はmastodon利用時の話で、そこまで変態的なものではなく、単にS3互換機能を使ってファイルを保存したい、というだけなのですが、正直Google謹製のドキュメントが微妙に読みにくい。互換機能があることはわかったんですがどれだけこういうところに応用が効くのかわからない、てな感じで訳もわからず3時間くらい(昼食休憩含む)悩んだ結果をまとめておきます。

#方法#

##Cloud Storageを準備する##

1. 例のメニューの「ストレージ」の中に、そのまんま「Storage」という項目がありますのでクリックします。
2. 「バケットを作成」をクリックします。
3. 「名前」を適切に決めます。あとで何回か使うことになるので256文字みたいな長いのにはしないほうがいいと思います。
4. デフォルトのストレージクラスは「Multi-Regional」か「Regional」を選びます。自分一人で使う場合、もしかしたら[「Nealine」ならもう少し安くなるかもしれません](https://cloud.google.com/storage/pricing?hl=ja)が、あなたが人気者で外部インスタンスに拡散したときとかそういう例があるかないか含め、ちょっと計算しづらいです。
5. ロケーションはVMインスタンスがあるところと同じところを選べばいいと思います。とはいえ、書き込みの時の上り料金は無料ですし、mastodonでCloud StorageからVMインスタンスにデータ転送することはほぼなさそうなので、どこにStorageを置いても料金はあまり変わらないような気もします。
6. 「作成」をクリックします。

##Cloud Storageの設定を変更する

1. バケット一覧に戻ってきたときに、各バケットの設定ボタンが右端にありますのでそれを選びます。
2. ポップアップメニューで「バケットの権限を編集」を選びます。
3. 「+項目を追加」します。
4. 「エンティティ」はユーザー、「名前」は「AllUsers」、権限は「書き込み」を設定します。
5. 「保存」をクリックします。
6. もう一度ポップアップメニューで「オブジェクトのデフォルトの権限」を選びます。
7. 「+項目を追加」します。
8. エンティティ、名前は先ほど同様、ユーザー、AllUsers、権限は「読み取り」を設定します。
9. 「保存」をクリックします。

これ、どっちか、もしくは両方共やる必要がないかもしれませんが、古いファイルを書き込んだ時にそれが見えなくて困ったのでやっておいたほうがよさそうですし、もしやらなくて、転送出来たのに表示できない、って時には、あらためてここを指定してからコピーすれば公開設定にしてくれるんで、ダメならここに戻ってまたやってみてください。

なお、ファイルが少ないときは、個別にファイルをブラウザで確認して「公開」を押せば解決しますが、フォルダ階層が深いので3つ以上のファイルがあるときはやめたほうがいいです。

##S3互換のアクセスキーと秘密を取得##

[Amazon S3からの単純な移行](https://cloud.google.com/storage/docs/migrating#migration-simple)に書いてあることを参考に、アクセスキーとそれに伴う秘密の鍵を手に入れます。これを.env.productionに書き込むわけです(後述)。

##mastodonの設定を変える##

[マストドンのバックエンドに Google Cloud Storage を使う方法](http://qiita.com/okumin/items/1b91286412f3912311dc#3-s3-%E3%82%92%E4%BD%BF%E3%81%86%E3%82%88%E3%81%86%E3%81%AB%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B)と同じです。というかどこのリージョン選ぶか以外さっきからそこのコピーを書いているような気がします。以下はそこからの再掲です。

```
S3_ENABLED=true
S3_BUCKET=[さっき設定したバケットの名前]
# 「単純な移行」で取得したアクセスキー
AWS_ACCESS_KEY_ID=GOOGXXXXXXXXXXXXXXXX
# 「単純な移行」で取得したシークレットキー
AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# 多分なんでもいいと思うが、自分は次のように設定している
S3_REGION=ASIA-NORTHEAST1
S3_PROTOCOL=https
S3_HOSTNAME=storage.googleapis.com
S3_ENDPOINT=https://storage.googleapis.com/
```

**S3_ENDPOINTが未設定**だと、画像アップロードしたときに500エラー吐きます。いちおうmastodonをdockerで起動している際は、

```
$sudo docker-compose logs web
```
でエラーログが見えますし、そこを記述していないと``s3-ほにゃらら-amazonaws.com 調べたけどみつかんねーよ``(実際は英語)というエラーが吐き出されているのがよくわかります。

大事なことなのでもう1回書きますね。**S3互換システムを使う際は、S3_ENDPOINTの設定は必須**です。

##mastodonを再起動する##

```
$sudo docker-compose down
$sudo docker-compose up -d
```
で、クライアントから画像アップできることを確認します。ただし、この時点ではこれまでに作られたアイコンとかその他画像投稿なんかはコピーされていないので見えないままです。

##ローカルのデータをCloud Storageにコピーする##

###コンテナからデータを取り出す###

mastodonの画像ファイルは、mastodon_web_1 コンテナの中に入っています。[こちらのエントリにある情報](https://hyper-text.org/archives/2017/04/mastodon-instance-with-amazon-s3.shtml
)をもとに、mastodon_web_1コンテナの中の/public/system/*内をまるっとコピーしてやります。

```
$sudo mkdir /tmp/mastodon_backup
$sudo docker cp mastodon_web_1:/mastodon/public/system /tmp/mastodon_backup
```
で/tmp/mastodon_backup/内にsystem/フォルダが作られ、その中身がディレクトリ構造ごとコピーされてきています。

###gsutilの認証を取る###

```
$gsuti config
```
を実行すると、何かURLが出てきます。これをコピーして適当なブラウザで開いてやると、認証を求められますので許可してやります。

###gsutilでバックアップファイルをコピーしてやる###

```
$cd /tmp/mastodon/backup/system
$gsutil cp -R ./* gs://(バケット名)
```
で全てコピー出来るはずです(ちょっと適当)。ワイルドカードが使えない場合はご面倒ですが、1つづつディレクトリ名を指定してください。多くて3つくらいしかないはずです(その下がたくさんある)。

この作業が間違いなく終われば、mastodonを再起動しなくても画像ファイルがすべて表示できるはずです。表示できない場合はディレクトリ構造がおかしいか、ファイルに全員への読み込み権限を与えていない可能性がありますので、ブラウザで確認してその辺なおしてください。

#まとめ#

- Cloud Storageのストレージクラス、どれを選ぶかは悩ましい
- S3でないシステムでS3互換機能を使う際は、**S3_ENDPOINTの指定は必須**
- gsutilでらくらくコピーできるけど、ツールを使う前にconfigで認証が必要