Cloud StorageのFake Serverをdocker-composeで実行する

Cloud Storage*1使っていますか?

私は最近、画像の保存場所によく使っています。

最近使ったものだと、大学のプロジェクトで作っているWebアプリのユーザアバターを保存する場所として使っています。

github.com

さて、このCloud Storageですがテストを書いたりデバッグをする中でローカルで実行させたいという話題がでます。

そのため、このブログではCloud Storageをdocker-composeで実行させる方法とかちょっと便利な使い方とかを紹介します。

fake-server

Cloud Storageは公式でローカルのDockerイメージは提供されていません。

そのため、fsouza/fake-gcs-serverを使用します。

github.com

version: '3'

services:
  gcs:
    image: fsouza/fake-gcs-server
    tty: true
    ports:
      - 4443:4443
    volumes:
      - ./.data:/data/[bucket name]
      - ./.storage:/storage
    command: -scheme http -public-host ${URL:-localhost}:4443

ここで、注意しておきたいのがvolumes/data/以下がbucket nameになる点です。ここで、bucket nameの空のディレクトリを作成しておかないとbucket nameを指定して接続した際にエラーが発生してしまいます。

また、fake-server実行時の-public-hostフラグはURLで画像にアクセスする際にはおそらく必須となります。

docker-composeの環境変数.envに書くかexportするかで定義することができます*2

さらに、fake-serverで保存されているファイルは.storageにマウントすることでテストなどでちゃんと設定できているかも確認できます。(閲覧する場合、sudo chmod -R 755 .storageで権限を変える必要があります。)

アプリケーションコード

これは、fake-serverが例を紹介しています。

github.com

おそらく、全てGoogle公式のGCSのパッケージを使用してアクセスできます。

Goとかはアクセスするのが一番簡単でSTORAGE_EMULATOR_HOST環境変数にfake-serverのホストを入れればそのままそこにアクセスしてもらえます。

// Set STORAGE_EMULATOR_HOST environment variable.
err := os.Setenv("STORAGE_EMULATOR_HOST", "localhost:4443")
if err != nil {
    // TODO: Handle error.
}

// Create client as usual.
client, err := storage.NewClient(ctx)
if err != nil {
    // TODO: Handle error.
}

// This request is now directed to http://localhost:4443/storage/v1/b
// instead of https://storage.googleapis.com/storage/v1/b
if err := client.Bucket("my-bucket").Create(ctx, projectID, nil); err != nil {
    // TODO: Handle error.
}

https://pkg.go.dev/cloud.google.com/go/storage#section-readme

Node.jsなんかは、そういった便利な環境変数は定義できないのでStorageオブジェクトのコンストラクタに引数で指定します。

// Creates a client
const storage = new Storage({
  apiEndpoint: "http://localhost:4443",
});

上記コードだとローカルしか実行できないので、以下のようにすると良さそうです。

let config = undefined;

if(process.env.NODE_ENV !== "production") {
  config = {
    apiEndpoint: "http://localhost:4443",
  };
}

const storage = new Storage(config);

公開する

GCP内の実行環境にデプロイすれば特に設定することもなく簡単にCloud Storageに接続できます。

// これで、何も設定しなくてもつながる(GCP内のサービスか、環境変数が設定されている場合)
const storage = new Storage();

また、別の環境でも同じことをしたい場合はGOOGLE_APPLICATION_CREDENTIALS環境変数にサービスアカウントキーの絶対パスを指定することでも可能*3です。

cloud.google.com

まとめ

GCSは便利なのでみんな使おう!!!