You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
11 KiB
11 KiB
MinIO 迁移到 boto3(S3 兼容协议)
日期:2026-02-02
类型:架构升级
影响范围:后端 - 文件存储服务
变更概述
将文件存储服务从 MinIO SDK 迁移到 boto3(S3 兼容协议),实现对多种对象存储的统一支持,包括阿里云 OSS、AWS S3、MinIO、腾讯云 COS 等。
迁移原因
1. 通用性需求
- 生产环境使用阿里云 OSS
- 开发环境可能使用 MinIO
- 未来可能需要支持 AWS S3 或其他云存储
2. S3 兼容协议优势
- boto3 是最成熟的对象存储 SDK
- 阿里云 OSS 完全支持 S3 兼容 API
- 一套代码适配多种存储,只需修改配置
3. 灵活性
- 开发/测试/生产环境可以使用不同存储
- 便于迁移和多云部署
- 降低供应商锁定风险
详细变更
1. 依赖更新
文件:server/requirements.txt
移除:
minio==7.2.0
添加:
boto3==1.34.0
botocore==1.34.0
2. 配置更新
文件:server/app/core/config.py
变更前:
class Settings(BaseSettings):
# MinIO 配置
MINIO_ENDPOINT: str
MINIO_ACCESS_KEY: str
MINIO_SECRET_KEY: str
MINIO_SECURE: bool = False
MINIO_BUCKET_NAME: str = "jointo"
MINIO_PUBLIC_URL: str
STORAGE_PROVIDER: str = "minio"
变更后:
class Settings(BaseSettings):
# S3 兼容存储配置
S3_ENDPOINT_URL: str
S3_ACCESS_KEY_ID: str
S3_SECRET_ACCESS_KEY: str
S3_REGION: str = "cn-hangzhou"
S3_BUCKET_NAME: str = "jointo"
S3_PUBLIC_URL: str = "" # 可选,用于 CDN
STORAGE_PROVIDER: str = "oss" # oss/s3/minio
3. 环境变量更新
文件:server/.env.example
变更前:
MINIO_ENDPOINT=localhost:6185
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=minioadmin
MINIO_SECURE=false
MINIO_BUCKET_NAME=jointo
MINIO_PUBLIC_URL=http://localhost:6185
STORAGE_PROVIDER=minio
变更后:
# 生产环境(阿里云 OSS)
S3_ENDPOINT_URL=https://oss-cn-hangzhou.aliyuncs.com
S3_ACCESS_KEY_ID=your_access_key_id
S3_SECRET_ACCESS_KEY=your_secret_access_key
S3_REGION=cn-hangzhou
S3_BUCKET_NAME=jointo
S3_PUBLIC_URL=https://jointo.oss-cn-hangzhou.aliyuncs.com
STORAGE_PROVIDER=oss
# 开发环境(本地 MinIO)
# S3_ENDPOINT_URL=http://localhost:9000
# S3_ACCESS_KEY_ID=minioadmin
# S3_SECRET_ACCESS_KEY=minioadmin
# S3_REGION=us-east-1
# S3_BUCKET_NAME=jointo-dev
# S3_PUBLIC_URL=http://localhost:9000/jointo-dev
# STORAGE_PROVIDER=minio
4. StorageService 重写
文件:server/app/core/storage.py
核心变更:
4.1 导入更新
# 变更前
from minio import Minio
from minio.error import S3Error
# 变更后
import boto3
from botocore.exceptions import ClientError
from botocore.client import Config
4.2 客户端初始化
# 变更前
self.client = Minio(
settings.MINIO_ENDPOINT,
access_key=settings.MINIO_ACCESS_KEY,
secret_key=settings.MINIO_SECRET_KEY,
secure=settings.MINIO_SECURE
)
# 变更后
self.s3_client = boto3.client(
's3',
endpoint_url=settings.S3_ENDPOINT_URL,
aws_access_key_id=settings.S3_ACCESS_KEY_ID,
aws_secret_access_key=settings.S3_SECRET_ACCESS_KEY,
region_name=settings.S3_REGION,
config=Config(
signature_version='s3v4',
s3={'addressing_style': 'virtual'}
)
)
4.3 Bucket 检查
# 变更前
if not self.client.bucket_exists(self.bucket_name):
self.client.make_bucket(self.bucket_name)
# 变更后
try:
self.s3_client.head_bucket(Bucket=self.bucket_name)
except ClientError as e:
if e.response['Error']['Code'] == '404':
self.s3_client.create_bucket(Bucket=self.bucket_name)
4.4 文件上传
# 变更前
self.client.put_object(
self.bucket_name,
object_name,
BytesIO(data),
len(data),
content_type=content_type
)
# 变更后
extra_args = {}
if content_type:
extra_args['ContentType'] = content_type
self.s3_client.put_object(
Bucket=self.bucket_name,
Key=object_name,
Body=data,
**extra_args
)
4.5 预签名 URL
# 变更前
return self.client.presigned_get_object(
self.bucket_name,
object_name,
expires=timedelta(seconds=expires)
)
# 变更后
url = self.s3_client.generate_presigned_url(
'get_object',
Params={
'Bucket': self.bucket_name,
'Key': object_name
},
ExpiresIn=expires
)
return url
4.6 文件删除
# 变更前
self.client.remove_object(self.bucket_name, object_name)
# 变更后
self.s3_client.delete_object(
Bucket=self.bucket_name,
Key=object_name
)
4.7 文件存在检查
# 变更前
try:
self.client.stat_object(self.bucket_name, object_name)
return True
except S3Error:
return False
# 变更后
try:
self.s3_client.head_object(
Bucket=self.bucket_name,
Key=object_name
)
return True
except ClientError:
return False
5. Docker Compose 更新(可选)
文件:server/docker-compose.yml
如果不再需要本地 MinIO 服务,可以移除:
# 移除 MinIO 服务
# minio:
# image: minio/minio:latest
# container_name: jointo-server-minio
# ...
注意:如果开发环境仍需要本地对象存储,建议保留 MinIO 服务,只需修改环境变量配置即可。
6. 文档更新
文件:docs/requirements/backend/04-services/resource/file-storage-service.md
- ✅ 更新服务概述(S3 兼容协议)
- ✅ 更新支持的存储提供商列表
- ✅ 更新 StorageService 实现代码
- ✅ 更新配置示例(不同环境)
- ✅ 更新环境变量说明
- ✅ 更新文档版本(v2.1 → v3.0)
迁移步骤
1. 更新依赖
# 在容器内执行
docker exec jointo-server-app pip uninstall minio -y
docker exec jointo-server-app pip install boto3==1.34.0
或更新 requirements.txt 后重新构建镜像:
docker-compose build app
2. 更新环境变量
编辑 server/.env 文件,将 MinIO 配置替换为 S3 配置:
# 阿里云 OSS 配置
S3_ENDPOINT_URL=https://oss-cn-hangzhou.aliyuncs.com
S3_ACCESS_KEY_ID=your_oss_access_key_id
S3_SECRET_ACCESS_KEY=your_oss_secret_access_key
S3_REGION=cn-hangzhou
S3_BUCKET_NAME=jointo-prod
S3_PUBLIC_URL=https://jointo-prod.oss-cn-hangzhou.aliyuncs.com
STORAGE_PROVIDER=oss
3. 更新代码
- 更新
app/core/config.py - 更新
app/core/storage.py
4. 重启服务
docker-compose restart app
5. 验证功能
# 测试文件上传
curl -X POST http://localhost:6170/api/v1/file-storage/upload \
-H "Authorization: Bearer $TOKEN" \
-F "file=@test.jpg" \
-F "category=test"
兼容性说明
API 接口
- ✅ 无变更:所有 API 接口保持不变
- ✅ 无影响:前端代码无需修改
数据库
- ✅ 无变更:数据库表结构无需修改
- ✅ 兼容:已存储的文件记录完全兼容
业务逻辑
- ✅ 无变更:FileStorageService 接口保持不变
- ✅ 透明:其他服务(AttachmentService、ProjectResourceService 等)无需修改
配置对照表
| MinIO 配置 | boto3 配置 | 说明 |
|---|---|---|
MINIO_ENDPOINT |
S3_ENDPOINT_URL |
需要添加协议前缀(http:// 或 https://) |
MINIO_ACCESS_KEY |
S3_ACCESS_KEY_ID |
访问密钥 ID |
MINIO_SECRET_KEY |
S3_SECRET_ACCESS_KEY |
访问密钥 Secret |
MINIO_SECURE |
- | 通过 endpoint URL 的协议判断(https = secure) |
MINIO_BUCKET_NAME |
S3_BUCKET_NAME |
Bucket 名称 |
MINIO_PUBLIC_URL |
S3_PUBLIC_URL |
公开访问 URL(可选) |
| - | S3_REGION |
区域(新增,OSS 需要) |
不同存储提供商配置示例
阿里云 OSS
S3_ENDPOINT_URL=https://oss-cn-hangzhou.aliyuncs.com
S3_ACCESS_KEY_ID=LTAI5t...
S3_SECRET_ACCESS_KEY=xxx...
S3_REGION=cn-hangzhou
S3_BUCKET_NAME=jointo-prod
S3_PUBLIC_URL=https://cdn.jointo.com # CDN 加速
STORAGE_PROVIDER=oss
AWS S3
S3_ENDPOINT_URL=https://s3.amazonaws.com
S3_ACCESS_KEY_ID=AKIA...
S3_SECRET_ACCESS_KEY=xxx...
S3_REGION=us-east-1
S3_BUCKET_NAME=jointo-prod
S3_PUBLIC_URL=https://jointo-prod.s3.amazonaws.com
STORAGE_PROVIDER=s3
MinIO(本地开发)
S3_ENDPOINT_URL=http://localhost:9000
S3_ACCESS_KEY_ID=minioadmin
S3_SECRET_ACCESS_KEY=minioadmin
S3_REGION=us-east-1
S3_BUCKET_NAME=jointo-dev
S3_PUBLIC_URL=http://localhost:9000/jointo-dev
STORAGE_PROVIDER=minio
腾讯云 COS
S3_ENDPOINT_URL=https://cos.ap-guangzhou.myqcloud.com
S3_ACCESS_KEY_ID=AKID...
S3_SECRET_ACCESS_KEY=xxx...
S3_REGION=ap-guangzhou
S3_BUCKET_NAME=jointo-prod-1234567890
S3_PUBLIC_URL=https://jointo-prod-1234567890.cos.ap-guangzhou.myqcloud.com
STORAGE_PROVIDER=cos
测试建议
1. 单元测试
# tests/unit/test_storage_service.py
import pytest
from app.core.storage import StorageService
@pytest.mark.asyncio
async def test_upload_bytes():
storage = StorageService()
data = b"test content"
url = await storage.upload_bytes(data, "test/file.txt", "text/plain")
assert url is not None
assert "test/file.txt" in url
2. 集成测试
# 上传测试
curl -X POST http://localhost:6170/api/v1/file-storage/upload \
-H "Authorization: Bearer $TOKEN" \
-F "file=@test.jpg" \
-F "category=test"
# 获取预签名 URL
curl -X GET "http://localhost:6170/api/v1/file-storage/presigned-url?storage_path=test/file.txt" \
-H "Authorization: Bearer $TOKEN"
3. 性能测试
- 上传 1MB 文件:< 1s
- 上传 10MB 文件:< 5s
- 生成预签名 URL:< 100ms
回滚方案
如果迁移后出现问题,可以快速回滚:
1. 恢复依赖
docker exec jointo-server-app pip uninstall boto3 -y
docker exec jointo-server-app pip install minio==7.2.0
2. 恢复配置
恢复 .env 文件中的 MinIO 配置
3. 恢复代码
git checkout HEAD~1 server/app/core/storage.py
git checkout HEAD~1 server/app/core/config.py
4. 重启服务
docker-compose restart app
注意事项
1. 阿里云 OSS 特殊配置
- 使用虚拟主机风格(virtual hosted-style)
- Endpoint 格式:
https://oss-<region>.aliyuncs.com - Bucket 域名:
https://<bucket-name>.oss-<region>.aliyuncs.com
2. 签名版本
- boto3 默认使用 Signature Version 4
- 阿里云 OSS 完全支持 S3v4 签名
3. CDN 加速
- 生产环境建议配置
S3_PUBLIC_URL为 CDN 域名 - 提升文件访问速度
4. 权限配置
- 确保 AccessKey 有 Bucket 的读写权限
- 建议使用 RAM 子账号,遵循最小权限原则
相关文档
- 需求文档:
docs/requirements/backend/04-services/resource/file-storage-service.md - boto3 文档:https://boto3.amazonaws.com/v1/documentation/api/latest/index.html
- 阿里云 OSS S3 兼容:https://help.aliyun.com/document_detail/64919.html
- AWS S3 API:https://docs.aws.amazon.com/s3/
作者
AI Assistant
审核状态
待审核