blog.cateiru.com

cateiru's blog

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フラグはhttpで使用する際には必須となります。これは、その画像にアクセスできるホストを定義するもので通常、デバッグ用途などで使用するならlocalhostで十分です。しかし、SSHで作業している場合など特殊な場合を想定してURL環境変数が定義されている場合はそちらを使用するようにします。

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

さらに、fake-serverで保存されているファイルは.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:9000")
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:9000/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:8080",
});

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

let config = undefined;

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

const storage = new Storage(config);

公開する

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

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

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

cloud.google.com

まとめ

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