很多朋友在 VPS 上折腾 AI 服务时,一开始图省事把所有容器塞进一个 `docker-compose.yml`,结果后来想更新某个服务,牵一发而动全身,甚至把数据卷搞丢了。在主机选的实战经验里,做好目录、网络和数据卷的隔离,是避免“删库跑路”悲剧的关键。Docker Compose 部署多个 AI 服务怎么规划?核心在于把每个服务当成独立的模块,通过统一的网络桥接,既保证互通,又互不干扰。

Docker Compose 部署多个 AI 服务的目录规划
别把所有鸡蛋放在一个篮子里。很多新手习惯在 `/root` 下乱建文件,时间久了连自己都找不到配置在哪。规范的目录结构能极大降低后期维护成本。建议在 `/opt` 或 `/home` 下建立统一的工作目录,例如 `/opt/ai-stack`,每个服务一个子目录。
mkdir -p /opt/ai-stack/{ollama,n8n,open-webui,nginx-proxy}
cd /opt/ai-stack
这种结构下,每个服务目录(如 `ollama`、`n8n`)都拥有独立的 `docker-compose.yml` 和数据文件夹。这样当你需要重装 n8n 时,完全不会影响到正在跑模型的 Ollama 容器。记住,目录清晰了,排障时才能一眼看到底是哪个服务的日志在报错。
独立 Compose 文件的优势
每个服务一个 `docker-compose.yml` 文件,虽然看起来麻烦,但生产环境必须这么干。比如你要升级 Ollama 版本,只需进入对应目录执行 `docker-compose pull` 和 `docker-compose up -d`。如果所有服务都在一个文件里,你每次重启都要等待所有容器重新加载,不仅浪费时间,还增加了服务不可用的风险。此外,独立文件也方便进行 Git 版本管理,把配置文件托管到私有仓库,服务器挂了能快速恢复。
统一网络管理实现服务互通
容器之间通信是 AI 工作流(如 n8n 调用 Ollama)的关键。默认情况下,Docker 会为每个 compose 项目创建一个独立的网络,这导致不同目录下的容器无法直接通过服务名互访。解决方案是创建一个外部共享网络,让所有需要交互的 AI 服务都接入这个网络。
docker network create ai-net
在各个服务的 `docker-compose.yml` 中,指定使用该外部网络:
yaml
services:
ollama:
networks:
– ai-net # 加入共享网络
networks:
ai-net:
external: true # 声明使用已存在的外部网络
这样,n8n 容器可以直接通过 `http://ollama:11434` 访问 Ollama 服务,而不需要暴露端口到公网。这种做法既安全又高效,避免了把所有 API 接口裸露在互联网上。
解决容器间通信与端口冲突
很多用户在部署多个 Web 服务(如 Open WebUI 和 n8n)时,习惯把 80、443 端口直接映射出来,导致端口冲突。正确的做法是只保留一个入口(通常是 Nginx 反向代理),其他 AI 服务的端口仅映射到 `127.0.0.1` 或者干脆不映射端口,仅通过 Docker 内部网络访问。
例如,n8n 默认端口是 5678,Open WebUI 是 3000。在 `docker-compose.yml` 里,n8n 可以写 `ports: ["127.0.0.1:5678:5678"]`,或者干脆不写 ports 段落,完全依赖 Nginx 容器去代理 `ai-net` 网络里的 `n8n:5678`。这能有效防止恶意扫描,减少被攻击面。
数据卷持久化与迁移实战
跑 AI 服务最怕的就是数据丢失。模型文件、知识库、n8n 的工作流配置,这些数据都在容器内部,一旦容器删除且没挂载卷,数据就没了。绝对不要使用自动生成的匿名卷,必须在 `docker-compose.yml` 里显式声明绑定挂载(Bind Mount)或具名卷。
推荐使用绑定挂载,因为路径直观,方便用 `rsync` 或 `scp` 备份。
yaml
services:
ollama:
volumes:
– ./ollama/data:/root/.ollama # 挂载模型数据
这样,Ollama 下载的模型文件就直接存在宿主机的 `./ollama/data` 目录下。如果你想迁移到另一台 VPS,直接打包这个目录拷过去,改一下配置就能跑,比 Docker 的 export/import 快得多,也兼容性更好。
避免数据丢失的备份策略
不要指望 VPS 商商的快照能天天帮你做备份。对于关键的 AI Agent 配置和知识库,建议写个简单的 Shell 脚本,利用 `cron` 定时把数据目录打包推送到对象存储(如 S3)或另一台备份服务器。特别是 n8n 的 SQLite 数据库和 Open WebUI 的向量库,一旦损坏,重建工作流的成本极高。
老鸟叮嘱
1.别用 root 跑容器:在 `docker-compose.yml` 里指定 `user` 参数,或者确保宿主机挂载目录的权限正确,避免容器内应用以 root 权限写入文件,导致安全漏洞。
2.注意时区问题:很多 AI 工具(如 n8n)的定时任务对时间敏感,记得在环境变量里加 `TZ=Asia/Shanghai`,否则 Cron 任务可能乱套。
3.日志轮转:Docker 容器日志如果不加限制,几天就能把磁盘撑爆。在 daemon.json 里配置 `"log-driver": "json-file", "log-opts": {"max-size": "10m", "max-file": "3"}`,或者在每个 compose 文件里限制 logging。
4.环境变量分离:API Key 这种敏感信息别直接写进 `docker-compose.yml`,建一个 `.env` 文件,并把 `.env` 加入 `.gitignore`,防止误提交泄露密钥。
FAQ
Q1: Docker Compose 部署多个 AI 服务时,必须用同一个网络吗?
A: 不是必须,但强烈推荐。如果服务之间不需要调用(比如两个独立的 Web UI),可以各自用默认网络。但如果 n8n 要调用 Ollama,或者 Open WebUI 要调用后端 API,就必须在同一个自定义网络中,或者通过 `links`(已过时)和 `extra_hosts` 来互通,共用网络是最简单的方案。
Q2: 更新一个服务会影响其他正在运行的 AI 服务吗?
A: 如果采用了独立的目录和 Compose 文件,更新操作(如 `docker-compose up -d`)只会作用于当前目录下的容器。只要没有共享底层资源(如都占用了所有 GPU 显存),其他服务不会受影响。
Q3: 如何查看容器是否成功连接到了共享网络?
A: 使用 `docker network inspect ai-net` 命令,在输出的 `Containers` 字段里,如果能看到你的服务名称和 IP 地址,说明连接成功。
Q4: 数据卷挂载后,容器内没有权限写入怎么办?
A: 这通常是宿主机目录 UID/GID 与容器内运行用户不一致导致的。可以在宿主机用 `chown -R 1000:1000 ./data` 修改目录权限(假设容器内运行用户是 UID 1000),或者在 Compose 文件中强制指定 `user: "1000:1000"`。
规划好目录、网络和数据卷,VPS 就能从“玩具环境”变成稳定的“生产环境”。这种架构不仅适用于 Ollama、n8n,也适用于后续部署任何新的 AI Agent 或自动化工具,扩展性极强。
转载请注明出处:https://www.zhujixuan.com/jishujiaocheng/10155.html 商家投稿邮箱:zhujixuanblog@qq.com
