devlog

minio-go で PutObject してみた

2023-08-14

MinIO のコンテナを立ててみました。
Go で PutObjectGetObject をしていきます。

MinIO とは

S3互換のオブジェクトストレージです。 dockerイメージが用意されており、ローカルでコンテナを立てれば S3 の代わりとなります。

コンテナを立てる

docker でコンテナを立てます。イメージは minio/minio を用います

# docker-compose.yaml version: '3.8' services: minio: image: minio/minio ports: - 9000:9000 # Minio本体 - 9001:9001 # コンソール environment: - MINIO_ROOT_USER= - MINIO_ROOT_PASSWORD= - MINIO_ADDRESS=:9000 - MINIO_CONSOLE_ADDRESS=:9001 volumes: - ./minio:/data command: server /data tty: true

9000番ポートが MinIO 本体です。9001番ポートは管理画面です。

ちなみにこのイメージを普通にrunするとminioコマンドが立ち上がりました。

$ docker run -it --rm minio/minio --help NAME: minio - High Performance Object Storage DESCRIPTION: Build high performance data infrastructure for machine learning, analytics and application data workloads with MinIO USAGE: minio [FLAGS] COMMAND [ARGS...] # (略)

Go で PutObject する

ライブラリとして minio-go を用います

go get github.com/minio/minio-go/v7
import ( "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" )

 
Repositoryパターンで実装していきます。
DI (依存性の注入) が出来るよう interface を定義しました。UploadとDownloadを行えます

type StorageRepositoryInterface interface { Upload(key string, value string) error Download(key string) (string, error) }

扱いやすいようデータ (value) の型を string にしてますが、これではメモリを食います。 そのため実際はストリーム (io.Reader) の方が良いです
 
この interface を実装していきます..
まず struct です

type StorageRepository struct { Bucket string Endpoint string }

MinIO へアクセスするのに必要な情報を詰めました。
今回は public な Bucket を用いているため格納してませんが、通常は他にアクセスキーがいります。
 
続いて Upload です

func (repo *StorageRepository) client() (*minio.Client, error) { return minio.New(repo.Endpoint, &minio.Options{ Creds: credentials.NewEnvMinio(), }) } func (repo *StorageRepository) Upload(key string, value string) error { client, err := repo.client() if err != nil { return err } ctx := context.Background() reader := strings.NewReader(value) size := reader.Size() options := minio.PutObjectOptions{} // アップロード if _, err := client.PutObject(ctx, repo.Bucket, key, reader, size, options); err != nil { return err } return nil }

これを呼び出してみます

func main() { storage := repository.StorageRepository { Bucket: "bucket-name", Endpoint: "minio:9000", } if err := storage.Upload("key", "data"); err != nil { fmt.Println(err) } }

Go で GetObject する

続いて Download です

func (repo *StorageRepository) Download(key string) (string, error) { client, err := repo.client() if err != nil { return "", err } ctx := context.Background() options := minio.GetObjectOptions{} // ダウンロード obj, err := client.GetObject(ctx, repo.Bucket, key, options) if err != nil { return "", err } value, err := io.ReadAll(obj) if err != nil { return "", err } return string(value), nil }

呼び出してみます

func main() { storage := repository.StorageRepository { Bucket: "bucket-name", Endpoint: "minio:9000", } data, err := storage.Download("key") if err != nil { fmt.Println(err) } }

感想

MinIO ですが、dockerコンテナとして立てられるので便利でした。

オブジェクトストレージはインタフェースが扱いやすく、アプリケーションへ組み込みやすいと感じているのですが、 APIありきなので、ローカル開発環境ではどうしようか悩むときがあります。

そういう課題感を汲み取っているんだろうな、と感じました。

  • 作成日
    2023-08-14
  • 更新日
    2023-08-14