多栈 Docker 环境:数据迁移后的卷盘点与安全清理流程

背景 在多 Compose 栈并存的环境里,迁移完成后常见现象是: 目标是:先盘点,再确认引用关系,最后最小化删除,避免误删关键数据。 核心原则 1) 先确认“新数据落点”是否稳定 迁移成功的强信号通常是:关键服务容器的持久化目录全部使用 bind mount,且映射到统一的宿主机工作目录结构。 2) named volume 的风险等级更高 在多栈环境里,named volume 很可能承载关键数据,例如: 结论:只有当卷确认“零引用”且业务已稳定使用 bind mount 时,才进入删除阶段。 盘点步骤 Step A:列出所有卷(建立资产清单) 只列出“无引用候选”(只做名单,不删除): Step B:列出所有容器(包含已停止) 目的: Step C:从容器侧确认挂载类型(关键确认) 对“目标业务容器”查看挂载: 关注点: 若目标业务容器已完全为 bind mount,说明迁移落点基本完成。 识别“迁移搬运容器” 迁移时常用方式是: 这类容器特征: 验证方式:列出某个卷当前被哪些容器引用(最重要的安全检查): 安全清理顺序 ① 先删“迁移搬运容器” 前提:确认这些容器不再需要、并且目标业务已稳定运行。 ② 再做“卷引用归零”验证 对每个旧卷执行: 判定规则: ③ 最后删除确认无引用的旧卷 …

OnlyOffice Docker 栈内统一与匿名卷迁移记录

背景 在使用 onlyoffice/documentserver 单容器部署 OnlyOffice 的过程中,虽然已经将常见目录(logs / data / cache / public / fonts)通过 bind mount 挂载到了用户目录,但在实际检查容器挂载点时,仍然发现 /var/lib/docker/volumes/ 下存在多组随机字符串命名的 volume。 这类 volume 并非人为创建,而是镜像在 Dockerfile 中通过 VOLUME 指令声明后,由 Docker 自动生成的匿名卷。如果不显式覆盖挂载,这些卷会默默承载真实数据,从而破坏“栈内统一、目录可迁移”的目标。 本文记录一次完整的排查与修正过程,将 OnlyOffice 的 全部持久化数据 统一收敛到单一项目目录下,并清理匿名卷依赖。 问题确认:匿名卷从何而来 通过以下命令检查容器挂载点: 可以观察到: 这些匿名卷对应的典型路径包括: 结论:OnlyOffice 内部依赖的 PostgreSQL / RabbitMQ / Redis 等组件,其数据仍然落在 Docker 管理区,而非项目目录。 目标 现有目录结构(示例) …

Docker 中应用栈数据卷重构与迁移记录

一、问题背景(抽象化) 在一台长期运行的 Linux 主机上,使用 Docker Compose 部署了多个应用栈。随着时间推移,出现了以下典型问题: 目标不是改变 Docker 的存储机制,而是: 在不破坏 Docker 设计的前提下,让数据卷“可读、可控、可迁移”。 二、总体设计原则(通用) 1. 不强行迁移 Docker 根目录 2. 明确区分三类数据 类型 处理方式 Compose / 配置文件 保留在用户可读目录 运行期业务数据 使用 命名 volume 临时 / 缓存数据 允许 Docker 自动管理 3. 通过“命名 volume”解决可读性问题 三、问题定位方法(通用步骤) 1. 列出系统中所有 volume 2. 反向确认 volume 与容器的挂载关系 通过该方式,可以明确: 四、数据迁移的通用流程 步骤 …

OpenWebUI 多模态与模型管理实践记录

背景 在 OpenWebUI 中同时接入本地模型(Ollama)与云端模型(OpenAI External)后,模型列表会显著膨胀,包含大量历史版本、兼容别名与专用用途模型。本文记录一种低心智负担、可长期使用的配置与使用方式,并解释多模态能力的实际用法。 一、为什么模型会“突然变多” 当 OpenWebUI 的 OpenAI 连接中 Model IDs 留空 时,系统会直接拉取 OpenAI /v1/models 的全量结果,其中包含: 这是 API 工程级清单,并非“用户选择列表”。数量增加并不代表配置错误。 二、真正需要关注的模型类别 1. 日常文本与思考 覆盖绝大多数文本任务。 2. 多模态(图文理解) 用法:在对话中拖入图片,配合文字提问即可完成“看图说话”。 3. 图像生成(文 → 图) 说明:该模型为单向生成模型,仅用于画图,不用于聊天或分析。 4. 可忽略的模型 这些模型不影响日常使用,可完全忽略。 三、两种可行的模型管理策略 策略 A:自动更新(省心) 适合:不想维护配置、只关心可用性。 策略 B:极简清单(推荐) 在 Settings → Connections → OpenAI → Model …

