minio の詳しい説明は公式に頼りたいところですが、minio とは s3 と互換性のある object storage です(object storage とは)。
今回はこの『s3 と互換性のある』って部分を少し深ぼって、golang の sdk から s3 にアクセスする既存コードを使い、ローカルでは minio に切り替えてみます。
環境
minio: RELEASE.2023-06-02T23-17-26Z
go: 1.20
golang aws-sdk:
github.com/aws/aws-sdk-go-v2 v1.18.0
github.com/aws/aws-sdk-go-v2/config v1.18.25
github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1
minio
minio の使い方
今回は docker-compose を使って以下のように立ち上げます。
この状態で http://localhost:9001 にアクセスすると以下のようなログイン画面が現れ、ログインすると s3 のようにバケット操作やアクセスキーの発行ができます。

version: '3.9'
services:
minio:
image: quay.io/minio/minio:latest
environment:
MINIO_ROOT_USER: root_user
MINIO_ROOT_PASSWORD: root_password
command: server --console-address ":9090" /data
ports:
- 9001:9000
- 9091:9090
volumes:
- ./data:/data
compose で minio 起動時にデータを入れる
詳しくは説明しませんが、以下のように minio に用意されてる mc コマンドをつかってデータを投入・アクセスキーの払い出しをしました。
version: '3.9'
services:
minio:
image: quay.io/minio/minio:latest
environment:
MINIO_ROOT_USER: root_user
MINIO_ROOT_PASSWORD: root_password
# console から作成しなくて済むよう、環境変数に設定。
# 注): この方法は非推奨になった。
# see: https://min.io/docs/minio/linux/administration/identity-access-management/minio-user-management.html#minio-users-root:~:text=later%20deprecates%20the%20following%20variables%20used%20for%20setting%20or%20updating
# 今後は mc コマンドで作成することになる。
# MINIO_ACCESS_KEY: 3AFDH6SThcVDnI7FsACg
# MINIO_SECRET_KEY: thG04kib7mgHwjfstUCpqsb1RQyzZitmbulZKWpI
command: server --console-address ":9090" /data
ports:
- 9001:9000
- 9091:9090
volumes:
- ./data:/data
minio-mc:
image: minio/mc:latest
depends_on:
- minio
entrypoint: >
/bin/sh -c "
/usr/bin/mc ls myminio;
# ----- alias の作成 -----;
until /usr/bin/mc alias set myminio http://minio:9000 root_user root_password; do echo '...waiting...' && sleep 1; done;
# ----- access key の作成 (sdk で使用) -----;
/usr/bin/mc admin user svcacct add --access-key '3AFDH6SThcVDnI7FsACg' --secret-key 'thG04kib7mgHwjfstUCpqsb1RQyzZitmbulZKWpI' myminio root_user;
# ----- bucket の作成 ----;
/usr/bin/mc mb myminio/mybucket;
# ----- object の作成 ----;
/usr/bin/mc cp /testdata/test.txt myminio/mybucket/myobject;
/usr/bin/mc ls myminio;
exit 0;
"
volumes:
- ./testdata/:/testdata
golang sdk
今回は aws-sdk-go-v2 を使っていきます。
全体のコード
まず全体のコードを貼って、その後気になる点を説明します。
package main import ( "context" "io" "log" "os" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" ) const ( bucket = "minio-compatibility-test" object = "object-name" region = "ap-northeast-1" // minio も共通で使うためには、以下の値が必要(環境変数)。 // for s3 // see: https://docs.aws.amazon.com/ja_jp/general/latest/gr/s3.html#:~:text=%E3%82%A2%E3%82%B8%E3%82%A2%E3%83%91%E3%82%B7%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%20(%E6%9D%B1%E4%BA%AC)-,ap%2Dnortheast%2D1,-%E6%A8%99%E6%BA%96%E3%82%A8%E3%83%B3%E3%83%89%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88 // endpoint = "https://s3.ap-northeast-1.amazonaws.com" // for minio (local) endpoint = "http://localhost:9001" ) func s3andMinio() { // dc 内のの mc で設定した key, secret を環境変数に設定する。 // (sdk 内で勝手に使われる。) os.Setenv("AWS_ACCESS_KEY_ID", "3AFDH6SThcVDnI7FsACg") os.Setenv("AWS_SECRET_ACCESS_KEY", "thG04kib7mgHwjfstUCpqsb1RQyzZitmbulZKWpI") // ============================================= // =============== s3 のみとの差分 =============== // ============================================= resolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, opts ...interface{}) (aws.Endpoint, error) { return aws.Endpoint{ URL: endpoint, HostnameImmutable: true, SigningRegion: region, }, nil }) // ============================================ // ============================================ // ============================================ cfg, err := config.LoadDefaultConfig( context.TODO(), config.WithRegion(region), config.WithEndpointResolverWithOptions(resolver), ) if err != nil { log.Fatal(err) } // **aws の** s3 client を作成する。 client := s3.NewFromConfig(cfg) // ========= Get an object ========= obj, err := client.GetObject(context.TODO(), &s3.GetObjectInput{ Bucket: aws.String(bucket), Key: aws.String(object), }) if err != nil { log.Fatal(err) } writeFile(obj.Body) }
local 実行時のみ minio を向ける
クライアント用の config を作る時に、エンドポイントを指定するリゾルバを指定します。
s3 のエンドポイントとしては公式からリージョン毎のエンドポイントを、minio のエンドポイントとしては local に起動させたものに対してポート付きで指定します。
resolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, opts ...interface{}) (aws.Endpoint, error) { return aws.Endpoint{ URL: endpoint, HostnameImmutable: true, SigningRegion: region, }, nil }) cfg, err := config.LoadDefaultConfig( context.TODO(), config.WithRegion(region), config.WithEndpointResolverWithOptions(resolver), ) client := s3.NewFromConfig(cfg)