GCS FUSEを使いGCE内のディレクトリとGCSを同期させる ~GCE x Ubuntu~

## 環境

```
Ubuntu 18.04.5 LTS
apt 1.6.12ubuntu0.1 (amd64)
Google Cloud SDK 305.0.0
gcsfuse 0.30.0 (Go version go1.9.7)
```


## GCE 環境構築まで

https://qiita.com/komiya_____/private/71a315195da82b91620e

## Cloud API アクセススコープの変更

インスタンス内から gsutil コマンドをつかって GCS の操作を可能にするため

### インスタンスの停止

↑ の GCE 環境構築時に公開 VM Image を利用しているため gcloud コマンドはデフォルトで利用可能です。
※ ほとんどの公開 VM Image で Google Cloud SDK のコマンドラインツールがデフォルトでインストールされているようです。
※ ローカル SSD が接続されたインスタンスは停止ができません。

```sh
gcloud compute instances stop webserver
```

#### 永続ディスクとローカル SSD の違い

- 永続ディスク

  - SSD, HDD から選べる
  - 外部ストレージを利用しているためローカル SSD に比べパフォーマンスが悪い
  - インスタンスを削除しても保存しておくことが可能

- ローカル SSD
  - SCSI と NVMe の 2 種類の接続方式がある
  - VM のローカルに存在するため永続ディスクに比べパフォーマンスが良い
  - インスタンスを削除すると一緒に削除される
  - 375GB 単位でのみ追加可能

### インスタンスのサービスアカウントのアクセススコープを変更

#### サービスアカウントの確認

```sh
$ gcloud compute instances describe インスタンス名

・
・
serviceAccounts:
- email: 107075897042-compute@developer.gserviceaccount.com
  scopes:
  - https://www.googleapis.com/auth/devstorage.read_only
  - https://www.googleapis.com/auth/logging.write
  - https://www.googleapis.com/auth/monitoring.write
  - https://www.googleapis.com/auth/pubsub
  - https://www.googleapis.com/auth/service.management.readonly
  - https://www.googleapis.com/auth/servicecontrol
  - https://www.googleapis.com/auth/trace.append
・
・
```

#### サービスアカウントの API アクセススコープを変更

```sh
$ gcloud compute instances set-service-account webserver \
--scopes default,storage-full \
--service-account 107075897042-compute@developer.gserviceaccount.com
```

--scopes に指定するのは、URI かそのエイリアスのどちらでも OK。
カンマ区切りで複数指定可能。

Alias URI
storage-full https://www.googleapis.com/auth/devstorage.full_control
storage-ro https://www.googleapis.com/auth/devstorage.read_only
storage-rw https://www.googleapis.com/auth/devstorage.read_write

##### Alias と URI 一覧

https://cloud.google.com/sdk/gcloud/reference/compute/instances/create?hl=ja#--scopes

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

```sh
$ gcloud compute instances start webserver
```

### インスタンスの外部 IP を確認

IP を固定していない場合、変わっているかとおもいます。

```sh
$ gcloud compute instances describe webserver | grep natIP

  natIP: 192.0.2.1
```

### ~/.ssh/config の修正

HostName を変更後の外部 IP に修正

```
Host webserver
  User anata_no_username
  HostName 192.0.2.1 <-　ここを変更後の外部IPに
  Port 55555
  IdentityFile ~/.ssh/id_rsa
```

## gcsfuse のインストール

こちらの手順ですすめます。
https://github.com/GoogleCloudPlatform/gcsfuse/blob/master/docs/installing.md

### apt パッケージ追加と公開鍵のインポート

gcsfuse 配布 URL をパッケージソースとして追加し、その公開鍵をインポートします。

```sh
export GCSFUSE_REPO=gcsfuse-`lsb_release -c -s`
echo "deb http://packages.cｌoud.google.com/apt $GCSFUSE_REPO main" | sudo tee /etc/apt/sources.list.d/gcsfuse.list
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
```

### おまけ

#### ↑ のコマンドなにしてるの？

##### lsb_release コマンドで Linux ディストリビューション(ここでは Ubuntu)のコードネームを取得

```sh
lsb_release -c -s

bionic
```

- -c, --codename

  - コードネームを表示

- -s, --short

  - 短い形式で表示する。 `Codename: bionic` -> `bionic`

##### GCSFUSE_REPO 変数に格納

```sh
export GCSFUSE_REPO=gcsfuse-`lsb_release -c -s`
```

中身はこれ

```sh
echo $GCSFUSE_REPO

gcsfuse-bionic
```

↑ の出力結果と組み合わせた文字列を /etc/apt/sources.list.d/gcsfuse.list に書き込む。
sources.list.d ディレクトリのは以下のファイルは apt-get update 時に apt のパッケージリポジトリとして読み込まれます。

```sh
$ echo "deb http://packages.cｌoud.google.com/apt $GCSFUSE_REPO main" | sudo tee /etc/apt/sources.list.d/gcsfuse.list
```

この文字列を

```sh
$ echo "deb http://packages.cloud.google.com/apt $GCSFUSE_REPO main"

deb http://packages.cloud.google.com/apt gcsfuse-bionic main
```

このリストに書き込む

```sh
| sudo tee /etc/apt/sources.list.d/gcsfuse.list
```

```sh
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
```

## パッケージリストを更新 -> gcsfuse をインストール。

```sh
sudo apt-get update
sudo apt-get install gcsfuse
```

## アプリケーションの認証

アプリケーションが API にアクセスするための認証。

```sh
gcloud auth application-default login
```
確認

```sh
gcloud auth application-default print-access-token
```
Tokenが出力されればOKです。

### マウントするディレクトリを作成

```sh
$ mkdir ./test
```

### GSC バケットを作成

```sh
$ BUCKETNAME='your-bucket-name'
$ gsutil mb gs://$BUCKETNAME
```

### 対象ディレクトリを GSC バケットにマウント

```sh
$ gcsfuse $BUCKETNAME ./test
```

### 確認

ファイルを作成

```sh
$ touch ./test/test.py
```

バケットの中身を確認

```sh
$ gsutil ls gs://$BUCKETNAME

gs://your-bucket-name/test.py
```

同じファイルが入っていれば OK です。


#### 中身がある場合はどうなる？

ローカルディレクトリの中身がGCSバケットと同じ状態になります。
ローカルディレクトリにファイルなどが入っていた場合、削除されてしまったように見えますが隠れているだけです。
下記手順でマウントを解除することで元の状態にもどります。


### マウントを解除

アンマウントする場合も`gs://`は不要。

```sh
$ umount $BUCKETNAME
```

#### マウントしたディレクトリを削除

マウントした状態のディレクトリは削除できないので、アンマウントしてから削除するようにします。
マウント中に削除しようとすると、このようなエラーが出ます。

```sh
rm -rfi ./test

rm: test/: Resource busy
```

## ローカルマシン（Mac）でやってみる

こちらもよろしければ

[GCS FUSEを使いローカルディレクトリとGCSを同期させる ~Mac~](https://qiita.com/komiya_____/items/8ef027c40772362ca589)

## おしまい

最後まで読んでいただきありがとうございました。