OpenAI API Key 管理实践:为 OpenWebUI 与 Dify 分离创建 Key

一、背景说明 在本地或自托管环境中同时部署 OpenWebUI 与 Dify 时,二者都会涉及对 OpenAI API 的调用。如果使用同一个 API Key: 因此,更合理的做法是:为不同服务分别创建并使用独立的 API Key。 二、API Key 是否可以免费创建 OpenAI 平台允许用户: 但需要注意的是: 因此,创建多个 Key 并不会带来额外的免费调用额度。 三、是否可以创建多个 API Key 结论很明确: 这使得 API Key 可以作为逻辑隔离工具,而不是计费隔离工具。 四、推荐的 Key 划分方案 针对常见的自托管 AI 使用场景,推荐至少划分如下两类: 使用场景 API Key OpenWebUI(交互式对话) openwebui Dify(应用 / Workflow / Agent) dify 原则非常简单: 一服务一 …

使用 ChatGPT API 构建自托管 AI 系统:与官方 ChatGPT 的全面对比

一、两个体系的本质区别 1. 官方 ChatGPT 官方 ChatGPT 是一个面向终端用户的一体化产品,核心特点是: 用户只需登录账号,即可直接使用文字、语音、图片、文件等能力,无需关心模型选择、上下文管理或计费细节。 2. ChatGPT API ChatGPT API 是一个面向开发者和系统构建者的能力接口,核心特点是: API 更像“发动机”,而不是“整车”。 二、账号与计费体系 账号关系 计费关系 两者可以同时使用,互不替代。 三、能力对比(模型层 vs 产品层) 模型能力 在模型层面: 差异主要来自产品层封装,而非模型本身。 四、多模态能力(图片 / 文档 / 截图) 官方 ChatGPT 的表现 这些能力对用户而言是“无感”的。 API 的实际情况 当前 OpenAI 的新一代 API 已原生支持多模态: 但需要注意: API 只提供能力,不提供完整交互体验 是否“好用”,高度依赖前端是否支持: 这也是为什么多数开源前端在体验上仍与官方存在差距。 五、语音能力 官方 ChatGPT …

Dify 使用入门:从安装到真正可用的最小路径

一、结论先行:Dify 是什么? 一句话概括: Dify 是一个“将大模型封装为应用”的平台。 它本身并不提供模型推理能力,也不是单纯的聊天界面,而是位于模型之上的应用与编排层,主要作用包括: 在常见的本地 LLM 架构中,其角色可以抽象为: 简化理解: 交互层解决“如何对话” Dify 解决“让 AI 持续按同一规则工作” 二、什么时候需要 Dify? 不适合引入 Dify 的情况 当使用目标主要是: 此时,引入额外的应用层意义不大。 Dify 的适用场景 Dify 更适合以下需求: 其核心价值在于:长期一致性与可控性。 三、学习 Dify 的正确主线 应用 → 行为规则(Prompt) → 数据接入 学习顺序非常关键。 不建议一开始接触复杂功能,应先理解 Dify 的最小工作模型。 四、第一步:创建最小可用应用 目标不是“功能完整”,而是: 核心原则 当应用能够正常调用模型并完成基本对话,即达到该阶段目标。 五、第二步:通过系统指令固定行为 Dify 的关键能力在于系统级指令。 系统指令的作用不是提示,而是长期生效的行为约束。 其价值在于: 示例结构(抽象): 只要系统指令保持不变,模型行为就具有可重复性。 …

Docker 中拆分 Ollama 与 Open-WebUI 为独立栈的实践记录

