MinIO `minio-py`:兼容 S3 的私有对象存储服务

好的,各位观众老爷,欢迎来到今天的MinIO专场!今天咱们要聊聊MinIO这个东西,它其实就是个“假装是S3”的对象存储服务。为啥说是“假装”呢?因为它不是真的亚马逊S3,但是API、功能跟S3那叫一个高度相似,简直就是孪生兄弟!更重要的是,它是开源的,你可以自己搭建,不用把数据都扔到亚马逊爸爸那里,想想就安全感爆棚!

今天咱们要用到的“玩具”是minio-py,这是MinIO官方提供的Python SDK,有了它,我们就能用Python代码跟MinIO愉快地玩耍了。

一、MinIO是个啥?为啥要用它?

先来简单科普一下,啥是对象存储?跟传统的文件存储有啥区别?

特性 传统文件存储 (例如:NAS) 对象存储 (例如:MinIO, S3)
存储方式 分层目录结构 扁平化键值对
扩展性 扩展性有限,受限于硬件 弹性扩展,无容量限制
元数据管理 有限的元数据 丰富的元数据
适用场景 小文件、结构化数据 大文件、非结构化数据

简单来说,对象存储更适合存储海量非结构化数据,比如图片、视频、日志等等。它最大的优点就是可扩展性强,想存多少就存多少,不用担心硬盘不够用。

那么,为啥要用MinIO呢?

  • 私有化部署: 数据掌握在自己手里,安全可控。
  • 兼容S3: 无缝迁移S3应用,降低学习成本。
  • 高性能: 采用Go语言开发,性能优秀。
  • 简单易用: 部署简单,API友好。
  • 开源免费: 免费使用,省钱!

总之,如果你需要一个可扩展、高性能、安全可控的对象存储服务,又不想被云厂商绑架,MinIO绝对是个不错的选择。

二、MinIO的安装与配置

首先,你得有个MinIO服务跑起来。这里假设你已经安装好了MinIO服务器。 可以通过 Docker 快速启动一个 MinIO 实例:

docker run -p 9000:9000 -p 9001:9001 
    --name minio1 
    -e "MINIO_ROOT_USER=your_access_key" 
    -e "MINIO_ROOT_PASSWORD=your_secret_key" 
    minio/minio server /data --console-address ":9001"
  • -p 9000:9000:将 MinIO 服务器的 9000 端口映射到主机的 9000 端口 (API)。
  • -p 9001:9001:将 MinIO 控制台的 9001 端口映射到主机的 9001 端口 (Web UI)。
  • --name minio1:给容器起个名字,方便管理。
  • -e "MINIO_ROOT_USER=your_access_key":设置 Access Key,请替换成你自己的值。
  • -e "MINIO_ROOT_PASSWORD=your_secret_key":设置 Secret Key,请替换成你自己的值。
  • minio/minio server /data:指定 MinIO 使用 /data 目录存储数据。
  • --console-address ":9001":指定控制台端口

启动后,可以通过浏览器访问 http://localhost:9001,使用你设置的 Access Key 和 Secret Key 登录 MinIO 控制台。

接下来,安装 minio-py

pip install minio

三、minio-py 的基本操作

终于可以开始写代码了!

  1. 连接 MinIO 服务器
from minio import Minio
from minio.error import S3Error

# MinIO 服务器的地址、Access Key 和 Secret Key
endpoint = "localhost:9000"
access_key = "your_access_key"  # 替换成你的 Access Key
secret_key = "your_secret_key"  # 替换成你的 Secret Key

# 创建 Minio 客户端
client = Minio(
    endpoint,
    access_key=access_key,
    secret_key=secret_key,
    secure=False  # 如果你的 MinIO 服务器没有启用 HTTPS,请设置为 False
)

print("MinIO客户端已连接!")
  1. 创建 Bucket

Bucket 相当于S3里的文件夹,用来存放对象。

bucket_name = "my-bucket"

try:
    # 检查 Bucket 是否存在
    found = client.bucket_exists(bucket_name)
    if not found:
        # 如果 Bucket 不存在,则创建
        client.make_bucket(bucket_name)
        print(f"Bucket '{bucket_name}' 创建成功!")
    else:
        print(f"Bucket '{bucket_name}' 已经存在!")
except S3Error as err:
    print(f"创建 Bucket 失败:{err}")
  1. 上传文件
import io

object_name = "my-object.txt"
file_path = "local_file.txt" # 本地文件路径

# 创建一个本地文件
with open(file_path, "w") as f:
    f.write("Hello, MinIO!")

try:
    # 上传文件
    client.fput_object(bucket_name, object_name, file_path)
    print(f"文件 '{file_path}' 上传到 Bucket '{bucket_name}',对象名为 '{object_name}'")

    # 上传一个内存中的字节流
    data = io.BytesIO(b"In memory data")
    client.put_object(bucket_name, "in_memory_object.txt", data, length=len(data.getvalue()))
    print("内存对象上传成功!")

except S3Error as err:
    print(f"上传文件失败:{err}")
  1. 下载文件
download_path = "downloaded_file.txt"

try:
    # 下载文件
    client.fget_object(bucket_name, object_name, download_path)
    print(f"对象 '{object_name}' 从 Bucket '{bucket_name}' 下载到 '{download_path}'")
except S3Error as err:
    print(f"下载文件失败:{err}")
  1. 列出 Bucket 中的对象
