从 0 到 1 WeKnora部署指南与深度排障

前言

在构建集成大模型与多智能体的企业级知识库系统(如 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!!!