docker-composeで立ち上げているminioをvirtual-hosted styleで接続する
本番環境のファイルストレージにS3を利用しているプロジェクトで、ローカルでの開発環境としてS3互換のファイルストレージであるminioを利用しています。
今回の記事では、minioのデフォルトの設定を変更しvirtual-hosted styleで接続する方法を解説します。
背景
前提として、S3オブジェクトのリクエスト方法は path-style
と virtual-hosted
style の二つがあります。
path-style: https://s3.amazonaws.com/my-bucket/my-file.jpg
virtual-hosted style: https://my-bucket.s3.amazonaws.com/my-file.jpg
このうちpath-styleはdeprecatedであり、削除予定となっています。詳細についてはこちらをご覧ください。
そしてこのプロジェクトではpath-styleでリクエストを行なっていました。これはminioはデフォルトでpath-styleしか受け付けず、それに合わせてしまっていたためです。
func (s3 s3Service) Download(f storage.File) (*string, error) {
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
Config: aws.Config{
Endpoint: aws.String(s3.Endpoints),
S3ForcePathStyle: aws.Bool(true)}, // path-styleを利用する
}))
downloader := s3manager.NewDownloader(sess)
buffer := &aws.WriteAtBuffer{}
if _, err := downloader.Download(buffer, &s3.GetObjectInput{
Bucket: aws.String(s3.BucketName),
Key: aws.String(f.FileName()),
}); err != nil {
return nil, err
}
data := base64.StdEncoding.EncodeToString(buffer.Bytes())
return &data, nil
}
開発環境の問題解決のために本番環境のコードに影響があるのはよろしくないですし、何よりdeprecatedなリクエスト方法を利用しているのは望ましくありません。
そのためminioでもvirtual-hosted styleでのリクエストができるようにしたい、というのが今回のモチベーションです。
環境
ローカルでの環境はdocker-composeで立ち上げており、元々のdocker-compose.ymlはこんな感じです。
version: "3.7"
services:
api: # GoのAPIサーバー
build: .
command: ["air"]
working_dir: /app
volumes:
- .:/app
ports:
- 3000:3000
environment:
# 省略
s3:
image: minio/minio:latest
ports:
- 9000:9000
- 9001:9001
environment:
MINIO_ROOT_USER: 'minio'
MINIO_ROOT_PASSWORD: 'minio123'
volumes:
- ./s3/data:/data
entrypoint: sh
command: -c "/opt/bin/minio server /data --console-address ":9001";"
# 他にもDBコンテナなどもあるが省略
docker-composeでデフォルトで作られるnetworkでは、コンテナ間の通信をコンテナ名で名前解決します。そのためapiコンテナのAWS SDKからs3コンテナにアクセスするとなると、現状では http://s3:9000/my-bucket/my-file.jpg
のようにpath-styleでアクセスすることになります。
解決方法
- minioの設定でvirtual-hosted styleを受け付けられるようにします。
- docker-composeのapiコンテナからminioを
http://バケット名.s3
で名前解決できるようにします。
1. minioでvirtual-hosted styleを受け付ける設定をする
MINIO_DOMAIN
環境変数にドメイン名を指定することで、virtual-hosted styleのリクエストが有効化されます。
docker-compose.ymlに以下のように加筆します。
s3:
image: minio/minio:latest
ports:
- 9000:9000
- 9001:9001
environment:
MINIO_ROOT_USER: 'minio'
MINIO_ROOT_PASSWORD: 'minio123'
+ MINIO_DOMAIN: s3
volumes:
- ./s3/data:/data
entrypoint: sh
command: -c "/opt/bin/minio server /data --console-address ":9001";"
有効化することによって、今回の場合、HTTPリクエストのHostヘッダーが (.+).s3
と一致する場合はそのサブドメインの値がバケットとして解釈されるようになります。
バケット名.s3
で名前解決できるようにする
2. apiコンテナからminioを virtual-hosted styleでのリクエストはバケット名をサブドメインとしてリクエストすることになりますが、docker-composeのdefault networkではコンテナ名で名前解決するので、そのままではサブドメイン込みでの名前解決はできません。
そのため新しくdocker networkを作り、api, s3の二つのコンテナを参加させて解決します。
docker-composeに以下のように加筆します。
api: # GoのAPIサーバー
build: .
command: ["air"]
working_dir: /app
volumes:
- .:/app
ports:
- 3000:3000
environment:
# 省略
+ networks:
+ - s3_buckets
s3:
image: minio/minio:latest
ports:
- 9000:9000
- 9001:9001
environment:
MINIO_ROOT_USER: 'minio'
MINIO_ROOT_PASSWORD: 'minio123'
volumes:
- ./s3/data:/data
entrypoint: sh
command: -c "/opt/bin/minio server /data --console-address ":9001";"
+ networks:
+ s3_buckets:
+ aliases:
+ - my-bucket.s3
+networks:
+ s3_buckets:
aliasesを利用してサブドメインを受け付けられるようにします。
ワイルドカードは使えないようなので、利用したいバケットが複数存在する場合はそれぞれ記載するしかなさそうです。
とはいえ、これでapiコンテナのAWS SDKからvirtual-hosted styleでリクエストを送ることができるようになりました。
終わり
以上です。なんともニッチな内容ですが、日本語でも英語でも情報がなかったため記事に起こしてみました。
開発環境でのファイルアップロード機能の検証のためにminioを使うのはとてもいいですよ。
リクエストのモックや、開発環境だけtmpディレクトリに保存する条件分岐のような環境差異を減らせるのでオススメです。
Discussion