1. MinIO 基础概念和存储模型
思维导图
什么是对象存储?
MinIO 是一个对象存储系统,这与传统的文件系统有根本区别:
传统文件系统 vs 对象存储
bash
传统文件系统:
/home/user/documents/report.pdf
/var/log/system.log
├── 分层目录结构
├── 文件路径概念
└── 文件属性(权限、所有者等)
对象存储:
bucket-name/report.pdf
bucket-name/logs/system.log
├── 扁平化结构
├── 对象键值(Key-Value)
└── 对象元数据
MinIO 的三层架构
css
┌─────────────────────────────────────────────┐
│ 应用层 │
│ Web界面、API接口、SDK客户端 │
├─────────────────────────────────────────────┤
│ 服务层 │
│ S3兼容API、身份验证、权限管理 │
├─────────────────────────────────────────────┤
│ 存储层 │
│ 纠删码(Erasure Code)、数据分片、冗余备份 │
└─────────────────────────────────────────────┘
2. 核心概念详解
Bucket(存储桶)
python
# 存储桶就像是一个大的容器或文件夹
bucket_name = "demo-bucket"
# 类比理解:
# 如果MinIO是一个图书馆
# Bucket就是不同的书架区域,比如:
# - "技术书籍" 存储桶
# - "小说文学" 存储桶
# - "历史资料" 存储桶
Bucket 的特点:
- 全局唯一命名(在同一MinIO实例中)
- 扁平化存储结构
- 可以设置访问策略和权限
- 支持版本控制和生命周期管理
Object(对象)
python
# 对象是实际存储的文件
object_name = "reports/2024/annual-report.pdf"
# 对象的组成:
# 1. 对象键(Key):reports/2024/annual-report.pdf
# 2. 对象数据:PDF文件的二进制内容
# 3. 元数据:文件类型、大小、创建时间等
对象键的层次结构
虽然MinIO是扁平存储,但支持"文件夹"概念:
python
# 这些都是对象键,看起来像文件路径
"images/photos/vacation.jpg"
"documents/contracts/2024/contract1.pdf"
"logs/application/2024-01-15.log"
# 实际上MinIO内部是这样存储的:
{
"images/photos/vacation.jpg": <二进制数据>,
"documents/contracts/2024/contract1.pdf": <二进制数据>,
"logs/application/2024-01-15.log": <二进制数据>
}
3. MinIO 底层技术原理
纠删码(Erasure Code)技术
ini
原始文件: [A][B][C][D] (4个数据块)
纠删码处理后:
数据块: [A][B][C][D]
校验块: [P1][P2] (根据数据块计算得出)
分布式存储:
服务器1: [A][P1]
服务器2: [B][P2]
服务器3: [C][损坏]
服务器4: [D][正常]
恢复过程:
即使服务器3的数据块C损坏,也能通过其他块重建
纠删码的优势:
- 存储效率高(相比完整副本)
- 容错能力强
- 数据一致性保证
分片存储机制
css
大文件处理流程:
100MB文件 → 分片 → [5MB][5MB][5MB]...[5MB] → 分布存储
每个分片独立处理:
分片1 → 纠删码 → 存储到多个节点
分片2 → 纠删码 → 存储到多个节点
...
4. MinIO vs 传统存储对比
性能对比
bash
传统文件系统:
读取 /path/to/file.txt
├── 目录遍历开销
├── 文件系统锁
└── 单点访问限制
MinIO对象存储:
读取 bucket/file.txt
├── 直接键值访问
├── 无锁并发读取
└── 分布式负载均衡
扩展性对比
传统存储:
单服务器 → 存储空间受限 → 需要更换硬件
MinIO集群:
节点1 + 节点2 + 节点3 + ... + 节点N
└── 水平扩展,理论上无限制
5. 实际应用场景代码示例
场景1:网站静态资源存储
python
# 上传网站图片
minio_manager.upload_file("logo.png", "assets/images/logo.png", "image/png")
# 生成公开访问链接
public_url = minio_manager.generate_presigned_url("assets/images/logo.png",
expires=timedelta(days=7))
# 在网页中使用:<img src="{public_url}" alt="Logo">
场景2:数据备份
python
# 备份数据库导出文件
backup_file = "database_backup_20240115.sql"
minio_manager.upload_file(backup_file, f"backups/2024/01/{backup_file}")
# 设置长期存储链接
archive_url = minio_manager.generate_presigned_url(
f"backups/2024/01/{backup_file}",
expires=timedelta(days=365)
)
场景3:文件分享系统
python
# 用户上传文件
user_file = "user_document.pdf"
object_key = f"users/{user_id}/documents/{user_file}"
minio_manager.upload_file(user_file, object_key)
# 生成临时分享链接(24小时有效)
share_link = minio_manager.generate_presigned_url(object_key,
expires=timedelta(hours=24))
6. 错误处理和最佳实践
常见错误类型
python
try:
minio_manager.upload_file("large_file.zip")
except S3Error as e:
if e.code == 'NoSuchBucket':
print("存储桶不存在")
elif e.code == 'AccessDenied':
print("权限不足")
elif e.code == 'EntityTooLarge':
print("文件过大")
else:
print(f"其他错误: {e}")
性能优化技巧
python
# 1. 并发上传多个文件
import concurrent.futures
def upload_files_parallel(files):
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
futures = []
for file_path in files:
future = executor.submit(minio_manager.upload_file, file_path)
futures.append(future)
for future in concurrent.futures.as_completed(futures):
result = future.result()
print(f"上传完成: {result}")
# 2. 使用流式上传减少内存占用
def upload_large_file_stream(file_path, object_name):
with open(file_path, 'rb') as file_data:
file_size = os.path.getsize(file_path)
minio_manager.client.put_object(
minio_manager.bucket_name,
object_name,
file_data,
file_size
)
7. 完整代码及其详解
7.1 完整代码
python
# -*- coding: utf-8 -*-
import os
import json
import tempfile
from datetime import timedelta
from minio import Minio
from minio.error import S3Error
from minio.commonconfig import Filter, CopySource
from minio.lifecycleconfig import LifecycleConfig, Rule, Expiration
import urllib3
# 禁用 SSL 警告(仅用于开发环境)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
"""
MinIO Python 客户端使用示例
"""
class MinIOManager:
def __init__(self, endpoint, access_key, secret_key, secure=False):
"""
初始化 MinIO 客户端
Args: endpoint: MinIO 服务端点,如 'localhost:9000' access_key: 访问密钥
secret_key: 密钥
secure: 是否使用 HTTPS """ self.endpoint = endpoint
self.client = Minio(
endpoint,
access_key=access_key,
secret_key=secret_key,
secure=secure
)
# 共享库
self.bucket_name = "code-data"
# 临时库
self.tmp_bucket = "temp-data"
self._init_bucket_conf()
def _init_bucket_conf(self):
# create need bucket
self.ensure_bucket_exists(self.bucket_name)
self.ensure_bucket_exists(self.tmp_bucket)
# 设置存储桶的访问策略
anonymous_read_policy = {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": ["*"]
},
"Action": ["s3:GetObject"],
"Resource": [f"arn:aws:s3:::{self.bucket_name}/**"]
}]
}
tmp_policy = {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": ["*"]
},
"Action": ["s3:GetObject"],
"Resource": [f"arn:aws:s3:::{self.tmp_bucket}/**"],
"Condition": {
"IpAddress": {
# 仅限制从 192.168.1.0/24 子网访问
"aws:SourceIp": "192.168.1.0/24"
}
}
}]
}
try:
policy = self.client.get_bucket_policy(self.bucket_name)
except Exception as e:
if str(e).find('NoSuchBucketPolicy') == -1:
raise e
self.client.set_bucket_policy(self.bucket_name, json.dumps(anonymous_read_policy))
try:
policy = self.client.get_bucket_policy(self.tmp_bucket)
except Exception as e:
if str(e).find('NoSuchBucketPolicy') == -1:
raise e
self.client.set_bucket_policy(self.tmp_bucket, json.dumps(tmp_policy))
# 设置临时存储桶的生命周期
if not self.client.get_bucket_lifecycle(self.tmp_bucket):
lifecycle_conf = LifecycleConfig([
Rule(
'Enabled', # 表示启用
# 设置规则的过滤器,表示该规则只适用于对象名以 'temp-data/' 开头的对象。
rule_filter=Filter(prefix='temp-data/'),
# 设置规则的 ID,这里为 'rule1'。
rule_id='rule1',
# 设置对象的过期时间为 1 天。
expiration=Expiration(days=1),
),
], )
self.client.set_bucket_lifecycle(self.tmp_bucket, lifecycle_conf)
def ensure_bucket_exists(self, bucket_name):
"""确保存储桶存在,如果不存在则创建"""
try:
if not self.client.bucket_exists(bucket_name):
self.client.make_bucket(bucket_name)
print(f"✅ 创建存储桶: {bucket_name}")
else:
print(f"✅ 存储桶已存在: {bucket_name}")
except S3Error as e:
print(f"❌ 创建存储桶失败: {e}")
raise
def create_sample_files(self):
"""创建示例文件用于演示"""
files = {}
# 2. 创建JSON文件
json_data = {
"name": "MinIO 演示数据",
"version": "1.0",
"features": ["对象存储", "S3兼容", "高性能", "云原生"],
"config": {
"max_file_size": "5TB",
"encryption": True,
"compression": "enabled"
}
}
json_file = tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False, encoding='utf-8')
json.dump(json_data, json_file, ensure_ascii=False, indent=2)
json_file.close()
files['config00000002.json'] = json_file.name
return files
def upload_file(self, local_file_path, object_name=None, content_type=None):
"""
上传文件到 MinIO
Args: local_file_path: 本地文件路径
object_name: MinIO中的对象名称,如果为None则使用文件名
content_type: 文件内容类型
Returns: str: 上传成功返回对象名称
""" if object_name is None:
object_name = os.path.basename(local_file_path)
try:
# 自动检测内容类型
if content_type is None:
if object_name.endswith('.txt'):
content_type = 'text/plain'
elif object_name.endswith('.json'):
content_type = 'application/json'
elif object_name.endswith('.csv'):
content_type = 'text/csv'
else:
content_type = 'application/text'
# 上传文件
self.client.fput_object(
self.tmp_bucket,
object_name,
local_file_path,
content_type=content_type
)
file_size = os.path.getsize(local_file_path)
print(f"✅ 上传成功: {object_name} ({file_size} bytes)")
return object_name
except S3Error as e:
print(f"❌ 上传失败 {object_name}: {e}")
raise
def download_file(self, object_name, local_file_path=None):
"""
从 MinIO 下载文件
Args: object_name: MinIO中的对象名称
local_file_path: 本地保存路径,如果为None则保存到临时目录
Returns: str: 下载文件的本地路径
""" try:
if local_file_path is None:
# 创建下载目录
download_dir = os.path.join(tempfile.gettempdir(), 'minio_downloads')
os.makedirs(download_dir, exist_ok=True)
local_file_path = os.path.join(download_dir, object_name)
# 下载文件
self.client.fget_object(
self.bucket_name,
object_name,
local_file_path
)
file_size = os.path.getsize(local_file_path)
print(f"✅ 下载成功: {object_name} -> {local_file_path} ({file_size} bytes)")
return local_file_path
except S3Error as e:
print(f"❌ 下载失败 {object_name}: {e}")
raise
def read_file_content(self, object_name):
"""
直接读取文件内容到内存
Args: object_name: MinIO中的对象名称
Returns: bytes: 文件内容
""" try:
response = self.client.get_object(self.bucket_name, object_name)
content = response.read()
response.close()
response.release_conn()
print(f"✅ 读取文件内容: {object_name} ({len(content)} bytes)")
return content
except S3Error as e:
print(f"❌ 读取文件失败 {object_name}: {e}")
raise
def generate_temp_url(self, object_name, expires=timedelta(hours=1)):
"""
生成预签名URL用于分享文件
Args: object_name: MinIO中的对象名称
expires: URL有效期,默认1小时
Returns: str: 预签名URL
""" try:
url = self.client.presigned_get_object(
self.tmp_bucket,
object_name,
expires=expires
)
print(f"✅ 生成分享链接: {object_name}")
print(f" 链接: {url}")
print(f" 有效期: {expires}")
return url
except S3Error as e:
print(f"❌ 生成分享链接失败 {object_name}: {e}")
raise
def generate_share_link(self, object_name):
"""
生成分享链接
Args: object_name: MinIO中的对象名称
bucket:
Returns: str: 预签名URL
""" if object_name[0] == '/':
object_name = object_name[1:]
# 因为bucket都允许公开访问了,所以不再需要生成有期限的url
share_host = f'http://{self.endpoint}'
return f'{share_host}/{self.tmp_bucket}/{object_name}'
def list_objects(self):
"""列出存储桶中的所有对象"""
try:
objects = self.client.list_objects(self.tmp_bucket)
print(f"\n📋 存储桶 '{self.bucket_name}' 中的文件:")
for obj in objects:
print(f" - {obj.object_name} (大小: {obj.size} bytes, 修改时间: {obj.last_modified})")
except S3Error as e:
print(f"❌ 列出对象失败: {e}")
def main():
"""主函数 - 演示完整的MinIO操作流程"""
# 上传文件
sample_files = {
"platform.zip": "C:/Users/KQL/Desktop/data/platform.zip",
"vuechatdemo.zip": "C:/Users/KQL/Desktop/data/vuechatdemo.zip"
}
# MinIO 连接配置
MINIO_CONFIG = {
'endpoint': '10.xx.xx.xx:9100', # 修改为你的MinIO服务地址
'access_key': 'minioadmin', # 修改为你的访问密钥
'secret_key': 'minioadmin', # 修改为你的密钥
'secure': False # 开发环境通常使用HTTP
}
print("🚀 MinIO Python SDK 演示开始")
print("=" * 50)
try:
# 初始化MinIO管理器
minio_manager = MinIOManager(**MINIO_CONFIG)
# 1. 确保存储桶存在
print("\n1️⃣ 初始化存储桶")
# 2. 创建示例文件
# print("\n2️⃣ 创建示例文件")
# sample_files = minio_manager.create_sample_files()
# 3. 上传文件
print("\n3️⃣ 上传文件到MinIO")
uploaded_objects = []
for display_name, file_path in sample_files.items():
object_name = minio_manager.upload_file(file_path, display_name)
uploaded_objects.append(object_name)
# 4. 列出存储桶中的文件
print("\n4️⃣ 列出存储桶中的文件")
minio_manager.list_objects()
# # 6. 下载文件
# print("\n5️⃣ 下载文件到本地")
# downloaded_files = [] # for obj_name in uploaded_objects: # downloaded_path = minio_manager.download_file(obj_name) # downloaded_files.append(downloaded_path) # 7. 生成分享链接
print("\n6️⃣ 生成临时性分享链接")
for obj_name in uploaded_objects:
if obj_name.endswith('.txt'):
minio_manager.generate_temp_url(obj_name, expires=timedelta(minutes=30))
else:
minio_manager.generate_temp_url(obj_name, expires=timedelta(hours=2))
print("\n7️⃣生成永久性分享链接")
for obj_name in uploaded_objects:
link_url = minio_manager.generate_share_link(obj_name)
print("生成的永久性分享链接:", link_url)
print("\n✨ MinIO 演示完成!")
except Exception as e:
print(f"\n💥 演示过程中发生错误: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
"""
运行前准备:
1. 安装MinIO Python SDK: pip install minio
2. 启动MinIO服务器或使用云端MinIO服务
3. 修改MINIO_CONFIG中的连接参数
4. 运行脚本: python minio_demo.py
""" main()
7.2 代码详解
MinIOManager 类初始化
python
class MinIOManager:
def __init__(self, endpoint, access_key, secret_key, secure=False):
"""
初始化解析:
endpoint: MinIO服务器地址
- 格式:'hostname:port' 或 'ip:port'
- 示例:'localhost:9000', '192.168.1.100:9000'
- 生产环境:'minio.company.com:443'
access_key & secret_key: 身份认证
- 类似于数据库的用户名和密码
- MinIO默认:minioadmin/minioadmin
- 生产环境应使用强密码
secure: 是否使用HTTPS
- False: HTTP协议(开发环境)
- True: HTTPS协议(生产环境)
"""
self.client = Minio(
endpoint,
access_key=access_key,
secret_key=secret_key,
secure=secure
)
# 预定义存储桶名称
self.bucket_name = "code-data"
# 临时库
self.tmp_bucket = "temp-data"
存储桶操作详解
python
def ensure_bucket_exists(self):
"""
存储桶管理的核心逻辑:
1. bucket_exists(): 检查存储桶是否存在
- 向MinIO发送HEAD请求
- 返回True/False
2. make_bucket(): 创建存储桶
- 发送PUT请求到MinIO
- 在服务器上创建存储空间
- 初始化元数据结构
"""
try:
if not self.client.bucket_exists(self.bucket_name):
self.client.make_bucket(self.bucket_name)
print(f"✅ 创建存储桶: {self.bucket_name}")
else:
print(f"✅ 存储桶已存在: {self.bucket_name}")
except S3Error as e:
print(f"❌ 创建存储桶失败: {e}")
raise
存储桶策略配置
Version(版本): 作用:指定策略文档的版本号 常用值:"2012-10-17"(AWS策略文档的标准版本) Statement(策略声明): 作用:包含一个或多个策略语句的数组,每个语句定义一组权限 Effect(效果): 作用:指定策略语句的效果,即允许还是拒绝访问 可选值:"Allow"(允许)或"Deny"(拒绝) Principal(主体): 作用:指定策略适用的用户或账户 可以是特定用户、账户组或通配符"*"(表示所有用户) Action(操作): 作用:指定允许或拒绝的具体操作 常见值:"s3:GetObject"(获取对象)、"s3:PutObject"(上传对象)、"s3:DeleteObject"(删除对象)等 Resource(资源): 作用:指定策略适用的资源(存储桶中的对象) 使用ARN(Amazon Resource Name)格式指定资源路径 Condition(条件): 作用:指定策略生效的条件 可以基于时间、IP地址、加密要求等条件限制访问 示例:限制只能从特定IP地址访问或要求使用HTTPS连接 Sid(语句ID): 作用:为策略语句提供可选的标识符 便于识别和管理复杂的策略 NotPrincipal(非主体): 作用:指定策略不适用的用户或账户 NotAction(非操作): 作用:指定策略不适用的操作 NotResource(非资源): 作用:指定策略不适用的资源
python
def _init_bucket_conf(self):
# create need bucket
self.ensure_bucket_exists(self.bucket_name)
self.ensure_bucket_exists(self.tmp_bucket)
# 设置存储桶的访问策略
anonymous_read_policy = {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": ["*"]
},
"Action": ["s3:GetObject"],
"Resource": [f"arn:aws:s3:::{self.bucket_name}/**"]
}]
}
tmp_policy = {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"AWS": ["*"]
},
"Action": ["s3:GetObject"],
"Resource": [f"arn:aws:s3:::{self.tmp_bucket}/**"],
"Condition": {
"IpAddress": {
# 仅限制从 192.168.1.0/24 子网访问
"aws:SourceIp": "192.168.1.0/24"
}
}
}]
}
try:
policy = self.client.get_bucket_policy(self.bucket_name)
except Exception as e:
if str(e).find('NoSuchBucketPolicy') == -1:
raise e
self.client.set_bucket_policy(self.bucket_name, json.dumps(anonymous_read_policy))
try:
policy = self.client.get_bucket_policy(self.tmp_bucket)
except Exception as e:
if str(e).find('NoSuchBucketPolicy') == -1:
raise e
self.client.set_bucket_policy(self.tmp_bucket, json.dumps(tmp_policy))
# 设置临时存储桶的生命周期
if not self.client.get_bucket_lifecycle(self.tmp_bucket):
lifecycle_conf = LifecycleConfig([
Rule(
'Enabled', # 表示启用
# 设置规则的过滤器,表示该规则只适用于对象名以 'temp-data/' 开头的对象。
rule_filter=Filter(prefix='temp-data/'),
# 设置规则的 ID,这里为 'rule1'。
rule_id='rule1',
# 设置对象的过期时间为 1 天。
expiration=Expiration(days=1),
),
], )
self.client.set_bucket_lifecycle(self.tmp_bucket, lifecycle_conf)
文件上传的内部机制
python
def upload_file(self, local_file_path, object_name=None, content_type=None):
"""
文件上传的完整流程:
1. 文件读取:从本地文件系统读取
2. 分片处理:大文件自动分片
3. 元数据设置:Content-Type, 文件大小等
4. 网络传输:HTTP/HTTPS PUT请求
5. 存储写入:MinIO服务器写入磁盘
6. 索引更新:更新对象索引信息
"""
# 自动内容类型检测
if content_type is None:
if object_name.endswith('.txt'):
content_type = 'text/plain'
elif object_name.endswith('.json'):
content_type = 'application/json'
# ... 更多类型判断
# fput_object 内部流程:
# 1. 打开本地文件
# 2. 计算文件大小和MD5
# 3. 创建HTTP PUT请求
# 4. 分片上传(如果文件大于5MB)
# 5. 验证上传完整性
self.client.fput_object(
self.bucket_name, # 目标存储桶
object_name, # 对象键
local_file_path, # 本地文件路径
content_type=content_type # MIME类型
)
预签名URL的安全机制
python
def generate_presigned_url(self, object_name, expires=timedelta(hours=1)):
"""
预签名URL的工作原理:
1. 时间戳计算:当前时间 + 有效期
2. 签名生成:使用密钥对URL进行加密签名
3. URL构建:包含签名、过期时间等参数
4. 权限验证:MinIO验证签名和时间戳
URL结构示例:
http://localhost:9000/demo-bucket/sample.txt?
X-Amz-Algorithm=AWS4-HMAC-SHA256&
X-Amz-Credential=minioadmin/20240115/us-east-1/s3/aws4_request&
X-Amz-Date=20240115T120000Z&
X-Amz-Expires=3600&
X-Amz-Signature=abc123...
"""
url = self.client.presigned_get_object(
self.bucket_name,
object_name,
expires=expires
)
return url
7.3 完整答案输出
perl
🚀 MinIO Python SDK 演示开始
==================================================
✅ 存储桶已存在: code-data
✅ 存储桶已存在: temp-data
1️⃣ 初始化存储桶
3️⃣ 上传文件到MinIO
✅ 上传成功: platform.zip (38908207 bytes)
✅ 上传成功: vuechatdemo.zip (114331 bytes)
4️⃣ 列出存储桶中的文件
📋 存储桶 'code-data' 中的文件:
- platform.zip (大小: 38908207 bytes, 修改时间: 2025-08-21 08:49:43.394000+00:00)
- vuechatdemo.zip (大小: 114331 bytes, 修改时间: 2025-08-21 08:49:43.425000+00:00)
6️⃣ 生成临时性分享链接
✅ 生成分享链接: platform.zip
链接: http://10.xx.xx.xx:9100/temp-data/platform.zip?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20250821%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250821T085059Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=fef2ad992e0e443413aadaaf2341184fa169be52ccbaf1eaf12128098c399449
有效期: 2:00:00
✅ 生成分享链接: vuechatdemo.zip
链接: http://10.xx.x.xx:9100/temp-data/vuechatdemo.zip?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=minioadmin%2F20250821%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250821T085059Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=bb39d1cca6c6212540ff7acb48e1f778b4c5dfc35f2ef3b304273298aa0d0036
有效期: 2:00:00
7️⃣生成永久性分享链接
生成的永久性分享链接: http://10.xx.xx.xx:9100/temp-data/platform.zip
生成的永久性分享链接: http://10.xx.xx.xx:9100/temp-data/vuechatdemo.zip
✨ MinIO 演示完成!
Process finished with exit code 0
8. 生产环境配置建议
安全配置
python
# 生产环境配置示例
PRODUCTION_CONFIG = {
'endpoint': 'minio.company.com:443',
'access_key': 'prod-access-key-32-chars-long',
'secret_key': 'prod-secret-key-64-chars-very-secure',
'secure': True, # 必须使用HTTPS
}
# 配置SSL证书验证
import ssl
context = ssl.create_default_context()
context.check_hostname = True
context.verify_mode = ssl.CERT_REQUIRED
监控和日志
python
import logging
# 配置详细日志
logging.basicConfig(level=logging.INFO)
minio_logger = logging.getLogger('minio')
# 操作审计
def audit_log_operation(operation, object_name, result):
logging.info(f"MinIO操作: {operation}, 对象: {object_name}, 结果: {result}")