[{"content":"","date":null,"permalink":"http://blog.hys.my/categories/ai/","section":"Categories","summary":"","title":"AI"},{"content":"","date":null,"permalink":"http://blog.hys.my/categories/android/","section":"Categories","summary":"","title":"Android"},{"content":"","date":null,"permalink":"http://blog.hys.my/categories/","section":"Categories","summary":"","title":"Categories"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/claude/","section":"Tags","summary":"","title":"Claude"},{"content":"","date":null,"permalink":"http://blog.hys.my/categories/deepseek/","section":"Categories","summary":"","title":"DeepSeek"},{"content":"","date":null,"permalink":"http://blog.hys.my/categories/docker/","section":"Categories","summary":"","title":"Docker"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/ds2api/","section":"Tags","summary":"","title":"DS2API"},{"content":" 重要免责声明\n本仓库仅供学习、研究、个人实验和内部验证使用,不提供任何形式的商业授权、适用性保证或结果保证。\n作者及仓库维护者不对因使用、修改、分发、部署或依赖本项目而产生的任何直接或间接损失、账号封禁、数据丢失、法律风险或第三方索赔负责。\n请勿将本项目用于违反服务条款、协议、法律法规或平台规则的场景。商业使用前请自行确认 LICENSE、相关协议以及你是否获得了作者的书面许可。\n架构概览(摘要) #flowchart LR Client[\u0026#34;🖥️ 客户端 / SDK\\n(OpenAI / Claude / Gemini)\u0026#34;] Upstream[\u0026#34;☁️ DeepSeek API\u0026#34;] subgraph DS2API[\u0026#34;DS2API 3.x(统一 OpenAI 内核)\u0026#34;] Router[\u0026#34;chi Router + 中间件\\n(RequestID / RealIP / Logger / Recoverer / CORS)\u0026#34;] subgraph Adapters[\u0026#34;协议适配层\u0026#34;] OA[\u0026#34;OpenAI\\n/v1/*\u0026#34;] CA[\u0026#34;Claude\\n/anthropic/* + /v1/messages\u0026#34;] GA[\u0026#34;Gemini\\n/v1beta/models/* + /v1/models/*\u0026#34;] Admin[\u0026#34;Admin API\\n/admin/*\u0026#34;] WebUI[\u0026#34;WebUI\\n/admin(静态托管)\u0026#34;] end subgraph Runtime[\u0026#34;运行时核心能力\u0026#34;] Bridge[\u0026#34;CLIProxy 转换桥\\n(多协议 \u0026lt;-\u0026gt; OpenAI)\u0026#34;] OAEngine[\u0026#34;OpenAI ChatCompletions\\n(统一工具调用与流式语义)\u0026#34;] Auth[\u0026#34;Auth Resolver\\n(API key / bearer / x-goog-api-key)\u0026#34;] Pool[\u0026#34;Account Pool + Queue\\n(并发槽位 + 等待队列)\u0026#34;] DSClient[\u0026#34;DeepSeek Client\\n(Session / Auth / HTTP)\u0026#34;] Pow[\u0026#34;PoW 实现\\n(纯 Go 毫秒级)\u0026#34;] Tool[\u0026#34;Tool Sieve\\n(Go/Node 语义对齐)\u0026#34;] end end Client --\u0026gt; Router Router --\u0026gt; OA \u0026amp; CA \u0026amp; GA Router --\u0026gt; Admin Router --\u0026gt; WebUI OA --\u0026gt; OAEngine CA \u0026amp; GA --\u0026gt; Bridge Bridge --\u0026gt; OAEngine OAEngine --\u0026gt; Auth OAEngine -.账号轮询.-\u0026gt; Pool OAEngine -.工具调用解析.-\u0026gt; Tool OAEngine -.PoW 计算.-\u0026gt; Pow Auth --\u0026gt; DSClient DSClient --\u0026gt; Upstream Upstream --\u0026gt; DSClient OAEngine --\u0026gt; Bridge Bridge --\u0026gt; Client 详细架构拆分与目录职责见 docs/ARCHITECTURE.md。\n后端:Go(cmd/ds2api/、api/、internal/),不依赖 Python 运行时 前端:React 管理台(webui/),运行时托管静态构建产物 部署:本地运行、Docker、Vercel Serverless、Linux systemd 核心能力 # 能力 说明 OpenAI 兼容 GET /v1/models、GET /v1/models/{id}、POST /v1/chat/completions、POST /v1/responses、GET /v1/responses/{response_id}、POST /v1/embeddings、POST /v1/files Claude 兼容 GET /anthropic/v1/models、POST /anthropic/v1/messages、POST /anthropic/v1/messages/count_tokens(及快捷路径 /v1/messages、/messages) Gemini 兼容 POST /v1beta/models/{model}:generateContent、POST /v1beta/models/{model}:streamGenerateContent(及 /v1/models/{model}:* 路径) 多账号轮询 自动 token 刷新、邮箱/手机号双登录方式 并发队列控制 每账号 in-flight 上限 + 等待队列,动态计算建议并发值 DeepSeek PoW 纯 Go 高性能实现(DeepSeekHashV1),毫秒级响应 Tool Calling 防泄漏处理:非代码块高置信特征识别、delta.tool_calls 早发、结构化增量输出 Admin API 配置管理、运行时设置热更新、代理管理、账号测试 / 批量测试、会话清理、导入导出、Vercel 同步、版本检查 WebUI 管理台 /admin 单页应用(中英文双语、深色模式) 运维探针 GET /healthz(存活)、GET /readyz(就绪) 平台兼容矩阵 # 级别 平台 当前状态 P0 Codex CLI/SDK(wire_api=chat / wire_api=responses) ✅ P0 OpenAI SDK(JS/Python,chat + responses) ✅ P0 Vercel AI SDK(openai-compatible) ✅ P0 Anthropic SDK(messages) ✅ P0 Google Gemini SDK(generateContent) ✅ P1 LangChain / LlamaIndex / OpenWebUI(OpenAI 兼容接入) ✅ 模型支持 #OpenAI 接口(GET /v1/models) # 模型类型 模型 ID thinking search default deepseek-chat ❌ ❌ default deepseek-reasoner ✅ ❌ default deepseek-chat-search ❌ ✅ default deepseek-reasoner-search ✅ ✅ expert deepseek-expert-chat ❌ ❌ expert deepseek-expert-reasoner ✅ ❌ expert deepseek-expert-chat-search ❌ ✅ expert deepseek-expert-reasoner-search ✅ ✅ vision deepseek-vision-chat ❌ ❌ vision deepseek-vision-reasoner ✅ ❌ vision deepseek-vision-chat-search ❌ ✅ vision deepseek-vision-reasoner-search ✅ ✅ 除原生模型外,也支持常见 alias 输入(如 gpt-5、gpt-5-mini、gpt-5-codex、gpt-4.1、o3、claude-opus-4-6、claude-sonnet-4-5、gemini-2.5-pro、gemini-2.5-flash 等),但 /v1/models 返回的是规范化后的 DeepSeek 原生模型 ID。\nClaude 接口(GET /anthropic/v1/models) # 当前常用模型 默认映射 claude-sonnet-4-5 deepseek-chat claude-haiku-4-5(兼容 claude-3-5-haiku-latest) deepseek-chat claude-opus-4-6 deepseek-reasoner 可通过配置中的 claude_mapping 或 claude_model_mapping 覆盖映射关系。/anthropic/v1/models 除上述当前主别名外,还会返回 Claude 4.x snapshots,以及 3.x / 2.x / 1.x 历史模型 ID 与常见 alias,便于旧客户端直接兼容。\nClaude Code 接入避坑(实测) # ANTHROPIC_BASE_URL 推荐直接指向 DS2API 根地址(例如 http://127.0.0.1:5001),Claude Code 会请求 /v1/messages?beta=true。 ANTHROPIC_API_KEY 需要与 config.json 中 keys 一致;建议同时保留常规 key 与 sk-ant-* 形态 key,兼容不同客户端校验习惯。 若系统设置了代理,建议对 DS2API 地址配置 NO_PROXY=127.0.0.1,localhost,\u0026lt;你的主机IP\u0026gt;,避免本地回环请求被代理拦截。 如遇“工具调用输出成文本、未执行”问题,请优先检查模型输出是否为受支持的 XML/Markup 工具块(例如 \u0026lt;tool_call\u0026gt; / \u0026lt;function_call\u0026gt; / \u0026lt;invoke\u0026gt; / tool_use),而不是纯 JSON tool_calls 片段。 Gemini 接口 #Gemini 适配器将模型名通过 model_aliases 或内置规则映射到 DeepSeek 原生模型,支持 generateContent 和 streamGenerateContent 两种调用方式,并完整支持 Tool Calling(functionDeclarations → functionCall 输出)。\n快速开始 #部署方式优先级建议 #推荐按以下顺序选择部署方式:\n下载 Release 构建包运行:最省事,产物已编译完成,最适合大多数用户。 Docker / GHCR 镜像部署:适合需要容器化、编排或云环境部署。 Vercel 部署:适合已有 Vercel 环境且接受其平台约束的场景。 本地源码运行 / 自行编译:适合开发、调试或需要自行修改代码的场景。 通用第一步(所有部署方式) #把 config.json 作为唯一配置源(推荐做法):\ncp config.example.json config.json # 编辑 config.json 后续部署建议:\n本地运行:直接读取 config.json Docker / Vercel:由 config.json 生成 DS2API_CONFIG_JSON(Base64)注入环境变量,也可以直接写原始 JSON 方式一:下载 Release 构建包 #每次发布 Release 时,GitHub Actions 会自动构建多平台二进制包:\n# 下载对应平台的压缩包后 tar -xzf ds2api_\u0026lt;tag\u0026gt;_linux_amd64.tar.gz cd ds2api_\u0026lt;tag\u0026gt;_linux_amd64 cp config.example.json config.json # 编辑 config.json ./ds2api 方式二:Docker 运行 ## 1. 准备环境变量和配置文件 cp .env.example .env cp config.example.json config.json # 2. 编辑 .env(至少设置 DS2API_ADMIN_KEY;如需修改宿主机端口,可额外设置 DS2API_HOST_PORT) # DS2API_ADMIN_KEY=请替换为强密码 # 3. 启动 docker-compose up -d # 4. 查看日志 docker-compose logs -f 默认 docker-compose.yml 会把宿主机 6011 映射到容器内的 5001。如果你希望直接对外暴露 5001,请设置 DS2API_HOST_PORT=5001(或者手动调整 ports 配置)。\n更新镜像:docker-compose up -d --build\nZeabur 一键部署(Dockerfile) # 点击上方 “Deploy on Zeabur” 按钮,一键部署。 部署完成后访问 /admin,使用 Zeabur 环境变量/模板指引中的 DS2API_ADMIN_KEY 登录。 在管理台导入/编辑配置(会写入并持久化到 /data/config.json)。 说明:Zeabur 使用仓库内 Dockerfile 直接构建时,不需要额外传入 BUILD_VERSION;镜像会优先读取该构建参数,未提供时自动回退到仓库根目录的 VERSION 文件。\n方式三:Vercel 部署 # Fork 仓库到自己的 GitHub 在 Vercel 上导入项目 配置环境变量(最少设置 DS2API_ADMIN_KEY;推荐同时设置 DS2API_CONFIG_JSON) 部署 建议先在仓库目录复制模板并填写:\ncp config.example.json config.json # 编辑 config.json 推荐:先本地把 config.json 转成 Base64,再粘贴到 DS2API_CONFIG_JSON,避免 JSON 格式错误:\nbase64 \u0026lt; config.json | tr -d \u0026#39;\\n\u0026#39; 流式说明:/v1/chat/completions 在 Vercel 上默认走 api/chat-stream.js(Node Runtime)以保证实时 SSE。鉴权、账号选择、会话/PoW 准备仍由 Go 内部 prepare 接口完成;流式响应(含 tools)在 Node 侧执行与 Go 对齐的输出组装与防泄漏处理。\n详细部署说明请参阅 部署指南。\n方式四:本地源码运行 #前置要求:Go 1.26+,Node.js 20.19+ 或 22.12+(仅在需要构建 WebUI 时)\n# 1. 克隆仓库 git clone https://github.com/CJackHwang/ds2api.git cd ds2api # 2. 配置 cp config.example.json config.json # 编辑 config.json,填入你的 DeepSeek 账号信息和 API key # 3. 启动 go run ./cmd/ds2api 默认本地访问地址:http://127.0.0.1:5001\n服务实际绑定:0.0.0.0:5001,因此同一局域网设备通常也可以通过你的内网 IP 访问。\nWebUI 自动构建:本地首次启动时,若 static/admin 不存在,会自动尝试执行 npm ci(仅在缺少依赖时)和 npm run build -- --outDir static/admin --emptyOutDir(需要本机有 Node.js)。你也可以手动构建:./scripts/build-webui.sh\n配置说明 #config.json 示例 #{ \u0026#34;keys\u0026#34;: [\u0026#34;your-api-key-1\u0026#34;, \u0026#34;your-api-key-2\u0026#34;], \u0026#34;accounts\u0026#34;: [ { \u0026#34;email\u0026#34;: \u0026#34;user@example.com\u0026#34;, \u0026#34;password\u0026#34;: \u0026#34;your-password\u0026#34; }, { \u0026#34;mobile\u0026#34;: \u0026#34;12345678901\u0026#34;, \u0026#34;password\u0026#34;: \u0026#34;your-password\u0026#34; } ], \u0026#34;model_aliases\u0026#34;: { \u0026#34;gpt-4o\u0026#34;: \u0026#34;deepseek-chat\u0026#34;, \u0026#34;gpt-5\u0026#34;: \u0026#34;deepseek-chat\u0026#34;, \u0026#34;gpt-5-mini\u0026#34;: \u0026#34;deepseek-chat\u0026#34;, \u0026#34;gpt-5-codex\u0026#34;: \u0026#34;deepseek-reasoner\u0026#34;, \u0026#34;o3\u0026#34;: \u0026#34;deepseek-reasoner\u0026#34;, \u0026#34;claude-opus-4-6\u0026#34;: \u0026#34;deepseek-reasoner\u0026#34;, \u0026#34;gemini-2.5-flash\u0026#34;: \u0026#34;deepseek-chat\u0026#34; }, \u0026#34;compat\u0026#34;: { \u0026#34;wide_input_strict_output\u0026#34;: true, \u0026#34;strip_reference_markers\u0026#34;: true }, \u0026#34;responses\u0026#34;: { \u0026#34;store_ttl_seconds\u0026#34;: 900 }, \u0026#34;embeddings\u0026#34;: { \u0026#34;provider\u0026#34;: \u0026#34;deterministic\u0026#34; }, \u0026#34;claude_mapping\u0026#34;: { \u0026#34;fast\u0026#34;: \u0026#34;deepseek-chat\u0026#34;, \u0026#34;slow\u0026#34;: \u0026#34;deepseek-reasoner\u0026#34; }, \u0026#34;admin\u0026#34;: { \u0026#34;jwt_expire_hours\u0026#34;: 24 }, \u0026#34;runtime\u0026#34;: { \u0026#34;account_max_inflight\u0026#34;: 2, \u0026#34;account_max_queue\u0026#34;: 0, \u0026#34;global_max_inflight\u0026#34;: 0, \u0026#34;token_refresh_interval_hours\u0026#34;: 6 }, \u0026#34;auto_delete\u0026#34;: { \u0026#34;mode\u0026#34;: \u0026#34;none\u0026#34; } } keys:API 访问密钥列表,客户端通过 Authorization: Bearer \u0026lt;key\u0026gt; 鉴权 accounts:DeepSeek 账号列表,支持 email 或 mobile 登录 token:配置文件中即使填写也会在加载时被清空(不会从 config.json 读取 token);实际 token 仅在运行时内存中维护并自动刷新 model_aliases:常见模型名(如 GPT/Codex/Claude)到 DeepSeek 模型的映射 compat.wide_input_strict_output:建议保持 true(当前实现默认宽进严出) compat.strip_reference_markers:建议保持 true,用于清理可见输出中的引用/标记 toolcall:旧字段,当前实现已固定为特征匹配 + 高置信早发;即使保留在配置里也会被忽略 responses.store_ttl_seconds:/v1/responses/{id} 的内存缓存 TTL embeddings.provider:embedding 提供方(当前内置 deterministic/mock/builtin) claude_mapping:字典中 fast/slow 后缀映射到对应 DeepSeek 模型(兼容读取 claude_model_mapping) admin:管理后台设置(JWT 过期时间、密码哈希等),可通过 Admin Settings API 热更新 runtime:运行时参数(并发限制、队列大小、托管账号 token 刷新间隔),可通过 Admin Settings API 热更新;account_max_queue=0/global_max_inflight=0 表示按推荐值自动计算,token_refresh_interval_hours=6 为默认强制重登间隔 auto_delete.mode:请求结束后如何清理 DeepSeek 远端聊天记录,支持 none(默认,不删除)、single(仅删除当前会话)、all(清空全部会话);旧配置里的 auto_delete.sessions=true 仍会被视为 all 环境变量 # 变量 用途 默认值 PORT 服务端口 5001 LOG_LEVEL 日志级别 INFO(可选:DEBUG/WARN/ERROR) DS2API_ADMIN_KEY Admin 登录密钥 admin DS2API_JWT_SECRET Admin JWT 签名密钥 等同 DS2API_ADMIN_KEY DS2API_JWT_EXPIRE_HOURS Admin JWT 过期小时数 24 DS2API_CONFIG_PATH 配置文件路径 config.json DS2API_CONFIG_JSON 直接注入配置(JSON 或 Base64) — DS2API_ENV_WRITEBACK 环境变量模式下自动写回配置文件并切换文件模式(1/true/yes/on) 关闭 DS2API_STATIC_ADMIN_DIR 管理台静态文件目录 static/admin DS2API_AUTO_BUILD_WEBUI 启动时自动构建 WebUI 本地开启,Vercel 关闭 DS2API_DEV_PACKET_CAPTURE 本地开发抓包开关(记录最近会话请求/响应体) 本地非 Vercel 默认开启 DS2API_DEV_PACKET_CAPTURE_LIMIT 本地抓包保留条数(超出自动淘汰) 20 DS2API_DEV_PACKET_CAPTURE_MAX_BODY_BYTES 单条响应体最大记录字节数 5242880 DS2API_ACCOUNT_MAX_INFLIGHT 每账号最大并发 in-flight 请求数 2 DS2API_ACCOUNT_MAX_QUEUE 等待队列上限 recommended_concurrency DS2API_GLOBAL_MAX_INFLIGHT 全局最大 in-flight 请求数 recommended_concurrency DS2API_VERCEL_INTERNAL_SECRET Vercel 混合流式内部鉴权密钥 回退用 DS2API_ADMIN_KEY DS2API_VERCEL_STREAM_LEASE_TTL_SECONDS 流式 lease 过期秒数 900 VERCEL_TOKEN Vercel 同步 token — VERCEL_PROJECT_ID Vercel 项目 ID — VERCEL_TEAM_ID Vercel 团队 ID — DS2API_VERCEL_PROTECTION_BYPASS Vercel 部署保护绕过密钥(内部 Node→Go 调用) — 提示:当检测到 DS2API_CONFIG_JSON 时,管理台会显示当前模式风险与自动持久化状态(含 DS2API_CONFIG_PATH 路径与模式切换说明)。\n鉴权模式 #调用业务接口(/v1/*、/anthropic/*、Gemini 路由)时支持两种模式:\n模式 说明 托管账号模式 Bearer 或 x-api-key 传入 config.keys 中的 key,由服务自动轮询选择账号 直通 token 模式 传入 token 不在 config.keys 中时,直接作为 DeepSeek token 使用 可选请求头 X-Ds2-Target-Account:指定使用某个托管账号(值为 email 或 mobile)。 Gemini 路由还可以使用 x-goog-api-key,或在没有认证头时使用 ?key= / ?api_key= 作为调用方凭据。\n并发模型 #每账号可用并发 = DS2API_ACCOUNT_MAX_INFLIGHT(默认 2) 建议并发值 = 账号数量 × 每账号并发上限 等待队列上限 = DS2API_ACCOUNT_MAX_QUEUE(默认 = 建议并发值) 429 阈值 = in-flight + 等待队列 ≈ 账号数量 × 4 当 in-flight 槽位满时,请求进入等待队列,不会立即 429 超出总承载上限后才返回 429 Too Many Requests GET /admin/queue/status 返回实时并发状态 Tool Call 适配 #当请求中带 tools 时,DS2API 会做防泄漏处理与结构化转译:\n只在非代码块上下文启用执行型 toolcall 识别(代码块示例默认不触发) 解析层当前以 XML/Markup 家族为准(\u0026lt;tool_call\u0026gt; / \u0026lt;function_call\u0026gt; / \u0026lt;invoke\u0026gt; / tool_use / antml 变体);纯 JSON tool_calls 片段默认不作为可执行调用解析 responses 流式严格使用官方 item 生命周期事件(response.output_item.*、response.content_part.*、response.function_call_arguments.*) responses 支持并执行 tool_choice(auto/none/required/强制函数);required 违规时非流式返回 422,流式返回 response.failed 客户端请求哪种协议,就按该协议返回工具调用(OpenAI/Claude/Gemini 各自原生结构);模型侧优先约束输出规范 XML,再由兼容层转译 说明:当前版本在 parser 层仍以“尽量解析成功”为优先,未启用基于 allow-list 的工具名硬拒绝。\n想评估“把工具调用封装成 XML 再输入模型”的方案,可参考:docs/toolcall-semantics.md。\n本地开发抓包工具 #用于定位「responses 思考流/工具调用」等问题。开启后会自动记录最近 N 条 DeepSeek 对话上游请求体与响应体(默认 20 条,超出自动淘汰;单条响应体默认最多记录 5 MB)。\n启用示例:\nDS2API_DEV_PACKET_CAPTURE=true \\ DS2API_DEV_PACKET_CAPTURE_LIMIT=20 \\ go run ./cmd/ds2api 查询/清空(需 Admin JWT):\nGET /admin/dev/captures:查看抓包列表(最新在前) DELETE /admin/dev/captures:清空抓包 GET /admin/dev/raw-samples/query?q=关键词\u0026amp;limit=20:按问题关键词查询当前内存抓包,并按 chat_session_id 归并 completion + continue 链 POST /admin/dev/raw-samples/save:把命中的某条抓包链保存为 tests/raw_stream_samples/\u0026lt;sample-id\u0026gt;/ 回放样本 返回字段包含:\nrequest_body:发送给 DeepSeek 的完整请求体 response_body:上游返回的原始流式内容拼接文本 response_truncated:是否触发单条大小截断 保存接口支持用 query、chain_key 或 capture_id 选中目标。例如:\n{\u0026#34;query\u0026#34;:\u0026#34;广州天气\u0026#34;,\u0026#34;sample_id\u0026#34;:\u0026#34;gz-weather-from-memory\u0026#34;} 文档索引 # 文档 说明 API.md / API.en.md API 接口文档(含请求/响应示例) DEPLOY.md / DEPLOY.en.md 部署指南(本地/Docker/Vercel/systemd) CONTRIBUTING.md / CONTRIBUTING.en.md 贡献指南 TESTING.md 测试集使用指南 测试 ## 单元测试(Go + Node) ./tests/scripts/run-unit-all.sh # 一键端到端全链路测试(真实账号,生成完整请求/响应日志) ./tests/scripts/run-live.sh # 或自定义参数 go run ./cmd/ds2api-tests \\ --config config.json \\ --admin-key admin \\ --out artifacts/testsuite \\ --timeout 120 \\ --retries 2 # 发布前阻断门禁 ./tests/scripts/check-stage6-manual-smoke.sh ./tests/scripts/check-refactor-line-gate.sh ./tests/scripts/run-unit-all.sh npm ci --prefix webui \u0026amp;\u0026amp; npm run build --prefix webui 测试 #详细测试指南请参阅 docs/TESTING.md。\n快速测试命令 ## 运行所有单元测试 go test ./... # 运行 tool calls 相关测试(调试工具调用问题) go test -v -run \u0026#39;TestParseToolCalls|TestRepair\u0026#39; ./internal/toolcall/ # 运行端到端测试 ./tests/scripts/run-live.sh Release 自动构建(GitHub Actions) #工作流文件:.github/workflows/release-artifacts.yml\n触发条件:仅在 GitHub Release published 时触发(普通 push 不会触发) 构建产物:多平台二进制包(linux/amd64、linux/arm64、darwin/amd64、darwin/arm64、windows/amd64)+ sha256sums.txt 容器镜像发布:仅推送到 GHCR(ghcr.io/cjackhwang/ds2api) 每个压缩包包含:ds2api 可执行文件、static/admin、WASM 文件(同时支持内置 fallback)、配置示例、README、LICENSE 免责声明 #本项目基于逆向方式实现,仅供学习、研究、个人实验和内部验证使用,不提供任何商业授权、稳定性保证或可用性保证。作者及仓库维护者不对因使用、修改、分发、部署或依赖本项目而产生的任何直接或间接损失、账号封禁、数据丢失、法律风险或第三方索赔负责。\n请勿将本项目用于违反服务条款、协议、法律法规或平台规则的场景。商业使用前请自行确认 LICENSE、相关协议以及你是否获得了作者的书面许可。\n","date":"2026年0月180日","permalink":"http://blog.hys.my/posts/ds2api/","section":"最近笔记","summary":"将 DeepSeek Web 对话能力转换为 OpenAI、Claude 与 Gemini 兼容 API。后端为 \u003cstrong\u003eGo 全量实现\u003c/strong\u003e,前端为 React WebUI 管理台。","title":"DS2API说明文档"},{"content":"","date":null,"permalink":"http://blog.hys.my/categories/firefox/","section":"Categories","summary":"","title":"Firefox"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/gemini%E5%85%BC%E5%AE%B9api/","section":"Tags","summary":"","title":"Gemini兼容API"},{"content":"您好!我是华禹,一位服务器运维工程师,对将统计方法应用于真实世界的医疗数据充满热情。我的研究兴趣在于高级统计分析与医学研究的交叉领域,旨在通过可靠的数据解读来提升科学进程。\n浏览我的网站,了解更多关于我的研究、咨询服务和专业经验的信息。\n进入 ","date":null,"permalink":"http://blog.hys.my/","section":"Home","summary":"\u003cp\u003e您好!我是华禹,一位服务器运维工程师,对将统计方法应用于真实世界的医疗数据充满热情。我的研究兴趣在于高级统计分析与医学研究的交叉领域,旨在通过可靠的数据解读来提升科学进程。\u003c/p\u003e","title":"Home"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/minio/","section":"Tags","summary":"","title":"MinIO"},{"content":"一、概述 #1.1 背景介绍 #非结构化数据的爆发式增长让传统文件存储和块存储越来越力不从心。图片、视频、日志、备份文件这类对象动辄 TB 甚至 PB 级别,传统 NAS 在扩展性和并发访问上存在天花板,而块存储(如 Ceph RBD、EBS)虽然性能好,但不适合海量小文件和 HTTP 直接访问的场景。\n对象存储通过扁平化的命名空间(Bucket + Object Key)取代了目录树结构,天然适合海量非结构化数据。AWS S3 定义了事实上的对象存储 API 标准,但公有云存储在数据主权、网络延迟和长期成本上并不总是最优解。\nMinIO 是目前最成熟的 S3 兼容私有化对象存储方案。它用 Go 语言编写,单个二进制文件部署,没有外部依赖,性能在同类产品中领先。MinIO 完整实现了 S3 API(包括 Select、Encryption、Versioning、Object Lock 等),绝大多数 S3 SDK 和工具可以零修改对接。\n三种存储类型的核心差异:\n对比维度 块存储 文件存储 对象存储 访问方式 设备级(/dev/sdb) 文件路径(POSIX) HTTP API(REST) 数据单位 固定大小块 文件 + 目录树 对象 + 元数据 扩展性 纵向为主 受限于 NAS 控制器 水平无限扩展 典型场景 数据库、虚拟机磁盘 共享文件、NFS 挂载 图片视频、备份、日志归档 元数据 无 有限(权限、时间戳) 丰富(自定义 KV) S3 API 兼容性原理:MinIO 在 HTTP 层实现了与 AWS S3 相同的 REST 接口规范,包括签名认证(AWS Signature V4)、分段上传(Multipart Upload)、预签名 URL 等。客户端只需将 endpoint 从 s3.amazonaws.com 改为 MinIO 地址,其余代码不需要任何改动。\n1.2 技术特点 # S3 完整兼容:支持 S3 API 的绝大多数功能,包括 Multipart Upload、Versioning、Object Lock、Server-Side Encryption、S3 Select 纠删码(Erasure Coding):数据被切分为数据块和校验块分散存储,在不做完整副本的前提下提供冗余,磁盘利用率远高于三副本方案 零依赖部署:单个 Go 二进制文件,不依赖数据库、ZooKeeper 或其他外部组件 高性能:充分利用多核 CPU 和 NVMe SSD,单集群可达数十 GB/s 吞吐 Bucket Notification:支持 Webhook、Kafka、AMQP、Redis 等事件通知,便于构建数据管道 Identity Management:集成 LDAP、OpenID Connect、Keycloak 等外部身份源 1.3 适用场景 # 应用系统的图片、视频、文档等非结构化数据存储,替代 NFS 共享目录 数据库备份、日志归档的统一存储后端,配合生命周期策略自动清理过期数据 AI/ML 训练数据集存储,利用 S3 API 与 PyTorch、TensorFlow 数据加载器直接对接 私有化 Docker Registry 或 Helm Chart 仓库的后端存储 替代公有云 S3,满足数据主权合规要求(金融、医疗、政务场景) 1.4 环境要求 # 组件 版本要求 说明 操作系统 Ubuntu 22.04+ / CentOS 8+ 推荐 Ubuntu 22.04 LTS MinIO Server RELEASE.2025-xx 使用最新稳定版,避免旧版已知 Bug MinIO Client (mc) RELEASE.2025-xx 与 Server 版本保持同期 硬件配置 4C8G 起步 生产环境建议 8C16G,纠删码集群每节点至少 4 块磁盘 磁盘 XFS 格式化 MinIO 强烈推荐 XFS,ext4 在大量小文件场景下性能衰减明显 网络 节点间万兆网络 纠删码集群的数据分片需要节点间高带宽 二、详细步骤 #2.1 单节点部署 #2.1.1 下载安装 ## 下载 MinIO 二进制文件 wget https://dl.min.io/server/minio/release/linux-amd64/minio chmod +x minio sudo mv minio /usr/local/bin/ # 验证版本 minio --version 2.1.2 创建数据目录和系统用户 ## 创建专用系统用户,不允许登录 sudo useradd -r -s /sbin/nologin minio-user # 创建数据目录(生产环境应使用独立磁盘挂载点) sudo mkdir -p /data/minio sudo chown minio-user:minio-user /data/minio 2.1.3 环境变量配置 ## /etc/default/minio - MinIO 环境变量配置 # 管理员账号(至少 3 个字符) MINIO_ROOT_USER=minioadmin # 管理员密码(至少 8 个字符,生产环境务必修改) MINIO_ROOT_PASSWORD=Change-Me-2025! # 数据存储路径 MINIO_VOLUMES=\u0026#34;/data/minio\u0026#34; # 监听地址,0.0.0.0 表示所有网卡 MINIO_OPTS=\u0026#34;--address :9000 --console-address :9001\u0026#34; 2.1.4 systemd 服务配置 ## /etc/systemd/system/minio.service [Unit] Description=MinIO Object Storage Documentation=https://min.io/docs After=network-online.target Wants=network-online.target [Service] User=minio-user Group=minio-user EnvironmentFile=/etc/default/minio ExecStart=/usr/local/bin/minio server $MINIO_VOLUMES $MINIO_OPTS Restart=always RestartSec=5 LimitNOFILE=65536 # 禁止 OOM Killer 杀掉 MinIO 进程 OOMScoreAdjust=-500 TasksMax=infinity TimeoutStopSec=infinity SendSIGKILL=no [Install] WantedBy=multi-user.target # 启动服务 sudo systemctl daemon-reload sudo systemctl enable --now minio # 验证状态 sudo systemctl status minio curl -s http://localhost:9000/minio/health/live # 预期返回空 body,HTTP 200 单节点模式没有纠删码保护,任何磁盘故障都会导致数据丢失,仅适合开发测试环境。\n2.2 纠删码多节点集群部署 #2.2.1 纠删码原理 #MinIO 的纠删码基于 Reed-Solomon 算法。以 4 节点、每节点 4 块磁盘(共 16 块)为例,默认配置下数据被切分为 8 个数据块 + 8 个校验块。这意味着集群可以容忍任意 8 块磁盘同时故障而不丢数据,磁盘利用率 50%(对比三副本的 33%)。\n纠删码集合(Erasure Set)的大小由磁盘总数决定。MinIO 自动计算最优的纠删码集合划分,管理员不需要手动配置。\n2.2.2 集群规划 #节点\nIP\n磁盘\n挂载点\nminio-1\n192.168.10.11\n4 × NVMe SSD\n/data/disk{1..4}\nminio-2\n192.168.10.12\n4 × NVMe SSD\n/data/disk{1..4}\nminio-3\n192.168.10.13\n4 × NVMe SSD\n/data/disk{1..4}\nminio-4\n192.168.10.14\n4 × NVMe SSD\n/data/disk{1..4}\n2.2.3 所有节点磁盘准备 ## 在每个节点上执行(以 disk1 为例,disk2-4 同理) # 使用 XFS 格式化,MinIO 官方推荐 sudo mkfs.xfs /dev/nvme0n1 sudo mkfs.xfs /dev/nvme1n1 sudo mkfs.xfs /dev/nvme2n1 sudo mkfs.xfs /dev/nvme3n1 # 创建挂载点 sudo mkdir -p /data/disk{1,2,3,4} # 写入 fstab 持久化挂载 # noatime 减少元数据写入,提升性能 cat \u0026lt;\u0026lt;\u0026#39;EOF\u0026#39; | sudo tee -a /etc/fstab /dev/nvme0n1 /data/disk1 xfs defaults,noatime 0 2 /dev/nvme1n1 /data/disk2 xfs defaults,noatime 0 2 /dev/nvme2n1 /data/disk3 xfs defaults,noatime 0 2 /dev/nvme3n1 /data/disk4 xfs defaults,noatime 0 2 EOF sudo mount -a sudo chown minio-user:minio-user /data/disk{1,2,3,4} 2.2.4 集群环境变量 ## /etc/default/minio - 4节点纠删码集群配置(所有节点相同) MINIO_ROOT_USER=minioadmin MINIO_ROOT_PASSWORD=Change-Me-2025! # 纠删码集群卷定义 # {1...4} 是 MinIO 的展开语法(三个点),不是 bash 的 {1..4}(两个点) MINIO_VOLUMES=\u0026#34;http://minio-{1...4}.example.com:9000/data/disk{1...4}\u0026#34; # 服务器发现用的域名(可选,用于自动 TLS 证书) MINIO_SERVER_URL=\u0026#34;https://minio.example.com:9000\u0026#34; MINIO_OPTS=\u0026#34;--address :9000 --console-address :9001\u0026#34; 关键说明:{1...4} 是 MinIO 自己的展开语法,三个点,不要和 bash 的 {1..4} 搞混。MinIO 会在内部展开为 minio-1.example.com 到 minio-4.example.com。\n# 配置 DNS 解析(或 /etc/hosts) cat \u0026lt;\u0026lt;\u0026#39;EOF\u0026#39; | sudo tee -a /etc/hosts 192.168.10.11 minio-1.example.com 192.168.10.12 minio-2.example.com 192.168.10.13 minio-3.example.com 192.168.10.14 minio-4.example.com EOF # 在所有节点上启动 sudo systemctl enable --now minio 2.2.5 集群健康检查 ## 存活检查 curl -s http://minio-1.example.com:9000/minio/health/live # 集群就绪检查(所有节点在线才返回 200) curl -s http://minio-1.example.com:9000/minio/health/cluster # 查看集群信息(需要 mc 客户端) mc admin info myminio 2.3 TLS 证书配置 #MinIO 支持自动加载 ~/.minio/certs/ 目录下的证书文件。\n# 创建证书目录 sudo mkdir -p /home/minio-user/.minio/certs sudo mkdir -p /home/minio-user/.minio/certs/CAs # 复制证书文件(文件名必须是 public.crt 和 private.key) sudo cp /path/to/fullchain.pem /home/minio-user/.minio/certs/public.crt sudo cp /path/to/privkey.pem /home/minio-user/.minio/certs/private.key # 如果使用自签名 CA,将 CA 证书放入 CAs 目录 sudo cp /path/to/ca.crt /home/minio-user/.minio/certs/CAs/ # 修正权限 sudo chown -R minio-user:minio-user /home/minio-user/.minio sudo chmod 600 /home/minio-user/.minio/certs/private.key # 重启 MinIO 加载证书 sudo systemctl restart minio 启用 TLS 后,MinIO 自动监听 HTTPS。环境变量中的 http:// 需要改为 https://,mc 客户端连接时也需要使用 https://。\n对于纠删码集群,每个节点都需要配置证书。如果使用内部 CA 签发,所有节点的 CAs 目录都要放入 CA 证书,否则节点间 TLS 握手会失败。\n2.4 mc 客户端操作 #2.4.1 安装与配置 ## 下载 mc 客户端 wget https://dl.min.io/client/mc/release/linux-amd64/mc chmod +x mc sudo mv mc /usr/local/bin/ # 配置别名(alias) mc alias set myminio https://minio.example.com:9000 minioadmin \u0026#39;Change-Me-2025!\u0026#39; # 验证连接 mc admin info myminio 2.4.2 常用操作 ## Bucket 操作 mc mb myminio/my-bucket # 创建 Bucket mc ls myminio # 列出所有 Bucket mc rb myminio/old-bucket --force # 删除 Bucket(含内容) # 对象操作 mc cp localfile.tar.gz myminio/my-bucket/ # 上传文件 mc cp myminio/my-bucket/file.tar.gz ./ # 下载文件 mc ls myminio/my-bucket --recursive # 递归列出对象 mc rm myminio/my-bucket/old-file.log # 删除对象 mc cat myminio/my-bucket/config.yaml # 查看对象内容 # 批量操作 mc cp --recursive ./logs/ myminio/my-bucket/logs/ # 递归上传目录 mc mirror ./data myminio/my-bucket/data # 目录镜像同步 # 管理操作 mc admin user add myminio app-user App-Pass-2025! # 创建用户 mc admin policy attach myminio readwrite --user app-user # 绑定策略 mc admin trace myminio # 实时请求追踪(调试用) 三、示例代码和配置 #3.1 Bucket Policy 配置 #3.1.1 公开只读策略 #适用于静态资源 CDN 回源场景,允许匿名用户读取指定 Bucket 的所有对象:\n{ \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Principal\u0026#34;: {\u0026#34;AWS\u0026#34;: [\u0026#34;*\u0026#34;]}, \u0026#34;Action\u0026#34;: [\u0026#34;s3:GetObject\u0026#34;], \u0026#34;Resource\u0026#34;: [\u0026#34;arn:aws:s3:::static-assets/*\u0026#34;] } ] } # 应用策略 mc anonymous set-json public-read.json myminio/static-assets 3.1.2 应用专用读写策略 #限制特定用户只能访问指定 Bucket 前缀:\n{ \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Action\u0026#34;: [ \u0026#34;s3:PutObject\u0026#34;, \u0026#34;s3:GetObject\u0026#34;, \u0026#34;s3:DeleteObject\u0026#34;, \u0026#34;s3:ListBucket\u0026#34; ], \u0026#34;Resource\u0026#34;: [ \u0026#34;arn:aws:s3:::app-data\u0026#34;, \u0026#34;arn:aws:s3:::app-data/uploads/*\u0026#34; ] } ] } # 创建自定义策略并绑定用户 mc admin policy create myminio app-rw-policy app-rw-policy.json mc admin policy attach myminio app-rw-policy --user app-user 3.2 生命周期管理脚本 ##!/bin/bash set -euo pipefail # minio-lifecycle.sh - MinIO Bucket 生命周期管理脚本 # 功能:为指定 Bucket 配置对象过期策略,自动清理过期数据 # 用法:./minio-lifecycle.sh \u0026lt;bucket-name\u0026gt; \u0026lt;prefix\u0026gt; \u0026lt;expire-days\u0026gt; # ============ 参数定义 ============ MINIO_ALIAS=\u0026#34;myminio\u0026#34; BUCKET_NAME=\u0026#34;${1:?用法: $0 \u0026lt;bucket-name\u0026gt; \u0026lt;prefix\u0026gt; \u0026lt;expire-days\u0026gt;}\u0026#34; PREFIX=\u0026#34;${2:?请指定对象前缀,例如 logs/}\u0026#34; EXPIRE_DAYS=\u0026#34;${3:?请指定过期天数,例如 30}\u0026#34; # ============ 参数校验 ============ if ! [[ \u0026#34;$EXPIRE_DAYS\u0026#34; =~ ^[0-9]+$ ]] || [ \u0026#34;$EXPIRE_DAYS\u0026#34; -lt 1 ]; then echo \u0026#34;[错误] 过期天数必须为正整数: $EXPIRE_DAYS\u0026#34; exit 1 fi # 检查 mc 客户端是否可用 if ! command -v mc \u0026amp;\u0026gt;/dev/null; then echo \u0026#34;[错误] mc 客户端未安装,请先安装 MinIO Client\u0026#34; exit 1 fi # 检查 Bucket 是否存在 if ! mc ls \u0026#34;${MINIO_ALIAS}/${BUCKET_NAME}\u0026#34; \u0026amp;\u0026gt;/dev/null; then echo \u0026#34;[错误] Bucket 不存在: ${BUCKET_NAME}\u0026#34; exit 1 fi # ============ 配置生命周期规则 ============ RULE_ID=\u0026#34;auto-expire-${PREFIX//\\//-}-${EXPIRE_DAYS}d\u0026#34; echo \u0026#34;[信息] 正在为 ${BUCKET_NAME}/${PREFIX} 配置 ${EXPIRE_DAYS} 天过期策略...\u0026#34; # 添加生命周期规则 mc ilm rule add \u0026#34;${MINIO_ALIAS}/${BUCKET_NAME}\u0026#34; \\ --prefix \u0026#34;${PREFIX}\u0026#34; \\ --expire-days \u0026#34;${EXPIRE_DAYS}\u0026#34; \\ --tags \u0026#34;managed-by=lifecycle-script\u0026#34; echo \u0026#34;[信息] 生命周期规则配置完成\u0026#34; # ============ 验证配置 ============ echo \u0026#34;[信息] 当前生命周期规则:\u0026#34; mc ilm rule ls \u0026#34;${MINIO_ALIAS}/${BUCKET_NAME}\u0026#34; # ============ 统计待清理对象 ============ echo \u0026#34;[信息] 统计 ${PREFIX} 下超过 ${EXPIRE_DAYS} 天的对象数量...\u0026#34; OLDER_THAN=\u0026#34;${EXPIRE_DAYS}d\u0026#34; OBJECT_COUNT=$(mc find \u0026#34;${MINIO_ALIAS}/${BUCKET_NAME}/${PREFIX}\u0026#34; \\ --older-than \u0026#34;${OLDER_THAN}\u0026#34; 2\u0026gt;/dev/null | wc -l || true) echo \u0026#34;[信息] 预计将在下次扫描周期清理约 ${OBJECT_COUNT} 个过期对象\u0026#34; echo \u0026#34;[完成] 脚本执行结束\u0026#34; 3.3 Nginx 反向代理 + HTTPS 卸载 ## /etc/nginx/conf.d/minio.conf # MinIO 反向代理配置 - HTTPS 卸载 + 负载均衡 # MinIO API 后端(9000 端口) upstream minio_api { # 最少连接数负载均衡 least_conn; server 192.168.10.11:9000; server 192.168.10.12:9000; server 192.168.10.13:9000; server 192.168.10.14:9000; } # MinIO Console 后端(9001 端口) upstream minio_console { least_conn; server 192.168.10.11:9001; server 192.168.10.12:9001; server 192.168.10.13:9001; server 192.168.10.14:9001; } # S3 API 入口 server { listen 443 ssl http2; server_name minio.example.com; # TLS 证书 ssl_certificate /etc/nginx/ssl/minio.example.com.crt; ssl_certificate_key /etc/nginx/ssl/minio.example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; # 允许大文件上传(5GB 分段上传) client_max_body_size 5G; # 关闭缓冲,避免大文件上传时 Nginx 占用过多内存 proxy_buffering off; proxy_request_buffering off; location / { proxy_pass http://minio_api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # S3 签名依赖 Host 头,必须透传 proxy_set_header Host $http_host; # 长连接支持 proxy_http_version 1.1; proxy_set_header Connection \u0026#34;\u0026#34;; # 超时设置(大文件上传需要较长超时) proxy_connect_timeout 300s; proxy_read_timeout 300s; proxy_send_timeout 300s; } } # Console 管理界面入口 server { listen 443 ssl http2; server_name console.minio.example.com; ssl_certificate /etc/nginx/ssl/minio.example.com.crt; ssl_certificate_key /etc/nginx/ssl/minio.example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; # Console 上传文件也需要较大 body 限制 client_max_body_size 5G; # 限制 Console 访问来源(可选) # allow 10.0.0.0/8; # deny all; location / { proxy_pass http://minio_console; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_http_version 1.1; # WebSocket 支持(Console 实时日志需要) proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection \u0026#34;upgrade\u0026#34;; } } # HTTP 跳转 HTTPS server { listen 80; server_name minio.example.com console.minio.example.com; return 301 https://$host$request_uri; } # 验证 Nginx 配置 sudo nginx -t # 重载配置 sudo systemctl reload nginx 3.4 MinIO 环境变量配置完整参考 ## /etc/default/minio - 生产环境完整配置参考 # ============ 认证 ============ MINIO_ROOT_USER=minioadmin MINIO_ROOT_PASSWORD=Change-Me-2025! # ============ 存储 ============ MINIO_VOLUMES=\u0026#34;http://minio-{1...4}.example.com:9000/data/disk{1...4}\u0026#34; # ============ 网络 ============ # 对外暴露的 URL(经过负载均衡器后的地址) MINIO_SERVER_URL=\u0026#34;https://minio.example.com\u0026#34; # Console 对外 URL MINIO_BROWSER_REDIRECT_URL=\u0026#34;https://console.minio.example.com\u0026#34; # ============ 区域 ============ MINIO_SITE_REGION=\u0026#34;cn-east-1\u0026#34; # ============ 日志 ============ # 审计日志推送到 Webhook # MINIO_AUDIT_WEBHOOK_ENABLE_target1=\u0026#34;on\u0026#34; # MINIO_AUDIT_WEBHOOK_ENDPOINT_target1=\u0026#34;http://logstash:8080/minio-audit\u0026#34; # ============ 启动参数 ============ MINIO_OPTS=\u0026#34;--address :9000 --console-address :9001\u0026#34; 四、最佳实践和注意事项 #4.1 最佳实践 #4.1.1 纠删码选择与硬件规划 #MinIO 的纠删码(Erasure Coding)直接决定集群的容错能力和可用存储比例,选型需在冗余度与空间利用率之间权衡:\n配置\n数据盘:校验盘\n最大容忍故障盘数\n存储利用率\n适用场景\nEC:4\n12:4\n4\n75%\n开发测试、非关键业务\nEC:8\n8:8\n8\n50%\n金融合规、医疗影像等高可靠场景\nEC:16\n16:16\n16\n50%\n超大规模归档,极端容灾需求\n生产环境默认 EC:N/2 即可满足多数需求。若业务对存储成本敏感且可接受较低冗余,可通过 --parity 参数降低校验盘数量。\n磁盘类型选择:\n磁盘类型\n随机读写 IOPS\n顺序吞吐\n单位成本\n推荐场景\nNVMe SSD\n500K+\n3-7 GB/s\n高\n元数据密集、小文件高并发\nSATA SSD\n50-90K\n500-550 MB/s\n中\n混合负载、中等并发\nHDD (7200rpm)\n100-200\n150-200 MB/s\n低\n大文件归档、冷数据存储\nJBOD vs RAID 对比:\n方案\n优势\n劣势\n建议\nJBOD 直通\nMinIO 纠删码直接管理磁盘,单盘故障仅影响该盘数据修复\n无硬件级缓存加速\n生产环境强烈推荐\n硬件 RAID\n有 BBU 写缓存可提升小 IO 性能\nRAID 重建期间整组性能下降,写放大严重,与纠删码功能重叠\n仅在遗留硬件无法关闭 RAID 时使用\n4.1.2 安全加固 #IAM Policy 最小权限原则:为每个应用创建独立 Service Account,绑定精确到 Bucket + 前缀的 Policy:\n{ \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Action\u0026#34;: [\u0026#34;s3:GetObject\u0026#34;, \u0026#34;s3:PutObject\u0026#34;], \u0026#34;Resource\u0026#34;: [\u0026#34;arn:aws:s3:::app-data/uploads/*\u0026#34;] }, { \u0026#34;Effect\u0026#34;: \u0026#34;Deny\u0026#34;, \u0026#34;Action\u0026#34;: [\u0026#34;s3:DeleteBucket\u0026#34;, \u0026#34;s3:PutBucketPolicy\u0026#34;], \u0026#34;Resource\u0026#34;: [\u0026#34;arn:aws:s3:::*\u0026#34;] } ] } 禁用匿名访问:默认情况下 MinIO 不允许匿名访问,但需确认没有人为设置 public Policy:\n# 检查所有 Bucket 的匿名策略 mc anonymous list myminio --recursive # 如发现异常,立即移除 mc anonymous set none myminio/bucket-name 启用 Object Lock(对象锁定):对合规性要求高的场景,在创建 Bucket 时启用:\n# 创建时必须指定 --with-lock,事后无法追加 mc mb myminio/compliance-data --with-lock # 设置默认保留策略:合规模式,保留 365 天 mc retention set --default COMPLIANCE 365d myminio/compliance-data 审计日志:将操作审计日志推送至外部系统,便于安全审计和事件溯源:\n# 配置审计日志 Webhook mc admin config set myminio audit_webhook:elk \\ endpoint=\u0026#34;http://logstash:8080/minio-audit\u0026#34; \\ queue_size=10000 # 重启生效 mc admin service restart myminio 4.1.3 多租户隔离 #MinIO 不提供原生的\u0026quot;租户\u0026quot;概念,但可通过 IAM User + Bucket + Policy 组合实现逻辑隔离:\n# 为租户 A 创建专属用户 mc admin user add myminio tenant-a-svc \u0026#39;T3nantA-P@ss!\u0026#39; # 创建租户专属 Bucket mc mb myminio/tenant-a-data # 编写隔离策略:仅允许访问自己的 Bucket cat \u0026gt; /tmp/tenant-a-policy.json \u0026lt;\u0026lt; \u0026#39;POLICY\u0026#39; { \u0026#34;Version\u0026#34;: \u0026#34;2012-10-17\u0026#34;, \u0026#34;Statement\u0026#34;: [ { \u0026#34;Effect\u0026#34;: \u0026#34;Allow\u0026#34;, \u0026#34;Action\u0026#34;: [\u0026#34;s3:*\u0026#34;], \u0026#34;Resource\u0026#34;: [ \u0026#34;arn:aws:s3:::tenant-a-data\u0026#34;, \u0026#34;arn:aws:s3:::tenant-a-data/*\u0026#34; ] } ] } POLICY # 创建并绑定策略 mc admin policy create myminio tenant-a-policy /tmp/tenant-a-policy.json mc admin policy attach myminio tenant-a-policy --user tenant-a-svc 对于大规模多租户场景(50+ 租户),建议部署多个独立 MinIO 集群通过 Kubernetes Operator 管理,避免单集群 IAM 策略过于复杂导致管理成本上升。\n4.1.4 版本控制与对象锁定 #Versioning(版本控制) 为 Bucket 内每个对象保留完整的历史版本,误删或误覆盖时可快速回滚:\n# 启用版本控制 mc version enable myminio/app-data # 查看对象的所有版本 mc ls --versions myminio/app-data/config.json # 恢复到指定版本(通过 version-id 复制回原路径) mc cp --version-id \u0026#34;a1b2c3d4-xxxx\u0026#34; myminio/app-data/config.json myminio/app-data/config.json WORM 合规模式:Object Lock 提供两种保留模式:\n模式\n特点\n适用场景\nGOVERNANCE\n拥有 s3:BypassGovernanceRetention 权限的用户可提前解除锁定\n内部数据保护,允许管理员紧急操作\nCOMPLIANCE\n任何人(包括 root)在保留期内都无法删除或修改\n金融监管、医疗合规、法律存证\n⚠️ COMPLIANCE 模式一旦设置,保留期内无法缩短或解除,务必确认保留时长后再操作。\n4.2 注意事项 #4.2.1 配置注意事项 #⚠️ 警告:以下配置错误在生产事故中出现频率极高,务必逐项检查。\n❗ 纠删码集合大小不可变更:集群初始化后,Erasure Set 的磁盘数量无法修改。扩容只能以 Server Pool 为单位追加,不能向已有 Pool 中添加单个节点或磁盘。 ❗ MINIO_VOLUMES 格式严格:花括号展开语法 {1...4} 中是三个点而非两个,写错不会报语法错误但会导致节点发现异常。 ❗ 时钟同步是硬性要求:分布式模式下节点间时钟偏差超过 15 秒会导致签名校验失败,所有节点必须配置 NTP/Chrony。 ❗ TLS 证书路径固定:MinIO 只从 ${HOME}/.minio/certs/ 或 /etc/minio/certs/ 读取证书,自定义路径需通过 --certs-dir 指定。 ❗ 内存预留:MinIO 在纠删码模式下每个 Erasure Set 约占用 2-3 GB 内存,16 组 Erasure Set 的集群至少预留 48 GB。 4.2.2 常见错误 #错误现象\n原因分析\n解决方案\nUnable to initialize backend: format.json not found\n磁盘未格式化或挂载点不正确\n检查 lsblk 确认挂载,确保目录为空且属主为 minio-user\nSignature does not match\n节点间时钟偏差过大\n部署 Chrony 并执行 chronyc makestep 强制同步\nHealing required\n持续不消失\n磁盘存在坏块或 IO 错误\nmc admin heal myminio --recursive\n并检查 dmesg 中的磁盘错误\nDrive already being healed\n多个 heal 任务冲突\n等待当前 heal 完成,通过 mc admin heal myminio --status 查看进度\nServer not initialized, please try again\n集群节点数不满足最小法定数\n检查所有节点网络连通性,确保至少 N/2+1 个节点在线\nConsole 登录后白屏\nMINIO_BROWSER_REDIRECT_URL\n与实际访问地址不匹配\n修正环境变量为实际的负载均衡器地址\n4.2.3 兼容性问题 # 版本兼容:MinIO 采用滚动发布,版本号格式为 RELEASE.YYYY-MM-DDTHH-MM-SSZ。升级时必须逐版本滚动,不支持跨大版本跳跃升级。升级前务必阅读对应版本的 Release Notes。 S3 API 兼容:MinIO 兼容 AWS S3 API 的绝大部分操作,但 S3 Select 仅支持 CSV/JSON/Parquet 格式,S3 Inventory 和 S3 Analytics 暂不支持。 客户端 SDK 兼容:AWS SDK(boto3、aws-sdk-js 等)可直接对接 MinIO,只需修改 endpoint 和关闭 virtual-hosted-style(使用 path-style)。部分旧版 SDK 的分片上传实现可能与 MinIO 存在兼容问题,建议使用 MinIO 官方 SDK 或 AWS SDK 最新版本。 五、故障排查和监控 #5.1 故障排查 #5.1.1 日志查看 ## 查看 MinIO 服务日志(systemd 部署) sudo journalctl -u minio.service -f --no-pager # 仅查看最近 1 小时的错误日志 sudo journalctl -u minio.service --since \u0026#34;1 hour ago\u0026#34; | grep -i \u0026#34;error\\|fatal\\|panic\u0026#34; # 通过 mc 实时查看服务端日志(需要管理员权限) mc admin logs myminio # 仅查看特定 Bucket 的操作日志 mc admin logs myminio --bucket app-data # 查看审计日志(如已配置 Webhook,从 ELK 等系统查询) mc admin trace myminio --call s3 --verbose 5.1.2 常见问题排查 #问题一:单盘故障恢复\n磁盘故障是分布式存储最常见的硬件问题。MinIO 在纠删码保护范围内可自动降级运行,但需尽快替换故障盘:\n# 1. 确认故障盘位置 mc admin info myminio --json | jq \u0026#39;.info.servers[].disks[] | select(.state != \u0026#34;ok\u0026#34;)\u0026#39; # 输出示例: # { \u0026#34;endpoint\u0026#34;: \u0026#34;/data/disk3\u0026#34;, \u0026#34;state\u0026#34;: \u0026#34;offline\u0026#34;, \u0026#34;totalspace\u0026#34;: 0 } # 2. 物理替换磁盘后,格式化并挂载到原路径 mkfs.xfs /dev/sdX mount /dev/sdX /data/disk3 # 3. 确保目录属主正确 chown minio-user:minio-user /data/disk3 # 4. MinIO 自动检测到新盘并开始 healing mc admin heal myminio --recursive --status 问题二:节点替换流程\n# 1. 确认待替换节点状态 mc admin info myminio # 2. 新节点部署完成后,使用相同的 MINIO_VOLUMES 配置启动 # 关键:新节点的主机名/IP 必须与原节点一致(或更新 DNS 解析) # 3. 启动后观察 healing 进度 mc admin heal myminio --recursive --status # 输出中关注 Items healed / Items pending 的比例 问题三:性能瓶颈定位\n# 实时追踪 S3 API 调用延迟 mc admin trace myminio --call s3 --verbose --filter-response-time 500ms # 查看各节点磁盘 IO 状态 mc admin speedtest myminio --duration 30s # 检查网络带宽是否成为瓶颈(节点间测试) iperf3 -c minio-2.example.com -t 10 -P 4 5.1.3 mc admin 诊断工具 #mc admin 提供了一套完整的集群诊断命令,排障时按以下顺序逐步排查:\n# 集群整体健康状态概览 mc admin info myminio # 生成诊断报告包(包含配置、日志、系统信息) # 提交工单或社区求助时附带此文件 mc admin inspect myminio # 查看集群配置差异(多节点配置不一致是常见问题源) mc admin config get myminio | head -50 # 查看实时 API 调用链路(类似 strace 效果) mc admin trace myminio --all --verbose # 磁盘级别健康检查 mc admin scanner status myminio 5.2 性能监控 #5.2.1 关键指标监控 #MinIO 原生支持 Prometheus 指标暴露,生成抓取配置:\n# 生成 Prometheus 抓取配置 mc admin prometheus generate myminio # 输出示例(添加到 prometheus.yml 的 scrape_configs 中): # - job_name: minio-job # bearer_token: \u0026lt;token\u0026gt; # metrics_path: /minio/v2/metrics/cluster # scheme: http # static_configs: # - targets: [\u0026#39;minio-1:9000\u0026#39;,\u0026#39;minio-2:9000\u0026#39;,\u0026#39;minio-3:9000\u0026#39;,\u0026#39;minio-4:9000\u0026#39;] 5.2.2 监控指标说明 #指标名称\n正常范围\n告警阈值\n说明\nminio_node_disk_free_bytes\n\u0026gt;20% 总容量\n\u0026lt;10%\n磁盘剩余空间,低于阈值需扩容\nminio_s3_requests_errors_total\n\u0026lt;0.1% 请求量\n\u0026gt;1%\nS3 错误请求数,突增说明客户端或权限异常\nminio_s3_ttfb_seconds\n\u0026lt;200ms (p99)\n\u0026gt;500ms\n首字节延迟,反映存储后端响应速度\nminio_node_disk_used_bytes\n线性增长\n增速突变\n磁盘使用量,突增可能是异常写入\nminio_heal_objects_total\n0\n\u0026gt;0 持续 1h\n待修复对象数,持续不为零说明有磁盘问题\nminio_node_process_cpu_total\n\u0026lt;70%\n\u0026gt;85%\nCPU 使用率,纠删码计算密集时会升高\n5.2.3 Prometheus + Grafana 告警配置 ## prometheus-rules.yml - MinIO 告警规则 groups: - name: minio-alerts rules: # 磁盘空间不足告警 - alert: MinioDiskSpaceLow expr: (minio_node_disk_free_bytes / minio_node_disk_total_bytes) \u0026lt; 0.1 for: 10m labels: severity: critical annotations: summary: \u0026#34;MinIO 磁盘空间不足 ({{ $labels.instance }})\u0026#34; description: \u0026#34;节点 {{ $labels.server }} 磁盘 {{ $labels.disk }} 剩余空间低于 10%\u0026#34; # S3 请求错误率告警 - alert: MinioHighErrorRate expr: rate(minio_s3_requests_errors_total[5m]) / rate(minio_s3_requests_total[5m]) \u0026gt; 0.01 for: 5m labels: severity: warning annotations: summary: \u0026#34;MinIO S3 错误率超过 1%\u0026#34; # 节点离线告警 - alert: MinioNodeOffline expr: minio_cluster_nodes_offline_total \u0026gt; 0 for: 2m labels: severity: critical annotations: summary: \u0026#34;MinIO 集群存在离线节点\u0026#34; description: \u0026#34;当前离线节点数: {{ $value }}\u0026#34; 5.3 备份与恢复 #5.3.1 mc mirror 备份脚本 ##!/bin/bash set -euo pipefail # MinIO 增量备份脚本 # 通过 mc mirror 将源集群数据同步到备份集群 # 建议通过 crontab 每日执行:0 2 * * * /opt/scripts/minio-backup.sh SOURCE_ALIAS=\u0026#34;myminio\u0026#34; TARGET_ALIAS=\u0026#34;backup-minio\u0026#34; BUCKETS=(\u0026#34;app-data\u0026#34; \u0026#34;user-uploads\u0026#34; \u0026#34;logs-archive\u0026#34;) LOG_DIR=\u0026#34;/var/log/minio-backup\u0026#34; DATE=$(date +%Y%m%d-%H%M%S) mkdir -p \u0026#34;${LOG_DIR}\u0026#34; for bucket in \u0026#34;${BUCKETS[@]}\u0026#34;; do echo \u0026#34;[${DATE}] 开始备份 Bucket: ${bucket}\u0026#34; | tee -a \u0026#34;${LOG_DIR}/backup-${DATE}.log\u0026#34; # --watch 不加,单次同步;--overwrite 覆盖已存在但内容不同的对象 mc mirror --overwrite --remove \\ \u0026#34;${SOURCE_ALIAS}/${bucket}\u0026#34; \\ \u0026#34;${TARGET_ALIAS}/${bucket}-backup\u0026#34; \\ 2\u0026gt;\u0026amp;1 | tee -a \u0026#34;${LOG_DIR}/backup-${DATE}.log\u0026#34; if [[ ${PIPESTATUS[0]} -ne 0 ]]; then echo \u0026#34;[ERROR] Bucket ${bucket} 备份失败\u0026#34; | tee -a \u0026#34;${LOG_DIR}/backup-${DATE}.log\u0026#34; # 发送告警(根据实际告警通道修改) curl -s -X POST \u0026#34;http://alertmanager:9093/api/v1/alerts\u0026#34; \\ -H \u0026#34;Content-Type: application/json\u0026#34; \\ -d \u0026#34;[{\\\u0026#34;labels\\\u0026#34;:{\\\u0026#34;alertname\\\u0026#34;:\\\u0026#34;MinioBackupFailed\\\u0026#34;,\\\u0026#34;bucket\\\u0026#34;:\\\u0026#34;${bucket}\\\u0026#34;}}]\u0026#34; fi done echo \u0026#34;[${DATE}] 备份任务完成\u0026#34; | tee -a \u0026#34;${LOG_DIR}/backup-${DATE}.log\u0026#34; # 清理 30 天前的备份日志 find \u0026#34;${LOG_DIR}\u0026#34; -name \u0026#34;backup-*.log\u0026#34; -mtime +30 -delete 5.3.2 站点复制(Site Replication) #Site Replication 是 MinIO 原生的多站点同步方案,支持 Bucket、对象、IAM 策略的双向实时同步,适用于异地容灾:\n# 前置条件:所有站点必须使用相同的 root 凭证,且均为空集群或数据完全一致 # 1. 添加站点复制关系(在任意一个站点执行) mc admin replicate add \\ site1-minio \\ site2-minio \\ site3-minio # 2. 查看复制状态 mc admin replicate status site1-minio # 3. 查看复制延迟指标 mc admin replicate metrics site1-minio # 注意事项: # - 站点复制会同步 IAM 用户、策略、Bucket 配置 # - 已有数据的集群加入复制前需确保数据一致 # - 网络中断后会自动追赶同步,但长时间中断可能导致队列积压 5.3.3 恢复流程 # 停止服务:sudo systemctl stop minio\n替换故障磁盘:物理更换后格式化挂载到原路径\n验证数据完整性:\n# 启动服务 sudo systemctl start minio # 触发全量 heal 检查 mc admin heal myminio --recursive # 持续观察 heal 进度直到完成 watch -n 5 \u0026#39;mc admin heal myminio --recursive --status\u0026#39; 从备份恢复(如需要):\n# 从备份集群恢复指定 Bucket mc mirror backup-minio/app-data-backup myminio/app-data # 验证对象数量一致 mc ls --summarize --recursive myminio/app-data 六、总结 #6.1 技术要点回顾 # ✅ 纠删码是核心:理解 Erasure Set 的划分逻辑和校验盘配比,直接决定集群的容错能力和存储效率 ✅ JBOD 优于 RAID:让 MinIO 自身管理磁盘冗余,避免硬件 RAID 带来的写放大和故障域耦合 ✅ 安全不是事后补救:IAM 最小权限、禁用匿名访问、Object Lock 应在集群初始化阶段就规划到位 ✅ 监控先于故障:Prometheus 指标 + Grafana 看板 + 告警规则三件套是生产环境的底线要求 ✅ 备份要自动化:mc mirror 脚本 + Site Replication 双管齐下,RPO 和 RTO 才有保障 ✅ 扩容按 Pool 为单位:不能向已有 Erasure Set 添加磁盘,扩容前做好容量规划 6.2 进阶学习方向 #MinIO vs Ceph RGW 对比:\n维度\nMinIO\nCeph RGW\n部署复杂度\n单二进制,分钟级部署\n需要 MON/OSD/MDS/RGW 多组件,小时级部署\n运维成本\n低,配置项少,升级简单\n高,组件多,调优参数复杂\nS3 兼容性\n覆盖主流 API,部分高级特性缺失\n覆盖面更广,支持 Swift API\n小文件性能\n优秀,元数据轻量\n一般,RADOS 层开销较大\n大文件吞吐\n优秀,纠删码计算高效\n优秀,可通过调优追平\n纠删码灵活性\nErasure Set 固定,扩容按 Pool\n可在线调整 EC Profile\n块存储/文件存储\n不支持,纯对象存储\n支持 RBD/CephFS,统一存储\n社区生态\n活跃,云原生方向发力\n成熟,企业级部署案例丰富\n适用场景\n纯对象存储、云原生、S3 网关\n需要统一存储、混合负载\nKubernetes Operator 部署:通过 MinIO Operator 在 K8s 上管理多租户集群,结合 CSI Driver 实现 PV 动态供给\n学习资源:MinIO Operator 文档 实践建议:先在测试集群部署单租户,熟悉 Tenant CRD 后再扩展到多租户 数据生命周期管理(ILM):通过 Lifecycle Rule 自动将冷数据迁移到低成本存储层或自动过期删除\n学习资源:MinIO Object Lifecycle Management 实践建议:从日志类 Bucket 开始配置 Expiration 规则,逐步扩展到 Transition 规则 事件通知集成:将 Bucket 事件推送到 Kafka/NATS/Webhook,构建数据驱动的处理管道\n学习资源:MinIO Bucket Notifications 6.3 参考资料 # MinIO 官方文档 - 最权威的配置和运维参考 MinIO GitHub - 源码、Issue 和 Release Notes MinIO Blog - 架构设计思路和性能测试报告 Awesome MinIO - 社区工具和集成方案汇总 附录 #A. 命令速查表 ## ========== 集群管理 ========== mc alias set myminio http://minio:9000 admin password # 添加集群别名 mc admin info myminio # 查看集群状态 mc admin service restart myminio # 重启服务 mc admin update myminio # 在线升级 mc admin speedtest myminio --duration 30s # 性能测试 # ========== Bucket 操作 ========== mc mb myminio/new-bucket # 创建 Bucket mc mb myminio/locked-bucket --with-lock # 创建带 Object Lock 的 Bucket mc rb myminio/empty-bucket # 删除空 Bucket mc ls myminio # 列出所有 Bucket # ========== 对象操作 ========== mc cp localfile.tar.gz myminio/bucket/path/ # 上传文件 mc cp myminio/bucket/path/file.tar.gz ./ # 下载文件 mc cp --recursive ./dir/ myminio/bucket/dir/ # 递归上传目录 mc rm myminio/bucket/path/file.tar.gz # 删除对象 mc ls --summarize --recursive myminio/bucket # 统计对象数量和大小 # ========== 同步与备份 ========== mc mirror source-minio/bucket target-minio/bucket # 增量同步 mc mirror --watch source-minio/bucket target-minio/bucket # 持续同步(守护模式) # ========== 用户与策略 ========== mc admin user add myminio username password # 创建用户 mc admin user list myminio # 列出用户 mc admin policy create myminio policy-name policy.json # 创建策略 mc admin policy attach myminio policy-name --user user # 绑定策略 # ========== 诊断与排障 ========== mc admin logs myminio # 实时日志 mc admin trace myminio --all # API 调用追踪 mc admin heal myminio --recursive # 触发数据修复 mc admin heal myminio --recursive --status # 查看修复进度 mc admin prometheus generate myminio # 生成监控配置 B. 配置参数详解 #MinIO 通过环境变量进行配置,以下为生产环境常用参数:\n环境变量\n默认值\n说明\nMINIO_ROOT_USER\nminioadmin\n超级管理员用户名,长度 3-128 字符\nMINIO_ROOT_PASSWORD\nminioadmin\n超级管理员密码,长度 8-128 字符\nMINIO_VOLUMES\n无\n存储路径,分布式模式使用 http://host:port/path 格式\nMINIO_OPTS\n无\n启动参数,如 --address :9000 --console-address :9001\nMINIO_SERVER_URL\n自动检测\n对外暴露的 S3 API 地址,经过负载均衡器时必须设置\nMINIO_BROWSER_REDIRECT_URL\n自动检测\nConsole 对外地址,反向代理场景必须设置\nMINIO_SITE_REGION\n无\n区域标识,S3 兼容性需要时设置(如 cn-east-1)\nMINIO_SITE_NAME\n无\n站点名称,Site Replication 场景使用\nMINIO_STORAGE_CLASS_STANDARD\nEC:N/2\n标准存储类的纠删码校验盘数量\nMINIO_STORAGE_CLASS_RRS\nEC:2\n低冗余存储类的校验盘数量\nMINIO_PROMETHEUS_AUTH_TYPE\njwt\nPrometheus 指标端点认证方式,可选 jwt 或 public\nMINIO_SCANNER_SPEED\ndefault\n后台扫描速度,可选 fastest/fast/default/slow/slowest\nMINIO_BATCH_REPLICATION_WORKERS\n4\n批量复制并发数,带宽充足时可适当调高\nC. 术语表 #术语\n英文\n解释\n纠删码\nErasure Coding\n将数据分片并生成校验片,允许在部分分片丢失时恢复完整数据\n纠删集\nErasure Set\nMinIO 中纠删码的最小管理单元,由固定数量的磁盘组成\n服务器池\nServer Pool\n一组配置相同的 MinIO 节点,扩容以 Pool 为单位追加\n对象锁定\nObject Lock\n防止对象在保留期内被删除或覆盖的 WORM 保护机制\n站点复制\nSite Replication\nMinIO 原生的多站点双向同步方案,支持对象和 IAM 同步\n生命周期管理\nILM (Information Lifecycle Management)\n基于规则自动迁移、过期或删除对象\n首字节延迟\nTTFB (Time To First Byte)\n从发起请求到收到第一个字节的耗时,衡量存储响应速度\n数据修复\nHealing\nMinIO 自动检测并修复损坏或缺失的数据分片的过程\n版本控制\nVersioning\n为同一对象保留多个历史版本,支持误操作回滚\n服务账户\nService Account\n绑定到 IAM 用户的访问凭证,用于应用程序接入\n","date":"2026年0月180日","permalink":"http://blog.hys.my/posts/minio/","section":"最近笔记","summary":"MinIO 是目前最成熟的 S3 兼容私有化对象存储方案。它用 Go 语言编写,单个二进制文件部署,没有外部依赖,性能在同类产品中领先。MinIO 完整实现了 S3 API(包括 Select、Encryption、Versioning、Object Lock 等),绝大多数 S3 SDK 和工具可以零修改对接。","title":"MinIO对象存储部署:S3兼容的私有化存储方案"},{"content":"","date":null,"permalink":"http://blog.hys.my/categories/openai/","section":"Categories","summary":"","title":"OpenAI"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/s3/","section":"Tags","summary":"","title":"S3"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/","section":"Tags","summary":"","title":"Tags"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/%E9%83%A8%E7%BD%B2%E6%8C%87%E5%8D%97/","section":"Tags","summary":"","title":"部署指南"},{"content":"","date":null,"permalink":"http://blog.hys.my/categories/%E5%AD%98%E5%82%A8%E6%96%B9%E6%A1%88/","section":"Categories","summary":"","title":"存储方案"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/%E5%AF%B9%E8%B1%A1%E5%AD%98%E5%82%A8/","section":"Tags","summary":"","title":"对象存储"},{"content":"","date":null,"permalink":"http://blog.hys.my/categories/%E6%8A%80%E6%9C%AF%E6%96%87%E6%A1%A3/","section":"Categories","summary":"","title":"技术文档"},{"content":" 在服务器上运行安卓和浏览器,以便执行一些自动化任务,比如115自动签到。使用自己的安卓手机来运行这些任务很容易中断,而在服务器上运行可以随时随地打开网页进行操作。至于为什么要运行Firefox浏览器,则是为了实现一套放在云上的指纹浏览器。注册国外的一些账号时,需要确保IP、语言、时区等保持一致,并且支持不同地区。我这套方案支持一键启动多实例,即同时运行多个安卓和Firefox。\n操作环境 # 甲骨文服务器 ws-scrcpy(web版本的scrcpy,用于实现远程控制,我适配了arm) firefox(docker版本的Firefox,我添加了中文字体) redroid(docker版本的安卓,可以自行定制镜像) nginx-proxy-manager(web管理nginx,可以自动申请证书,添加basic认证) cloudflare zerotrust(可选,用于安全拦截) docker-gateway(我编写的docker网关,用于给容器做代理策略,避免使用Firefox浏览器代理被检测) socks5住宅IP代理(可选,根据需求购买,这里不做推荐) 部署 #我使用docker compose进行部署,以下是配置文件。我添加了gateway作为容器内部的代理网关,如果不需要使用代理,请去掉gateway网关服务和虚拟网卡的配置。\n加载内核模块\nsudo apt install linux-modules-extra-`uname -r` sudo modprobe binder_linux devices=\u0026#34;binder,hwbinder,vndbinder\u0026#34; sudo modprobe ashmem_linux sudo modprobe xt_mark sudo modprobe iptable_filter sudo modprobe iptable_nat sudo modprobe xt_TPROXY sudo modprobe xt_socket docker compose 配置\nservices: nginx-proxy-manager: image: jc21/nginx-proxy-manager:2.11.3 container_name: nginx volumes: - nginx_data:/data - nginx_cert:/etc/letsencrypt ports: - 80:80 # 管理端口,建议后面去掉 - 81:81 - 443:443 restart: unless-stopped networks: - default # 5800 firefox-1: image: monlor/firefox volumes: - firefox-1:/config restart: unless-stopped environment: - TZ=Australia/Sydney - LANG=en_AU.UTF-8 # 这个配置和docker-gateway搭配使用,将当前容器的默认网关指向docker-gateway服务,不添加这个变量则不走代理 - GATEWAY_IP=172.100.0.2 networks: gateway: ipv4_address: 172.100.0.11 default: scrcpy: image: monlor/ws-scrcpy container_name: scrcpy environment: # 这里添加你的redroid adb地址,用逗号分隔,如:redroid-1:5555,redroid-2:5555 - ADB_ADDRESS=redroid-1:5555 restart: unless-stopped networks: default: gateway: ipv4_address: 172.100.0.50 redroid-1: image: redroid/redroid:13.0.0-latest container_name: redroid-1 privileged: true volumes: - redroid-1:/data command: - androidboot.hardware=mt6891 - ro.secure=0 - ro.boot.hwc=GLOBAL # 这里的imei需要修改,每个机器都不一样 - ro.ril.oem.imei=861503068112233 - ro.ril.oem.imei1=861503068112234 - ro.ril.oem.imei2=861503068112235 - ro.ril.miui.imei0=861503068112236 - ro.product.manufacturer=Xiaomi - ro.product.model=droid-1 - ro.build.product=chopin - redroid.width=720 - redroid.height=1280 - redroid.gpu.mode=guest healthcheck: \u0026amp;healthcheck test: [\u0026#34;CMD\u0026#34;, \u0026#34;sh\u0026#34;, \u0026#34;-c\u0026#34;, \u0026#34;test \\\u0026#34;1\\\u0026#34; = \\\u0026#34;`/system/bin/getprop sys.boot_completed`\\\u0026#34;\u0026#34;] interval: 30s timeout: 10s retries: 3 start_period: 30s restart: unless-stopped networks: gateway: ipv4_address: 172.100.0.51 gateway: image: ghcr.io/monlor/docker-gateway:main container_name: gateway environment: # 指定哪些容器ip需要走PH的代理,ip为容器ip,这里为firefox-1 - RULE_TAG_PH=172.100.0.11/32 # 添加名为PH的socks代理,ip 端口 用户 密码 - OUTBOUND_SERVER_PH=socks,2.2.2.2:58688:user:pass # 再指定哪些容器ip走UK的代理,我这里随便写的gateway网络下的ip - RULE_TAG_UK=172.100.0.13/32 # 再添加名为UK的socks代理,ip 端口 用户 密码 - OUTBOUND_SERVER_UK=socks,3.3.3.3:58688:user:pass privileged: true pid: host volumes: - /var/run/docker.sock:/var/run/docker.sock networks: gateway: ipv4_address: 172.100.0.2 restart: unless-stopped volumes: nginx_data: nginx_cert: redroid-1: firefox-1: networks: default: driver: bridge ipam: config: - subnet: \u0026#34;172.18.0.0/16\u0026#34; gateway: \u0026#34;172.18.0.1\u0026#34; gateway: name: gateway driver: bridge ipam: config: - subnet: 172.100.0.0/24 如果你没有安装docker,可以执行以下命令进行安装:\ncurl -sSL https://get.docker.com/ | sh 将配置文件保存到你喜欢的文件夹,比如/opt/server,然后部署服务:\ncd /opt/server docker compose up -d 查看容器日志:\ndocker compose logs 查看服务状态:\ndocker compose ps 原理解释 # Cloudflare Zero Trust 安全拦截 # 非必需\n拦截scrcpy和firefox的域名,使用github oauth登陆,保证服务安全性\nnginx proxy manager #使用81端口访问,用于反向代理,ssl证书申请,如果你不使用zero trust,可以在这一层做basic认证,可以参考以下配置\n我还在这一层配置了cf的ip白名单,保证cf =\u0026gt; nginx的安全性\nDocker Host # ws-scrcpy用于远程控制多个安卓设备(如redroid-1和redroid-2)。 redroid-1和redroid-2运行安卓系统实例。 firefox-1运行Firefox浏览器实例。 ws-scrcpy #需要添加环境变量,指定你要管理的redroid实例,有多少个redroid就添加多少个,会自动帮你连接。同时,当你重启redroid之后,也需要重启scrcpy。\nADB_ADDRESS=redroid-1:5555,redoird-2:5555 Docker Gateway # 非必需,这里以firefox-1举例\n固定firefox-1容器的ip,方便做分流,例如\n... networks: gateway: ipv4_address: 172.100.0.11 ... 在容器中添加环境变量,修改默认网关,执行我们的docker-gateway网关\n- GATEWAY_IP=172.100.0.2 在docker-gateway容器中添加环境变量代理,指定firefox-1走哪个代理,以下指定ip为172.100.0.11的firefox-1容器走PH这个代理。\n... # 指定哪些容器ip需要走PH的代理,ip为容器ip,这里为firefox-1 - RULE_TAG_PH=172.100.0.11/32 # 添加名为PH的socks代理,ip 端口 用户 密码 - OUTBOUND_SERVER_PH=socks,2.2.2.2:58688:user:pass - ... 看到这里你应该明白docker-gateway的工作原理了,要是不明白就实操。\n效果图 #安卓在手机上打开支持触摸,体验不错,在电脑上打开支持键盘输入。都可以很方便的共享给其他人使用。\n最后修改:2024 年 09 月 10 日\n© 允许规范转载\n","date":"2026年0月180日","permalink":"http://blog.hys.my/posts/android-firefox/","section":"最近笔记","summary":"在服务器上运行安卓和浏览器,以便执行一些自动化任务,比如115自动签到。使用自己的安卓手机来运行这些任务很容易中断,而在服务器上运行可以随时随地打开网页进行操作。至于为什么要运行Firefox浏览器,则是为了实现一套放在云上的指纹浏览器。注册国外的一些账号时,需要确保IP、语言、时区等保持一致,并且支持不同地区。我这套方案支持一键启动多实例,即同时运行多个安卓和Firefox。","title":"使用Docker容器在服务器上运行安卓和Firefox,实现自建云手机和指纹浏览器"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/%E7%A7%81%E6%9C%89%E5%8C%96%E5%AD%98%E5%82%A8/","section":"Tags","summary":"","title":"私有化存储"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/%E6%8C%87%E7%BA%B9%E6%B5%8F%E8%A7%88%E5%99%A8/","section":"Tags","summary":"","title":"指纹浏览器"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/%E8%87%AA%E5%8A%A8%E7%AD%BE%E5%88%B0/","section":"Tags","summary":"","title":"自动签到"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/%E8%87%AA%E5%BB%BA%E4%BA%91%E6%89%8B%E6%9C%BA/","section":"Tags","summary":"","title":"自建云手机"},{"content":"欢迎来到我的博客:探索科研、创业和日常加入我在科研、创业和日常探索的旅程中,一起发现新事物、分享经验和灵感。\n","date":null,"permalink":"http://blog.hys.my/posts/","section":"最近笔记","summary":"所有博客文章列表","title":"最近笔记"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/hugo/","section":"Tags","summary":"","title":"Hugo"},{"content":"","date":null,"permalink":"http://blog.hys.my/categories/%E6%8A%80%E6%9C%AF/","section":"Categories","summary":"","title":"技术"},{"content":"","date":null,"permalink":"http://blog.hys.my/tags/%E6%95%99%E7%A8%8B/","section":"Tags","summary":"","title":"教程"},{"content":"这里是文章的正文内容,使用 Markdown 语法编写。\n欢迎阅读 #这是我的第一篇博客文章,使用 Hugo 和 Congo 主题搭建。\n一些功能展示 # 支持列表 支持加粗、斜体 支持超链接 支持代码块: ","date":"2024年0月290日","permalink":"http://blog.hys.my/posts/first-post/","section":"最近笔记","summary":"这里是文章的简短摘要,会显示在文章列表页。","title":"我的第一篇文章"}]