在 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,适合各种开发场景。

相关推荐
毕竟是shy哥2 小时前
vs code连接远程服务器docker环境及配置免密登录
服务器·docker·vs code
徐小黑ACG3 小时前
nginx配置文件
linux·服务器·nginx
新时代牛马3 小时前
Linux VFS 完整篇:从path_openat、dentry/inode 到page cache 与挂载排障
linux·运维·服务器
新时代牛马5 小时前
Linux 驱动中断与定时完整篇:从 request_threaded_irq 到hrtimer 选型与排障
linux·运维·服务器
这个DBA有点耶8 小时前
同样48核配置TPS差1倍?高性价比数据库一体机的“软硬协同”才是分水岭
服务器·数据库·架构
码农小韩11 小时前
Linux应用开发(一)——Linux的标准IO
linux·运维·服务器
路弥行至11 小时前
Linux (ARM64 / Jetson) 挂载 exFAT 移动硬盘排障与离线安装指南
linux·运维·服务器·经验分享·笔记·jetson·exfat
云泽80812 小时前
Linux 系统编程实战:从零手写一个高性能终端进度条
linux·运维·服务器
半摆烂日常12 小时前
自建WMS和买成品:三年成本对比
大数据·服务器·数据库·python·深度学习·低代码·numpy
宋军涛13 小时前
Windows 操作系统【任务计划程序】简单使用
服务器·windows