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

相关推荐
讯捷蓝达1 小时前
戴尔R720xd服务器卡死在 “Configuring Memory...Done“,换了内存还是卡?问题根本不在内存
运维·服务器
数字新视界3 小时前
动环监控信创适配在智能机房管理中的应用价值与未来展望
大数据·服务器·数据库·动环监控系统·动力与环境监控系统
爱和冰阔落3 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
lisanmengmeng4 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器
Android系统攻城狮5 小时前
Linux FFmpeg深度解析之av_write_frame调用流程与实战(三十三)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频
上火的金鱼妹5 小时前
k8s生产实际问题排查(网关,数据库读写等)
运维·服务器
爱莉希雅&&&19 小时前
GitLab 完整学习笔记
linux·运维·服务器
陈希12321 小时前
Linux 服务器性能排查手册(2026):CPU、内存、磁盘IO、网络四大瓶颈定位
linux·服务器·网络
测试界的小码农1 天前
【Linux 命令实战(03):文件创建、复制、移动与删除,掌握 touch、mkdir、cp、mv、rm】
linux·服务器·php
|_⊙1 天前
网络层协议 IP
服务器·网络·tcp/ip