# Supabase Stack 运维指南 完整的 Supabase 对象存储运维手册 --- ## 📋 目录 1. [系统架构](#系统架构) 2. [服务启动与管理](#服务启动与管理) 3. [Storage API 使用](#storage-api-使用) 4. [故障排查](#故障排查) --- ## 🏗️ 系统架构 ### 组件说明 ``` 外部用户 (HTTPS) ↓ Traefik (:443) ↓ Kong Gateway (:18000) ↓ ┌────────────────────────────────┐ │ Supabase Services │ ├────────────────────────────────┤ │ • Auth (GoTrue) - 用户认证 │ │ • REST (PostgREST) - 数据API │ │ • Storage - 对象存储 │ │ • Realtime - 实时订阅 │ └────────────────────────────────┘ ↓ PostgreSQL + MinIO ``` ### 访问地址 | 服务 | 地址 | 用途 | |------|------|------| | 公网 API | https://amiap.hzau.edu.cn/supa | 所有 API 入口 | | Storage API | https://amiap.hzau.edu.cn/supa/storage/v1 | 对象存储 | | Dashboard | http://100.64.0.2:18000 | 管理后台(内网) | ### 数据存储 - **PostgreSQL 数据**: `./volumes/db/data/` - **对象存储数据**: `/vol1/1000/s3/stub/` --- ## 🚀 服务启动与管理 ### 启动服务 ```bash cd /vol1/1000/docker_server/traefik/supabase-stack # 启动所有服务(包含 MinIO 对象存储后端) docker compose -f docker-compose.yml -f docker-compose.s3.yml up -d ``` **说明**: - `docker-compose.yml` - Supabase 核心服务 - `docker-compose.s3.yml` - MinIO 存储后端(**必需**) ### 查看状态 ```bash # 查看所有容器 docker compose ps # 查看日志 docker compose logs -f storage docker compose logs -f kong ``` ### 停止/重启 ```bash # 停止服务 docker compose stop # 重启特定服务 docker compose restart storage docker compose restart minio # 完全停止并删除容器(数据保留) docker compose down ``` ### 环境变量 关键密钥在 `.env` 文件中: ```bash # 服务密钥(后端使用) SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UiLCJpYXQiOjE3NjM4MDI2NjksImV4cCI6MjA3OTE2MjY2OX0.gQWUaTkZ6mjjlv2TED0cODp2meqqWuCGKZR1ptIbovg # 匿名密钥(前端使用) ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlzcyI6InN1cGFiYXNlIiwiaWF0IjoxNzYzODAyNjY5LCJleHAiOjIwNzkxNjI2Njl9.ltGXvQKpguLaf8Vzomn310hLgOZbrjqZT-F3rR00ulg ``` --- ## 📦 Storage API 使用 ### API 端点 ``` Base URL: https://amiap.hzau.edu.cn/supa Storage: https://amiap.hzau.edu.cn/supa/storage/v1 ``` ### 完整 Python 示例 保存为 `storage_client.py`: ```python import requests from pathlib import Path class StorageClient: def __init__(self, base_url, api_key): self.base_url = base_url self.headers = { 'apikey': api_key, 'Authorization': f'Bearer {api_key}' } def create_bucket(self, name, public=False): """创建 bucket""" response = requests.post( f'{self.base_url}/storage/v1/bucket', headers=self.headers, json={'name': name, 'public': public} ) return response.ok def upload_file(self, bucket, file_path, storage_path=None): """上传文件""" if not storage_path: storage_path = Path(file_path).name with open(file_path, 'rb') as f: response = requests.post( f'{self.base_url}/storage/v1/object/{bucket}/{storage_path}', headers=self.headers, files={'file': f} ) return response.json() if response.ok else None def download_file(self, bucket, storage_path, local_path): """下载文件""" response = requests.get( f'{self.base_url}/storage/v1/object/{bucket}/{storage_path}', headers=self.headers ) if response.ok: with open(local_path, 'wb') as f: f.write(response.content) return True return False def create_signed_url(self, bucket, storage_path, expires_in=3600): """生成临时下载链接""" response = requests.post( f'{self.base_url}/storage/v1/object/sign/{bucket}/{storage_path}', headers=self.headers, json={'expiresIn': expires_in} ) if response.ok: return self.base_url + response.json()['signedURL'] return None # 使用示例 if __name__ == '__main__': client = StorageClient( 'https://amiap.hzau.edu.cn/supa', 'your-service-role-key' ) # 创建 bucket client.create_bucket('my-bucket') # 上传文件 client.upload_file('my-bucket', 'photo.jpg', 'uploads/photo.jpg') # 生成临时链接 url = client.create_signed_url('my-bucket', 'uploads/photo.jpg') print(f'下载链接: {url}') ``` ### 完整 JavaScript 示例 ```javascript class StorageClient { constructor(baseUrl, apiKey) { this.baseUrl = baseUrl; this.headers = { 'apikey': apiKey, 'Authorization': `Bearer ${apiKey}` }; } async createBucket(name, isPublic = false) { const response = await fetch(`${this.baseUrl}/storage/v1/bucket`, { method: 'POST', headers: { ...this.headers, 'Content-Type': 'application/json' }, body: JSON.stringify({ name, public: isPublic }) }); return response.ok; } async uploadFile(bucket, file, storagePath) { const formData = new FormData(); formData.append('file', file); const response = await fetch( `${this.baseUrl}/storage/v1/object/${bucket}/${storagePath}`, { method: 'POST', headers: this.headers, body: formData } ); return response.ok ? await response.json() : null; } async createSignedUrl(bucket, storagePath, expiresIn = 3600) { const response = await fetch( `${this.baseUrl}/storage/v1/object/sign/${bucket}/${storagePath}`, { method: 'POST', headers: { ...this.headers, 'Content-Type': 'application/json' }, body: JSON.stringify({ expiresIn }) } ); if (response.ok) { const data = await response.json(); return this.baseUrl + data.signedURL; } return null; } } // 使用示例 const client = new StorageClient( 'https://amiap.hzau.edu.cn/supa', 'your-service-role-key' ); // 上传文件 const fileInput = document.querySelector('input[type="file"]'); fileInput.addEventListener('change', async (e) => { const file = e.target.files[0]; await client.uploadFile('my-bucket', file, `uploads/${file.name}`); }); ``` 完整代码示例请查看:`storage_client.py` 和 `storage_client.js` --- ## 🔧 故障排查 ### 常见问题 **1. 服务无法启动** ```bash # 检查端口占用 docker compose ps netstat -tulpn | grep -E ":(8000|5432|9000)" # 查看日志 docker compose logs storage ``` **2. API 返回 403** ```bash # 检查密钥是否正确 grep SERVICE_ROLE_KEY .env # 测试 API curl -I https://amiap.hzau.edu.cn/supa/storage/v1/bucket \ -H "apikey: YOUR_KEY" ``` **3. 上传失败** ```bash # 检查 MinIO 是否运行 docker compose ps minio # 查看 Storage 日志 docker compose logs storage | tail -50 ``` ### 健康检查 ```bash # 快速测试脚本 python3 test_https_storage.py # 手动测试 curl https://amiap.hzau.edu.cn/supa/rest/v1/ ``` ### 备份 ```bash # 备份数据库 docker exec supabase-db pg_dump -U postgres > backup.sql # 备份对象存储 tar -czf s3_backup.tar.gz /vol1/1000/s3/ ``` --- ## 📚 相关文档 - `storage_client.py` - Python 完整客户端代码 - `storage_client.js` - JavaScript 完整客户端代码 - `test_https_storage.py` - 测试脚本 - `VUE_API_INTEGRATION.md` - Vue 集成指南 --- ## 🎯 快速开始 ```bash # 1. 启动服务 docker compose -f docker-compose.yml -f docker-compose.s3.yml up -d # 2. 测试 python3 test_https_storage.py # 3. 查看文档 cat storage_client.py ``` 完成!现在可以开始使用 Supabase Storage 了。