MinIO のコンテナを立ててみました。
Go で PutObject や GetObject をしていきます。
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ありきなので、ローカル開発環境ではどうしようか悩むときがあります。
そういう課題感を汲み取っているんだろうな、と感じました。