背景 在单机环境中使用 Docker Compose 同时运行 Ollama(推理核心)与 Open-WebUI(交互界面)是一个常见做法。初期将两者放在同一个 compose 文件中管理较为方便,但随着系统逐步演进,这种方式会带来以下问题: 因此,本次实践的目标是: 在不丢失任何既有数据的前提下,将 Ollama 与 Open-WebUI 拆分为两个独立的 Docker Compose 栈,并通过一个核心网络进行连接。 设计原则 原始状态分析 在最初的一体化部署中,Docker 会自动为服务创建数据卷。拆分为多个栈后,如果未显式指定旧数据卷名称,Docker 会为新栈创建新的空卷,从而导致“历史数据消失”的错觉。 需要明确的是: 数据通常并未被删除,而是新容器未挂载到正确的旧数据卷。 因此,拆分过程中最关键的工作并不是服务启动顺序,而是数据卷的精确绑定。 拆分思路概述 整体架构被拆分为两类栈: 所有服务间通信均通过 Docker 内部网络完成,核心服务不直接对外暴露。 核心栈配置要点(示意) 核心栈的职责包括: 配置示意(省略非关键字段): 外围栈配置要点(示意) 外围栈的职责包括: 配置示意(省略非关键字段): 常见问题与判断方法 为什么拆分后看起来“数据没了”? 如何判断旧数据卷是否仍然存在? 可通过 Docker 的卷列表与磁盘占用信息进行判断。通常: 最终状态 在完成拆分与修正后,系统应达到以下状态: 总结 本次实践的核心经验可以归纳为一句话: Docker 不会替用户判断应当使用哪个历史数据卷,所有关键数据都必须显式绑定。 通过明确: …

Docker 中未被任何容器使用的卷识别与清理实录

背景 在长期运行的 Docker 环境中,随着容器的反复创建、删除与重建,系统中可能残留未被任何容器使用的卷(volume)。这些卷如果不加区分地清理,存在误删有效数据的风险;如果完全不清理,又会造成系统状态不透明。 本文记录一次严格、可验证的 Docker 卷清理过程,目标是: 一、初步筛选:dangling volume Docker 提供了对“悬空卷(dangling volume)”的定义: 未被任何容器引用的卷 使用以下命令列出: 输出结果为两个卷 ID: 该步骤只能说明: 这些卷当前没有被容器引用 但仍需要进一步验证它们的空间占用与引用状态。 二、空间与引用状态交叉验证 通过 docker system df -v 查看本地卷的使用情况,并重点关注两项信息: 关键结果如下(节选): 可以确认: 三、判断结论 综合两次验证结果: 卷 ID LINKS SIZE 状态 14ab1c74859f… 0 7.7 kB 未被使用 ebd2fa33478… 0 90 kB 未被使用 结论: 四、安全删除方式 明确目标卷后,采用精确删除而非批量清理: 该方式的优点是: 五、实践原则总结 …

从 Brix 到砂糖:一次关于“控糖咖啡”的理性拆解

一、问题背景 在超市中常见一种标注为“糖度控制”的咖啡饮料。直观感受是甜度不高,但如果从理性角度出发,一个自然的问题是: 这种咖啡里,实际相当于摄入了多少“糖”?是否会对长期健康造成影响? 本文从 糖度(Brix)定义、砂糖种类、折糖换算、热量估算 等角度,对这一问题进行一次完整拆解。 二、Brix(糖度)到底表示什么? 糖度计上显示的 Brix(°Bx),并不等同于“真实加了多少糖”。 定义: 1 °Bx = 100 g 溶液中,含有 1 g 蔗糖当量的可溶性固形物 关键点在于: 因此: 在咖啡中,除了糖,还包括: 这些都会对 Brix 产生贡献。 三、为什么“糖度控制咖啡”不能直接读糖量? 即使是完全无糖的黑咖啡,其 Brix 通常也在 0.5–1.5 °Bx 左右。 因此: 一定会高估实际糖摄入。 合理做法(理论上): 但在日常生活中,更现实的方式是:根据配方和标称糖度进行估算。 四、砂糖的种类:グラニュー糖 vs 上白糖 在日本常见两种砂糖: 1️⃣ グラニュー糖(Granulated Sugar) 用途: 👉 食品分析与量化计算的“基准糖” 2️⃣ 上白糖 用途: 👉 …