try:
    # 列出 Bucket 中的所有对象
    objects = client.list_objects(bucket_name)
    print(f"Bucket '{bucket_name}' 中的对象:")
    for obj in objects:
        print(f"- {obj.object_name}")
except S3Error as err:
    print(f"列出对象失败:{err}")
  1. 删除对象
try:
    # 删除对象
    client.remove_object(bucket_name, object_name)
    print(f"对象 '{object_name}' 从 Bucket '{bucket_name}' 中删除成功!")
except S3Error as err:
    print(f"删除对象失败:{err}")
  1. 删除 Bucket

注意:删除 Bucket 前必须先清空 Bucket 中的所有对象!

try:
    # 清空 Bucket 中的所有对象
    objects = client.list_objects(bucket_name)
    for obj in objects:
        client.remove_object(bucket_name, obj.object_name)

    # 删除 Bucket
    client.remove_bucket(bucket_name)
    print(f"Bucket '{bucket_name}' 删除成功!")
except S3Error as err:
    print(f"删除 Bucket 失败:{err}")

四、进阶操作:Presigned URL、元数据、多部分上传

  1. Presigned URL (预签名 URL)

Presigned URL 允许你生成一个带有有效期的 URL,用户可以通过这个 URL 直接访问 MinIO 中的对象,而无需提供 Access Key 和 Secret Key。这在某些场景下非常有用,比如分享文件给他人下载。

from datetime import timedelta

object_name = "my-object.txt"

try:
    # 生成一个用于下载对象的 Presigned URL,有效期为 7 天
    url = client.get_presigned_url(
        "GET",
        bucket_name,
        object_name,
        expires=timedelta(days=7)
    )
    print(f"用于下载对象的 Presigned URL:{url}")

    # 生成一个用于上传对象的 Presigned URL,有效期为 1 天
    url = client.get_presigned_url(
        "PUT",
        bucket_name,
        "new-object.txt",
        expires=timedelta(days=1)
    )
    print(f"用于上传对象的 Presigned URL: {url}")

except S3Error as err:
    print(f"生成 Presigned URL 失败:{err}")
  1. 元数据 (Metadata)

MinIO 允许你为每个对象添加元数据,这些元数据可以用来存储对象的描述、标签等信息。

object_name = "my-object.txt"
file_path = "local_file.txt"

try:
    # 上传文件并添加元数据
    metadata = {
        "Content-Type": "application/octet-stream",
        "X-Amz-Meta-My-Custom-Header": "my-custom-value"
    }
    client.fput_object(bucket_name, object_name, file_path, metadata=metadata)
    print(f"文件 '{file_path}' 上传到 Bucket '{bucket_name}',对象名为 '{object_name}',并添加了元数据")

    # 获取对象的元数据
    stat = client.stat_object(bucket_name, object_name)
    print(f"对象 '{object_name}' 的元数据:")
    print(f"- Content-Type: {stat.metadata['content-type']}")
    print(f"- X-Amz-Meta-My-Custom-Header: {stat.metadata['x-amz-meta-my-custom-header']}")

except S3Error as err:
    print(f"上传文件或获取元数据失败:{err}")
  1. 多部分上传 (Multipart Upload)

对于大文件,建议使用多部分上传,可以将文件分成多个部分并行上传,提高上传速度和可靠性。

import os

object_name = "large-file.zip"
file_path = "large_file.zip"

# 创建一个大的本地文件 (例如 100MB)
file_size = 100 * 1024 * 1024
with open(file_path, "wb") as f:
    f.seek(file_size - 1)
    f.write(b"")

try:
    # 使用多部分上传上传文件
    client.fput_object(bucket_name, object_name, file_path, part_size=10*1024*1024) # 设置每个部分的大小为 10MB
    print(f"大文件 '{file_path}' 通过多部分上传到 Bucket '{bucket_name}',对象名为 '{object_name}'")

except S3Error as err:
    print(f"多部分上传失败:{err}")
finally:
    os.remove(file_path) # 删除临时的大文件

五、错误处理

在使用 minio-py 时,可能会遇到各种错误,比如网络错误、权限错误、文件不存在等等。minio-py 使用 S3Error 异常来表示这些错误。

from minio.error import S3Error

try:
    # 可能会出错的代码
    client.get_object("non-existent-bucket", "non-existent-object.txt")
except S3Error as err:
    print(f"发生错误:{err}")
    print(f"- 错误代码:{err.code}")
    print(f"- 错误消息:{err.message}")
    print(f"- 资源:{err.resource}")
    print(f"- 请求 ID:{err.request_id}")

六、最佳实践

  • 使用 HTTPS: 强烈建议启用 HTTPS,确保数据传输安全。
  • 设置合理的 Access Key 和 Secret Key: 不要使用默认的 Access Key 和 Secret Key,并定期更换。
  • 使用 IAM 策略: 使用 IAM 策略控制用户的访问权限,实现最小权限原则。
  • 监控 MinIO 服务器: 监控 MinIO 服务器的性能和健康状况,及时发现和解决问题。
  • 合理设置 Bucket Policy: 设置 Bucket Policy 控制 Bucket 的访问权限。

七、总结

今天咱们一起学习了如何使用 minio-py 操作 MinIO 对象存储服务。 掌握了这些基本操作,你就可以用 Python 代码轻松地管理 MinIO 中的对象了。 希望今天的分享对你有所帮助!

最后,记住一句话:数据无价,安全第一! 使用 MinIO,让你的数据更安全、更可控!

感谢各位的观看,下课!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注