在 Ubuntu 上安装 MinIO 并使用 Python 封装类操作对象存储

MinIO 是一个高性能、兼容 Amazon S3 API 的对象存储服务,非常适合小型私有云或者开发测试环境。本文将详细介绍在 Ubuntu 上安装 MinIO,并用 Python 封装类实现文件上传、下载、删除和批量操作。


一、MinIO 安装与配置

1. 下载 MinIO 二进制

复制代码
wget https://dl.min.io/server/minio/release/linux-amd64/minio -O /usr/local/bin/minio
sudo chmod +x /usr/local/bin/minio

确保 MinIO 可执行文件有执行权限。

2. 创建数据目录

复制代码
sudo mkdir -p /data/minio 
sudo chown -R $USER:$USER /data/minio

3. 以系统服务方式启动 MinIO(可选)

创建 systemd 服务文件 /etc/systemd/system/minio.service

复制代码
[Unit]
Description=MinIO Object Storage
After=network.target

[Service]
User=root
ExecStart=/usr/local/bin/minio server /data/minio --console-address ":9001"
Restart=always
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

启用并启动:

复制代码
sudo systemctl daemon-reload
sudo systemctl enable minio
sudo systemctl start minio
sudo systemctl status minio

注意:如果在 WSL 环境下,systemd 默认未启用,可直接用命令启动:

minio server /data/minio --console-address ":9001"

4. 测试 MinIO

访问浏览器:

  • Web 控制台 : http://127.0.0.1:9001

  • API 端口 : http://127.0.0.1:9000

默认用户名和密码可以在启动命令中通过环境变量指定:

复制代码
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=admin123456

二、Python 操作 MinIO 的封装类

为了方便操作 MinIO 对象存储,我们可以写一个 Python 封装类 MinioClient,支持:

  • 文件上传/下载

  • 字节数据上传/下载

  • 删除文件

  • 列举对象

  • 批量上传/下载文件夹

  • 生成临时 URL

1. 安装 Python SDK

复制代码
pip install minio

2. 封装类代码

python 复制代码
from minio import Minio
from minio.error import S3Error
from io import BytesIO
import os

class MinioClient:
    def __init__(self, endpoint, access_key, secret_key, bucket_name, secure=False):
        """
        初始化 MinIO 客户端,并固定 bucket
        """
        self.client = Minio(endpoint, access_key=access_key, secret_key=secret_key, secure=secure)
        self.bucket_name = bucket_name
        # 自动创建 bucket
        if not self.client.bucket_exists(bucket_name):
            self.client.make_bucket(bucket_name)

    def upload_file(self, object_name, file_path, content_type=None):
        try:
            self.client.fput_object(self.bucket_name, object_name, file_path, content_type=content_type)
        except S3Error as e:
            raise RuntimeError(f"上传文件 {file_path} 到 {self.bucket_name}/{object_name} 失败: {e}")

    def upload_bytes(self, object_name, data: bytes, content_type="application/octet-stream"):
        try:
            self.client.put_object(self.bucket_name, object_name, BytesIO(data), length=len(data), content_type=content_type)
        except S3Error as e:
            raise RuntimeError(f"上传字节数据到 {self.bucket_name}/{object_name} 失败: {e}")

    def download_file(self, object_name, file_path):
        try:
            self.client.fget_object(self.bucket_name, object_name, file_path)
        except S3Error as e:
            raise RuntimeError(f"下载 {self.bucket_name}/{object_name} 到 {file_path} 失败: {e}")

    def download_bytes(self, object_name) -> bytes:
        try:
            response = self.client.get_object(self.bucket_name, object_name)
            data = response.read()
            response.close()
            response.release_conn()
            return data
        except S3Error as e:
            raise RuntimeError(f"下载 {self.bucket_name}/{object_name} 失败: {e}")

    def delete_object(self, object_name):
        try:
            self.client.remove_object(self.bucket_name, object_name)
        except S3Error as e:
            raise RuntimeError(f"删除 {self.bucket_name}/{object_name} 失败: {e}")

    def list_objects(self, prefix="", recursive=True):
        try:
            return [obj.object_name for obj in self.client.list_objects(self.bucket_name, prefix=prefix, recursive=recursive)]
        except S3Error as e:
            raise RuntimeError(f"列举 {self.bucket_name} 下对象失败: {e}")

    def presigned_get_url(self, object_name, expires=3600):
        try:
            return self.client.presigned_get_object(self.bucket_name, object_name, expires=expires)
        except S3Error as e:
            raise RuntimeError(f"生成下载链接失败: {e}")

    def presigned_put_url(self, object_name, expires=3600):
        try:
            return self.client.presigned_put_object(self.bucket_name, object_name, expires=expires)
        except S3Error as e:
            raise RuntimeError(f"生成上传链接失败: {e}")

    # ================= 批量操作文件夹 =================
    def upload_folder(self, local_folder, remote_folder=""):
        """上传本地目录到 MinIO"""
        if not os.path.isdir(local_folder):
            raise ValueError(f"{local_folder} 不是目录")
        for root, _, files in os.walk(local_folder):
            for file in files:
                local_path = os.path.join(root, file)
                relative_path = os.path.relpath(local_path, local_folder)
                object_name = os.path.join(remote_folder, relative_path).replace("\\", "/")
                self.upload_file(object_name, local_path)

    def download_folder(self, remote_folder, local_folder):
        """下载 MinIO 前缀到本地目录"""
        objects = self.list_objects(prefix=remote_folder, recursive=True)
        for obj_name in objects:
            relative_path = os.path.relpath(obj_name, remote_folder).replace("\\", "/")
            local_path = os.path.join(local_folder, relative_path)
            os.makedirs(os.path.dirname(local_path), exist_ok=True)
            self.download_file(obj_name, local_path)

