minioがdockerイメージを配布しなくなったので新しいS3互換ストレージを探す
MinIO が Docker イメージ配布を停止して困った話
via https://gigazine.net/news/20251023-minio-stops-distributing-free-docker-images/
MinIO(みにお、みんあいおー)が公式の Docker イメージ配布を停止しました。
背景には収益化の難しさがあるとされており、商用サポートや有償契約への誘導を強める意図があったようです。
MinIO は非常に完成度の高い OSS ですが、このあおりを受けて、運用実験やローカルでS3互換ストレージを作るのが大変になったので代替となる S3 互換ストレージプロダクトを探すことにしました。
幸い、すでに詳細な調査をされている先駆者の方がいらっしゃいます。 考察が興味深いのでリンク先を読んでおくとよいです。
先駆者の方が紹介されていたS3互換ストレージのプロダクトは次の通り
私が紹介するのは
まず、MinIO のように Docker イメージで手軽にローカル展開できることを条件にします。
そう考えると
- Cephのように分散ストレージベースのもの
- Dockerイメージが提供されていないもの
これらを除外すると、候補は以下のようになります。
好きなのを選んでください。私はGarageかSeaweedFSにする予定です。
付録:compose.yaml
ひとまず、SeaweedFSを動かせるcompose.yaml付録として置いておきます。
マウント先は/mnt/hdd/seaweedfs/ です。先に作成しておいてください。
動作確認用コマンド
※EXTERNAL_IPはローカルで環境するなら127.0.0.1です
EXTERNAL_IP=YOUR-IP
docker-compose up -d
compose.yaml
services:
master:
image: chrislusf/seaweedfs
container_name: seaweed-master
network_mode: host
command: master -ip.bind=${EXTERNAL_IP} -port=9333 -port.grpc=19333 -mdir=/data/master
volumes:
- /mnt/hdd/seaweedfs/master:/data/master
restart: unless-stopped
volume:
image: chrislusf/seaweedfs
container_name: seaweed-volume
network_mode: host
depends_on:
- master
command: volume -mserver=${EXTERNAL_IP}:9333 -publicUrl=${EXTERNAL_IP}:8080 -port=8080 -dir=/data/volume -max=1
volumes:
- /mnt/hdd/seaweedfs/volume:/data/volume
restart: unless-stopped
filer:
image: chrislusf/seaweedfs
container_name: seaweed-filer
network_mode: host
depends_on:
- volume
command: filer -master=${EXTERNAL_IP}:9333 -ip.bind=${EXTERNAL_IP} -port=8888 -port.grpc=18888 -defaultStoreDir=/data/filer
volumes:
- /mnt/hdd/seaweedfs/filer:/data/filer
restart: unless-stopped
s3:
image: chrislusf/seaweedfs
container_name: seaweed-s3
network_mode: host
depends_on:
- filer
environment:
- AWS_ACCESS_KEY_ID=test
- AWS_SECRET_ACCESS_KEY=testtest
command: s3 -filer=${EXTERNAL_IP}:8888 -ip.bind=${EXTERNAL_IP} -port=8333
restart: unless-stopped
操作感も MinIO に近く、ローカル用途であれば十分実用的です。
残念な点としては、マウント先が NFS 上では動作しない点です。
起動確認できたら、実行確認用Python3スクリプト使ってみましょう。
touch upload.txt download.txt
python seaweedfs_s3_test.py
seaweedfs_s3_test.py
import boto3
from botocore.client import Config
# ===== 設定 =====
ENDPOINT_URL = "http://127.0.0.1:8333" # EXTERNAL_IP に置き換え
ACCESS_KEY = "test"
SECRET_KEY = "testtest"
REGION = "us-east-1"
BUCKET_NAME = "my-bucket"
UPLOAD_FILE = "upload.txt"
DOWNLOAD_FILE = "download.txt"
OBJECT_KEY = "sample/upload.txt"
# =================
# S3クライアント作成
s3 = boto3.client(
"s3",
endpoint_url=ENDPOINT_URL,
aws_access_key_id=ACCESS_KEY,
aws_secret_access_key=SECRET_KEY,
region_name=REGION,
config=Config(signature_version="s3v4"),
)
# バケット作成(存在しなければ)
def create_bucket():
try:
s3.create_bucket(Bucket=BUCKET_NAME)
print(f"Bucket created: {BUCKET_NAME}")
except s3.exceptions.BucketAlreadyOwnedByYou:
print(f"Bucket already exists: {BUCKET_NAME}")
# ファイルアップロード
def upload_file():
with open(UPLOAD_FILE, "w") as f:
f.write("Hello SeaweedFS S3!\n")
s3.upload_file(UPLOAD_FILE, BUCKET_NAME, OBJECT_KEY)
print(f"Uploaded: {OBJECT_KEY}")
# ファイルダウンロード
def download_file():
s3.download_file(BUCKET_NAME, OBJECT_KEY, DOWNLOAD_FILE)
print(f"Downloaded to: {DOWNLOAD_FILE}")
# オブジェクト一覧
def list_objects():
resp = s3.list_objects_v2(Bucket=BUCKET_NAME)
print("Objects:")
for obj in resp.get("Contents", []):
print(f" - {obj['Key']} ({obj['Size']} bytes)")
if __name__ == "__main__":
create_bucket()
upload_file()
list_objects()
download_file()
output
Bucket created: my-bucket
Uploaded: sample/upload.txt
Objects:
- sample/upload.txt (20 bytes)
Downloaded to: download.txt
使える様です。
上手く使えなかったらエラーメッセージをChatGPTにでも投げると解決策を提示してくれます。
MinIOの代替になれば幸いです。
Discussion