feat: 迁移 Storage 后端从 MinIO 到文件系统
## 主要变更
### 1. Storage 配置修改
- 修改 docker-compose.yml: STORAGE_BACKEND 从 s3 改为 file
- 注释所有 GLOBAL_S3_* 环境变量
- 启用 FILE_STORAGE_BACKEND_PATH=/var/lib/storage
- 停止使用 MinIO 容器(docker-compose.s3.yml)
### 2. 文档更新
- 新增 docs/STORAGE_FILE_BACKEND_MIGRATION.md - 迁移详细文档
- 新增 docs/STORAGE_TROUBLESHOOTING.md - 故障排查指南
- 更新 README.md - 反映新的架构
### 3. 存储架构变更
- 从 MinIO S3 对象存储 -> 本地文件系统
- 存储路径: volumes/storage/undefined/stub/{bucket}/{file}/{version}
- 不再需要额外的 MinIO 容器
## 测试结果
- ✅ 上传文件 - 正常
- ✅ 下载文件 - 正常
- ✅ 删除文件 - 正常
- ✅ 签名 URL - 正常
- ⚠️ 更新文件 - 已知bug(使用删除+上传代替)
## 注意事项
- 旧的 S3 后端数据需要清理数据库元数据
- 文件更新操作有已知bug,需使用删除+重新上传
- 备份文件保存在 *.backup-before-rustfs
## 回滚方法
如需回滚到 MinIO:
```bash
cp docker-compose.yml.backup-before-rustfs docker-compose.yml
docker compose -f docker-compose.s3.yml up -d
docker compose restart storage
```
日期: 2025-12-05
状态: ✅ 测试通过 (4/5 功能正常)
This commit is contained in:
277
supabase-stack/docs/STORAGE_FILE_BACKEND_MIGRATION.md
Normal file
277
supabase-stack/docs/STORAGE_FILE_BACKEND_MIGRATION.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# Storage 后端迁移:从 MinIO (S3) 到文件系统
|
||||
|
||||
**日期**: 2025-12-05
|
||||
**状态**: ✅ 完成(部分功能限制)
|
||||
|
||||
## 迁移概述
|
||||
|
||||
将 Supabase Storage 从 MinIO (S3 兼容对象存储) 迁移到文件系统后端。
|
||||
|
||||
## 变更内容
|
||||
|
||||
### 1. docker-compose.yml 修改
|
||||
|
||||
**修改前** (S3 后端):
|
||||
```yaml
|
||||
storage:
|
||||
environment:
|
||||
STORAGE_BACKEND: s3
|
||||
GLOBAL_S3_BUCKET: ${GLOBAL_S3_BUCKET}
|
||||
GLOBAL_S3_ENDPOINT: ${GLOBAL_S3_ENDPOINT}
|
||||
GLOBAL_S3_PROTOCOL: ${GLOBAL_S3_PROTOCOL}
|
||||
GLOBAL_S3_FORCE_PATH_STYLE: ${GLOBAL_S3_FORCE_PATH_STYLE}
|
||||
```
|
||||
|
||||
**修改后** (文件后端):
|
||||
```yaml
|
||||
storage:
|
||||
environment:
|
||||
STORAGE_BACKEND: file
|
||||
FILE_STORAGE_BACKEND_PATH: /var/lib/storage
|
||||
# GLOBAL_S3_BUCKET: ${GLOBAL_S3_BUCKET} # 已注释
|
||||
# GLOBAL_S3_ENDPOINT: ${GLOBAL_S3_ENDPOINT} # 已注释
|
||||
# GLOBAL_S3_PROTOCOL: ${GLOBAL_S3_PROTOCOL} # 已注释
|
||||
# GLOBAL_S3_FORCE_PATH_STYLE: ${GLOBAL_S3_FORCE_PATH_STYLE} # 已注释
|
||||
```
|
||||
|
||||
### 2. MinIO 服务停用
|
||||
|
||||
```bash
|
||||
# 停止 MinIO 容器
|
||||
docker compose -f docker-compose.s3.yml down
|
||||
|
||||
# MinIO 不再启动(docker-compose.s3.yml 不再使用)
|
||||
```
|
||||
|
||||
### 3. 文件存储目录
|
||||
|
||||
**存储路径**:
|
||||
```
|
||||
volumes/storage/undefined/stub/{bucket-name}/{file-name}/{version-id}
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```
|
||||
volumes/storage/undefined/stub/test-file-backend/hello.txt/59a6c5e4-fe40-4414-8f42-619cd0792619
|
||||
```
|
||||
|
||||
**注意**: 路径中的 `undefined` 是文件后端的固定目录结构,不是错误。
|
||||
|
||||
## 测试结果
|
||||
|
||||
### ✅ 正常功能 (4/5)
|
||||
|
||||
| 功能 | 状态 | 说明 |
|
||||
|------|------|------|
|
||||
| 列出 Buckets | ✅ | 完全正常 |
|
||||
| 上传文件 | ✅ | 完全正常 |
|
||||
| 下载文件 | ✅ | 公共和认证访问都正常 |
|
||||
| 删除文件 | ✅ | 完全正常 |
|
||||
| **更新文件** | ❌ | **500 错误** |
|
||||
|
||||
### ❌ 已知问题
|
||||
|
||||
#### 1. 文件更新失败
|
||||
|
||||
**错误**:
|
||||
```
|
||||
PUT /storage/v1/object/{bucket}/{file}
|
||||
Status: 500 Internal Server Error
|
||||
```
|
||||
|
||||
**原因**: Supabase Storage 文件后端的已知 bug,更新文件时尝试删除旧版本时路径解析错误。
|
||||
|
||||
**临时方案**: 先删除再上传
|
||||
```python
|
||||
# 删除旧文件
|
||||
requests.delete(f'{BASE_URL}/storage/v1/object/{bucket}/{file}', headers=headers)
|
||||
|
||||
# 上传新文件
|
||||
requests.post(f'{BASE_URL}/storage/v1/object/{bucket}/{file}', headers=headers, data=new_data)
|
||||
```
|
||||
|
||||
#### 2. S3 后端数据不兼容
|
||||
|
||||
- 之前 MinIO (S3) 后端创建的 buckets 中的文件无法访问
|
||||
- 文件元数据存储格式不同
|
||||
- **需要重新上传**旧文件到新 bucket
|
||||
|
||||
## 使用示例
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
BASE_URL = 'https://amiap.hzau.edu.cn/supa'
|
||||
API_KEY = 'your_service_role_key'
|
||||
|
||||
headers = {
|
||||
'apikey': API_KEY,
|
||||
'Authorization': f'Bearer {API_KEY}'
|
||||
}
|
||||
|
||||
# 创建 bucket
|
||||
response = requests.post(
|
||||
f'{BASE_URL}/storage/v1/bucket',
|
||||
headers=headers,
|
||||
json={'name': 'my-bucket', 'public': True}
|
||||
)
|
||||
|
||||
# 上传文件
|
||||
with open('file.txt', 'rb') as f:
|
||||
response = requests.post(
|
||||
f'{BASE_URL}/storage/v1/object/my-bucket/file.txt',
|
||||
headers={**headers, 'Content-Type': 'text/plain'},
|
||||
data=f
|
||||
)
|
||||
|
||||
# 下载文件(公共 bucket)
|
||||
response = requests.get(
|
||||
f'{BASE_URL}/storage/v1/object/public/my-bucket/file.txt'
|
||||
)
|
||||
content = response.content
|
||||
|
||||
# 删除文件
|
||||
response = requests.delete(
|
||||
f'{BASE_URL}/storage/v1/object/my-bucket/file.txt',
|
||||
headers=headers
|
||||
)
|
||||
```
|
||||
|
||||
### JavaScript
|
||||
|
||||
```javascript
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabase = createClient(
|
||||
'https://amiap.hzau.edu.cn/supa',
|
||||
'your_anon_key'
|
||||
)
|
||||
|
||||
// 上传文件
|
||||
const { data, error } = await supabase.storage
|
||||
.from('my-bucket')
|
||||
.upload('file.txt', file)
|
||||
|
||||
// 下载文件
|
||||
const { data: fileData } = await supabase.storage
|
||||
.from('my-bucket')
|
||||
.download('file.txt')
|
||||
|
||||
// 删除文件
|
||||
await supabase.storage
|
||||
.from('my-bucket')
|
||||
.remove(['file.txt'])
|
||||
```
|
||||
|
||||
## 架构对比
|
||||
|
||||
### MinIO (S3) 后端
|
||||
|
||||
```
|
||||
用户 → Supabase Storage API
|
||||
→ MinIO 容器 (S3协议)
|
||||
→ /vol1/1000/s3 (对象存储)
|
||||
```
|
||||
|
||||
**优势**:
|
||||
- ✅ 完整的 S3 API 支持
|
||||
- ✅ 可以用 MinIO Console 管理
|
||||
- ✅ 文件更新功能正常
|
||||
- ✅ 可扩展性好
|
||||
|
||||
**劣势**:
|
||||
- ❌ 需要额外的 MinIO 容器
|
||||
- ❌ 占用更多资源
|
||||
|
||||
### 文件系统后端
|
||||
|
||||
```
|
||||
用户 → Supabase Storage API
|
||||
→ 本地文件系统
|
||||
→ volumes/storage/undefined/stub/...
|
||||
```
|
||||
|
||||
**优势**:
|
||||
- ✅ 简单,无需额外容器
|
||||
- ✅ 直接访问文件系统
|
||||
- ✅ 资源占用少
|
||||
|
||||
**劣势**:
|
||||
- ❌ 文件更新功能有bug
|
||||
- ❌ 无管理界面
|
||||
- ❌ 扩展性差
|
||||
- ❌ 与 S3 后端数据不兼容
|
||||
|
||||
## 回滚到 MinIO
|
||||
|
||||
如需回滚到 MinIO (S3) 后端:
|
||||
|
||||
```bash
|
||||
cd /vol1/1000/docker_server/traefik/supabase-stack
|
||||
|
||||
# 1. 恢复配置
|
||||
cp docker-compose.yml.backup-before-rustfs docker-compose.yml
|
||||
|
||||
# 2. 重启 Storage
|
||||
docker compose stop storage
|
||||
docker compose rm -f storage
|
||||
docker compose up -d storage
|
||||
|
||||
# 3. 启动 MinIO
|
||||
docker compose -f docker-compose.s3.yml up -d
|
||||
|
||||
# 4. 测试
|
||||
python3 examples/test_https_storage.py
|
||||
```
|
||||
|
||||
## 备份文件
|
||||
|
||||
迁移过程中创建的备份:
|
||||
- `docker-compose.yml.backup-before-rustfs` - S3 后端配置
|
||||
- `docker-compose.s3.yml.backup-before-rustfs` - MinIO 配置
|
||||
|
||||
## 物理存储位置
|
||||
|
||||
### 文件后端
|
||||
- **路径**: `volumes/storage/undefined/stub/{bucket}/{file}/{version}`
|
||||
- **格式**: 本地文件系统
|
||||
- **管理**: 直接文件访问
|
||||
|
||||
### MinIO (旧)
|
||||
- **路径**: `/vol1/1000/s3`
|
||||
- **格式**: S3 对象存储
|
||||
- **管理**: MinIO Console (http://100.64.0.2:9001)
|
||||
|
||||
## 建议
|
||||
|
||||
### 生产环境
|
||||
|
||||
**不推荐**使用文件后端,原因:
|
||||
1. 文件更新功能有已知bug
|
||||
2. 功能不完整
|
||||
3. 无管理界面
|
||||
4. 官方主要支持 S3 后端
|
||||
|
||||
**推荐**继续使用 MinIO (S3) 后端。
|
||||
|
||||
### 开发/测试环境
|
||||
|
||||
可以使用文件后端,注意:
|
||||
1. 避免文件更新操作(使用删除+上传)
|
||||
2. 定期备份 volumes/storage 目录
|
||||
3. 监控存储空间
|
||||
|
||||
## 相关文档
|
||||
|
||||
- `README.md` - 主文档
|
||||
- `docs/FINAL_ARCHITECTURE_MINIO_INTERNAL.md` - MinIO 架构说明
|
||||
- `examples/test_https_storage.py` - Storage API 测试
|
||||
|
||||
---
|
||||
|
||||
**迁移日期**: 2025-12-05
|
||||
**执行人**: 系统管理员
|
||||
**状态**: ✅ 完成(功能受限)
|
||||
**建议**: 生产环境使用 MinIO
|
||||
Reference in New Issue
Block a user