3. 使用示例

python 复制代码
client = MinioClient("127.0.0.1:9000", "admin", "admin123456", bucket_name="mybucket")

# 上传单文件
client.upload_file("test.txt", "/tmp/test.txt")

# 上传字节数据
client.upload_bytes("hello.txt", b"Hello MinIO!")

# 下载文件
client.download_file("test.txt", "/tmp/test_download.txt")

# 下载到内存
data = client.download_bytes("hello.txt")
print(data.decode())

# 删除文件
client.delete_object("hello.txt")

# 列举对象
print(client.list_objects())

# 批量上传目录
client.upload_folder("/tmp/local_folder", "remote_folder")

# 批量下载目录
client.download_folder("remote_folder", "/tmp/download_folder")

# 临时下载 URL
url = client.presigned_get_url("test.txt")
print("Download URL:", url)

三、总结

  1. MinIO 是轻量级、兼容 S3 的对象存储,安装简单,适合私有云和开发环境。

  2. Python 官方 SDK minio 可以方便地操作对象存储,结合封装类 MinioClient 可以像操作本地文件一样管理文件和目录。

  3. 封装类支持单文件和批量文件夹操作,同时支持生成临时 URL,适合各种开发场景。

相关推荐
wuk99816 分钟前
CentOS7环境搭建L2TP服务器
运维·服务器
恒创科技HK18 分钟前
香港1核2G云服务器当网站服务器够用不?
运维·服务器
学习3人组1 小时前
Node.js 网站服务器开发
运维·服务器·node.js
来知晓1 小时前
Linux:WSL内存空间管理之清完内存C盘可用空间不增问题解决
linux·运维·服务器
GTgiantech2 小时前
科普SFP 封装光模块教程
服务器·网络·数据库
深圳市恒讯科技2 小时前
如何在服务器上安装和配置数据库(如MySQL)?
服务器·数据库·mysql
wanhengidc3 小时前
云手机能够流畅运行大型游戏吗
运维·服务器·游戏·智能手机·云计算
繁华的地方不一定留下你的脚印3 小时前
ubuntu18.04版本配置静态IP并且可以上网(解决配置静态IP不能额上网的问题)
运维·服务器
0和1的舞者3 小时前
网络通信的奥秘:HTTP详解 (七)
服务器·网络·网络协议·http·okhttp·软件工程·1024程序员节
阿猿收手吧!5 小时前
windows本机vscode通过ssh免密登录远程linux服务器 && git push/pull 免密
服务器·windows·vscode