前言
在构建集成大模型与多智能体的企业级知识库系统(如 WeKnora)时,私有化部署是保障数据安全的必经之路。然而,面对包含 PostgreSQL(集成 pgvector 插件)、Qdrant 向量库、Neo4j 图数据库等庞大组件的微服务集群,环境基建往往是最容易翻车的一环。
本文将分为两大板块:**【标准部署篇】确保你能跟着步骤一次性跑通全流程;【深度排障篇】**则为你剖析那些极具隐蔽性的底层架构陷阱。
第一篇:从 0 到 1 标准部署指南
不要轻视基础环境的搭建。微服务启动失败,90% 源于宿主机指令集不支持、系统预装的 Docker 版本过旧或依赖冲突。
⚠️ 环境要求 :请准备一台纯净的 Ubuntu 24.04/22.04 服务器。如果是虚拟机,请务必在虚拟化面板中将 CPU 模式设置为 Host(直通模式),以透传 AVX2 指令集,否则后续的向量数据库将无法运行。
Step 0: 拉取源码或者下载官方源码zip/tar包
shell
# 方式一:使用 Git 克隆(推荐)
git clone git@github.com:Tencent/WeKnora.git
# 方式二:使用 curl 下载压缩包 并制定下载后的文件名称
curl -o WeKnora-v0.6.2.tar.gz https://github.com/Tencent/WeKnora/archive/refs/tags/v0.6.2.tar.gz
# 解压下载的压缩包(根据实际文件名选择)
tar -zxvf WeKnora-v0.6.2.tar.gz
Step 1: 彻底清理旧版环境
不要信任系统自带的包管理器(如 snap),先执行外科手术式的清理,为新环境腾出干净的空间:
bash
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove -y $pkg; done
Step 2: 安装官方 Docker 引擎
配置官方 GPG 密钥与源,确保获取的是最新且最纯正的 Docker Engine 与 Compose V2 插件:
bash
# 1. 安装基础依赖
sudo apt update
sudo apt install -y ca-certificates curl jq
# 2. 注入官方 GPG 密钥
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL [https://download.docker.com/linux/ubuntu/gpg](https://download.docker.com/linux/ubuntu/gpg) -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# 3. 添加 Docker 稳定版仓库
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] [https://download.docker.com/linux/ubuntu](https://download.docker.com/linux/ubuntu) \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 4. 安装 Docker 引擎全家桶
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Step 3: 前置规避引擎冲突与修改配置
为了防止 Docker 29.x 版本引入的新特性(Private Time Namespace)与 Ubuntu 内核产生冲突,以及确保微服务依赖启动顺畅,我们需要提前调整两处配置。
1. 关闭 Docker 时间命名空间特性:
bash
sudo mkdir -p /etc/docker
# 如果 daemon.json 存在则安全合并,不存在则创建
if [ -f /etc/docker/daemon.json ]; then
sudo jq '.features += {"time-namespaces": false}' /etc/docker/daemon.json > /tmp/daemon.json && sudo mv /tmp/daemon.json /etc/docker/daemon.json
else
echo '{"features": {"time-namespaces": false}}' | sudo tee /etc/docker/daemon.json
fi
sudo systemctl restart docker
2. 优化微服务自愈能力(修改 Compose 文件):
进入 WeKnora 项目目录,打开 docker-compose.yml,找到负责数据库初始化的 langfuse-db-init 服务,为其添加失败重启策略,然后注释原有的 #restart: "no" 配置 以规避数据库启动慢导致的时序崩溃。
yaml
langfuse-db-init:
image: paradedb/paradedb:v0.22.2-pg17
container_name: WeKnora-langfuse-db-init
depends_on:
postgres:
condition: service_healthy
environment:
PGPASSWORD: ${DB_PASSWORD}
restart: on-failure # 遇到非零退出码时自动重启
deploy:
restart_policy:
condition: on-failure # 仅在失败时重启(成功 exit 0 则不重启)
delay: 5s # 每次重试前等待 5 秒,避开 DB 的重启空窗期
max_attempts: 10
# ${LANGFUSE_DB_NAME:-langfuse} / ${DB_USER} 由 compose 解析成字面量后再传给 shell;
# 脚本中需要 shell 自己展开的变量(无)一律用 $$ 转义。
entrypoint: ["sh", "-c"]
command:
- |
set -e
echo "[langfuse-db-init] ensuring database '${LANGFUSE_DB_NAME:-langfuse}' exists in WeKnora-postgres..."
# 先刷新现有库的 collation(镜像 ICU 2.36 与宿主 2.41 不匹配时必须做),否则 CREATE DATABASE 会失败
psql -h postgres -U ${DB_USER} -d postgres -v ON_ERROR_STOP=0 -c "ALTER DATABASE template1 REFRESH COLLATION VERSION;" >/dev/null 2>&1 || true
psql -h postgres -U ${DB_USER} -d postgres -v ON_ERROR_STOP=0 -c "ALTER DATABASE postgres REFRESH COLLATION VERSION;" >/dev/null 2>&1 || true
# 幂等创建:已存在则跳过;不存在则从 template0 克隆(template0 永远不会有 collation 漂移)
if psql -h postgres -U ${DB_USER} -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='${LANGFUSE_DB_NAME:-langfuse}'" | grep -q 1; then
echo "[langfuse-db-init] database '${LANGFUSE_DB_NAME:-langfuse}' already exists, skipping."
else
psql -h postgres -U ${DB_USER} -d postgres -v ON_ERROR_STOP=1 -c "CREATE DATABASE \"${LANGFUSE_DB_NAME:-langfuse}\" TEMPLATE template0;"
echo "[langfuse-db-init] database '${LANGFUSE_DB_NAME:-langfuse}' created."
fi
echo "[langfuse-db-init] done."
networks:
- WeKnora-network
#restart: "no"
profiles:
- langfuse
- full
Step 4: 配置
shell
# 基本示例配置 复制一份配置文件
cp .env.example .env
在.env 文件中,修改自定义配置,如修改前端端口 FRONTEND_PORT=8082)等
Step 5: 一键拉起微服务集群
启动集群:
bash
# 全量拉起
docker compose --profile full up -d
# 验收服务拓扑与运行状态
docker compose --profile full ps
当所有容器状态显示 Up 或 Up (healthy),并在 PORTS 列看到端口映射时,即可通过浏览器访问你的智能体工作台。
第二篇:深度排障与架构陷阱复盘
如果你在过去的部署中,遇到过容器不断重启、部分服务"离奇失踪"等问题,极大可能是踩中了以下三大架构级陷阱。以下是我的完整排障实录。
陷阱一:CPU 指令集阉割引发 Illegal instruction
异常现场
WeKnora-postgres 容器启动即崩溃,查看日志仅有短短几行,退出码为致命的 132:
running bootstrap script ... ok
Illegal instruction (core dumped)
child process exited with exit code 132
深度剖析
退出码 132 (SIGILL) 代表 CPU 无法识别程序发出的指令。
现代 AI 业务对向量计算性能要求极高,带有向量插件的数据库(如 paradedb 或 pgvector)在编译时,会强制要求宿主机 CPU 支持 AVX2 甚至 FMA 硬件指令集。
当我们的业务运行在虚拟机(KVM/Proxmox等)上时,如果底层的虚拟 CPU 模型被设置成了通用的 kvm64,虚拟化层就会无情地阉割掉物理机的 AVX2 指令集,导致容器引擎直接崩溃。
检测是否支持avx2指令集
shell
grep -q avx2 /proc/cpuinfo && echo "AVX2 supported" || echo "AVX2 not supported"
破局之道
如果是虚拟机 :必须从 Hypervisor 层解决。进入虚拟化管理后台,将该虚拟机的 CPU 类型修改为 Host(直通模式) ,让其直接调用物理硬件指令集。注意:必须彻底关机后重开 方能生效。
如果还是不行建议更换支持avx2的机器
如果是物理机器: 目前看来要不降级 postgres 版本 要不更换支持avx2的机器(推荐)
另外可关注已提交的官方问题
https://github.com/Tencent/WeKnora/issues/271
陷阱二:引擎背刺 ------ Docker 29 time 命名空间冲突
异常现场
在纯正的 Ubuntu 物理节点上全新安装 Docker 后,docker compose up 遭到 Daemon 秒拒:
Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: namespace {"time" ""} does not exist
深度剖析
这是 Docker v29.x 引入的 Private Time Namespace(私有时间命名空间) 惹的祸。该特性本意是隔离容器时间,但部分 Linux 内核与底层 runc 的安全策略尚未完美兼容。当容器向内核索要 time 命名空间时遭拒,导致整个创建流程阻断。
破局之道
既然超前特性引发了兼容性灾难,最快的方法就是主动降级,显式禁用该特性。即在 /etc/docker/daemon.json 中配置 "features": { "time-namespaces": false } 并重启引擎。(详见第一篇 Step 3)
陷阱三:容器编排的"假健康"与依赖熔断
异常现场
底层组件均已就绪(Postgres 显示 Healthy),但负责初始化的容器 langfuse-db-init 却报错 Connection refused。更致命的是,排在它后面的前端 UI 和 Web 管理容器根本不启动。
深度剖析
这是微服务编排中最经典的 Race Condition(时序错位) 。
Postgres 首次挂载空卷启动时,会先拉起一个临时实例建表,随后关闭临时实例 ,最后才拉起正式实例。
Docker 的健康探针常常在"临时实例"存活期间就被骗过了,打上了 Healthy 标记,导致 db-init 脚本过早入场,一头撞死在 Postgres 的关机空窗期。
而 Docker Compose 存在严格的依赖链保护机制:一旦初始化节点(db-init)失败,所有依赖它的前端服务全部遭遇依赖熔断,被引擎静默抛弃。
破局之道
不要试图用 sleep 脚本去对抗不确定的 I/O 延迟。用架构的思维解决:为该一次性容器赋予容错自愈能力 。
通过在 Compose 文件中为初始化容器配置 restart: on-failure 策略(详见第一篇 Step 3)。即使它不幸撞上空窗期失败,也会在退避 5 秒后自动重试。只要最终执行成功(exit 0),原本被熔断的前端链路将如多米诺骨牌般自动拉起。
结语
在落地私有化 AI 基础设施时,排障视野必须向下穿透:敬畏硬件算力边界(AVX2),警惕运行时引擎特性(Namespace),驾驭服务启动时序(状态机容错)。用架构思维打好地基,才能让上层的智能体跑得更加稳健。
good day!!!