多服务器集群部署

本文档介绍如何在多台服务器上部署 Data Agent 集群,适用于需要高可用但不使用 Kubernetes 的场景。

前置条件
  • 至少 3 台 Linux 服务器(以 CentOS 为例)
  • 所有服务器需具备 sudo 权限
  • 服务器之间网络互通
  • 已阅读 环境变量 文档

机器推荐配置

每台服务器的配置要求:

项目最低推荐
Linux 内核版本3.10 及以上3.10 及以上
位数64 位64 位
内存8GB32GB 及以上
硬盘(要求固态)30GB 及以上60GB 及以上

架构概述

                    ┌─────────────────┐
                    │   负载均衡器     │
                    │  (Nginx/HAProxy) │
                    └────────┬────────┘

        ┌────────────────────┼────────────────────┐
        │                    │                    │
        ▼                    ▼                    ▼
┌───────────────┐   ┌───────────────┐   ┌───────────────┐
│   服务器 1     │   │   服务器 2     │   │   服务器 3     │
│  App + PG主   │   │  App + PG从   │   │  App + PG从   │
└───────────────┘   └───────────────┘   └───────────────┘

部署说明:

  • 每台服务器运行一个 Data Agent 应用实例
  • PostgreSQL 可选择外部数据库或本地集群部署(1 主 2 从)
  • 应用层通过负载均衡器分发请求
  • 所有应用实例连接同一个 PostgreSQL 主库

1. 安装 Docker

每台服务器 上安装 Docker,安装方式与单台服务器部署相同。

1.1 Linux 在线安装

参考 Docker 官方文档:Install Docker Engine on CentOS

1.2 Linux 离线安装

如服务器无法访问外网,可使用离线安装方式。

注意

仅支持 x86_64 架构的 Linux 服务器。

1. 下载离线安装文件

下载以下三个文件并放置在同一目录下:

文件下载地址
Docker 离线安装包docker-27.5.1.tgz
Docker Composedocker-compose-linux-x86_64
安装脚本docker-install.sh(见下方折叠内容)
docker-install.sh 脚本内容(点击展开)
#!/bin/bash

set -e  # 遇到错误即退出

# 设置文件名
docker_file="docker-27.5.1.tgz"
docker_compose_file="docker-compose-linux-x86_64"

# 检查架构
ARCH=$(uname -m)
if [ "$ARCH" != "x86_64" ]; then
    echo "当前服务器的架构是: $ARCH,仅支持x86_64架构"
    exit 1
fi

echo "当前服务器的架构是 x86_64 (64-bit),继续进行"


install_docker(){
    # 检查文件是否存在(内网环境,不进行下载,仅检查文件是否存在)
    if [[ ! -f "$docker_file" || ! -f "$docker_compose_file" ]]; then
        echo "错误:未在当前目录找到必要的安装文件!"
        echo "请确保 $docker_file 和 $docker_compose_file 已放置在脚本同路径下"
        exit 1
    fi

    # 执行离线安装 Docker
    offline_install() {
        local origin_path=$(pwd)  # 记录当前目录
        file_path=$(pwd)  # 设置离线文件所在目录为当前目录

        # 解压 Docker 文件并安装
        cd $file_path
        tar xzvf $docker_file
        cp -rf docker/* /usr/bin/  # 复制 Docker 可执行文件到 /usr/bin/
        rm -rf docker  # 删除解压后的临时文件
        cd ${origin_path} >/dev/null  # 回到原来的目录
    }

    # 写入 Docker systemd 服务配置
    write_service() {
        mkdir -p /usr/lib/systemd/system/

        # 定义 Docker 服务配置内容
        docker_service_config="[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP \$MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target"

        # 将服务配置内容写入 docker.service 文件
        echo "$docker_service_config" > /usr/lib/systemd/system/docker.service
    }

    # 执行离线安装步骤
    offline_install
    write_service
    systemctl daemon-reload

    # 安装 Docker Compose
    mv $docker_compose_file docker-compose
    mv docker-compose /usr/local/bin/
    chmod +x /usr/local/bin/docker-compose

    # 判断是否存在 systemctl
    if command -v systemctl &>/dev/null; then
        # 启用并重启 Docker 服务
        systemctl enable docker.service
        systemctl restart docker
    else
        echo "未找到 systemctl,无法管理 Docker 服务。"
    fi

    echo "Docker 和 Docker Compose 安装完成!"
}


# 检查 docker 是否存在
if ! command -v docker &> /dev/null; then
    echo "未安装 Docker,开始安装..."
    install_docker && echo "Docker 安装完成"
else
    echo "Docker 已安装,版本:$(docker --version)"
    # 检查 docker compose(支持新版和旧版)
    if command -v docker-compose &> /dev/null; then
        echo "安装了旧版 docker-compose,版本:$(docker-compose --version)"
    elif docker compose version &> /dev/null; then
        echo "安装了新版 Docker Compose,版本:$(docker compose version --short)"
    else
        echo "未安装 Docker Compose,开始安装..."
        install_docker && echo "Docker Compose 安装完成"
    fi
fi

echo "所有任务执行完毕!"

2. 执行安装脚本

在每台服务器上执行:

# 赋予脚本执行权限
chmod +x docker-install.sh

# 执行安装脚本
sudo ./docker-install.sh

1.3 验证安装

在每台服务器上验证:

# 检查 Docker 是否正常运行
sudo docker ps

# 检查 Compose 插件是否安装
sudo docker-compose --version

# 设置开机自启(如未设置)
sudo systemctl enable docker

2. 网络规划

假设三台服务器 IP 如下(请根据实际情况替换):

角色IP 地址说明
服务器 1192.168.1.101PostgreSQL 主库 + App
服务器 2192.168.1.102PostgreSQL 从库 + App
服务器 3192.168.1.103PostgreSQL 从库 + App

2.1 防火墙配置

确保以下端口在服务器之间互通:

端口用途
5432PostgreSQL
3052Data Agent 应用
# CentOS/RHEL 防火墙配置示例
sudo firewall-cmd --permanent --add-port=5432/tcp
sudo firewall-cmd --permanent --add-port=3052/tcp
sudo firewall-cmd --reload

3. PostgreSQL 数据库配置

根据实际情况选择以下两种方案之一。

数据库部署方案
  • 方案 A:使用外部 PostgreSQL 数据库(客户自备,单机或集群均可)
  • 方案 B:在三台服务器上部署新的 PostgreSQL 主从集群

3.1 方案 A:使用外部 PostgreSQL 数据库

如果已有 PostgreSQL 数据库(单机或集群),可直接使用。

数据库要求

要求说明
版本PostgreSQL 17 及以上
扩展需安装 pgvector 扩展
权限专用账号需具备专用库的读写权限

请让数据库管理员为 Data Agent 创建专用账号和专用库,并授予读写权限。

配置完成后,跳转到 4. 验证应用状态


3.2 方案 B:部署 PostgreSQL 主从集群

在三台服务器上部署 PostgreSQL,采用流复制(Streaming Replication)实现 1 主 2 从架构。PostgreSQL 与应用服务共用同一个 docker-compose.yml 文件。

3.2.1 主库配置(服务器 1)

在服务器 1 上创建部署目录并配置 docker-compose.yml

mkdir -p /opt/data-agent
cd /opt/data-agent

创建 docker-compose.yml(主库配置):

services:
  app:
    image: chatbi/yiask:latest
    container_name: yiask
    restart: always
    environment:
      - PROJECT=prod-agent
      - LOGGER_LEVEL=error
      - DB_HOST=postgres
      - DB_DATABASE=mydatabase
      - DB_USER=postgres
      - DB_PASSWORD=your_strong_password
    volumes:
      - storage:/app/nocobase/storage
    depends_on:
      - postgres
    ports:
      - "3052:80"
    init: true
    extra_hosts:
      - "host.docker.internal:host-gateway"

  postgres:
    container_name: postgres-primary
    image: pgvector/pgvector:pg17-trixie
    restart: always
    command: >
      postgres
      -c wal_level=replica
      -c max_wal_senders=10
      -c max_replication_slots=10
      -c hot_standby=on
      -c listen_addresses='*'
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: your_strong_password
      POSTGRES_DB: mydatabase
    volumes:
      - pg-data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  storage:
  pg-data:

启动服务:

sudo docker-compose up -d

等待主库完全启动后,再配置从库。

3.2.2 从库配置(服务器 2 和 3)

在服务器 2 和服务器 3 上分别执行以下步骤。

创建部署目录:

mkdir -p /opt/data-agent
cd /opt/data-agent

创建 docker-compose.yml(从库配置):

services:
  app:
    image: chatbi/yiask:latest
    container_name: yiask
    restart: always
    environment:
      - PROJECT=prod-agent
      - LOGGER_LEVEL=error
      # 注意:从库的应用也连接主库
      - DB_HOST=192.168.1.101
      - DB_DATABASE=mydatabase
      - DB_USER=postgres
      - DB_PASSWORD=your_strong_password
    volumes:
      - storage:/app/nocobase/storage
    ports:
      - "3052:80"
    init: true
    extra_hosts:
      - "host.docker.internal:host-gateway"

  postgres:
    container_name: postgres-replica
    image: pgvector/pgvector:pg17-trixie
    restart: always
    command: >
      postgres
      -c hot_standby=on
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: your_strong_password
      POSTGRES_DB: mydatabase
    volumes:
      - pg-data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  storage:
  pg-data:

初始化从库数据(从主库同步):

# 使用 pg_basebackup 从主库同步数据
# 注意:将 192.168.1.101 替换为主库实际 IP

sudo docker run --rm \
  -v data-agent_pg-data:/var/lib/postgresql/data \
  pgvector/pgvector:pg17-trixie \
  bash -c "
    rm -rf /var/lib/postgresql/data/*
    PGPASSWORD='replicator_password' pg_basebackup \
      -h 192.168.1.101 \
      -U replicator \
      -D /var/lib/postgresql/data \
      -Fp -Xs -P -R
  "

# 启动服务
sudo docker-compose up -d
注意
  • 192.168.1.101 替换为主库实际 IP
  • 确保主库已完全启动后再执行从库同步
  • -R 参数会自动创建 standby.signal 文件和配置复制连接
  • 从库上的应用服务 DB_HOST 应填写主库 IP,确保写操作指向主库

3.2.3 验证集群状态

在主库服务器上验证复制状态:

sudo docker exec -it postgres-primary psql -U postgres -c "SELECT client_addr, state, sync_state FROM pg_stat_replication;"

正常输出应显示两个从库连接:

  client_addr   |   state   | sync_state
----------------+-----------+------------
 192.168.1.102  | streaming | async
 192.168.1.103  | streaming | async

4. 验证应用状态

在每台服务器上验证:

# 查看容器状态
sudo docker ps

# 查看日志
sudo docker-compose logs -f

访问 http://<服务器IP>:3052 确认应用正常运行。


5. 负载均衡配置

使用 Nginx、HAProxy 或其他负载均衡器将请求分发到多个应用实例。

配置要点:

  • 后端服务器地址:各服务器的 3052 端口
  • 建议使用 least_conn(最少连接)负载均衡策略
  • 需支持 WebSocket 连接(配置 UpgradeConnection 头)

6. 运维管理

6.1 查看集群状态

# PostgreSQL 复制状态(在主库执行)
sudo docker exec -it postgres-primary psql -U postgres -c "SELECT * FROM pg_stat_replication;"

# 应用容器状态
sudo docker ps

6.2 日志查看

# PostgreSQL 日志
sudo docker logs -f postgres-primary

# 应用日志
sudo docker logs -f yiask

6.3 故障切换

PostgreSQL 原生流复制不支持自动故障切换,当主库故障时需要手动将从库提升为主库。如需自动故障切换,可考虑使用 Patroni、repmgr 等高可用方案。

手动切换步骤:

# 在从库服务器上执行
sudo docker exec -it postgres-replica psql -U postgres -c "SELECT pg_promote();"

提升后,更新所有应用实例的 docker-compose.yml 中的 DB_HOST,将其指向新主库,然后重启应用:

sudo docker-compose down && sudo docker-compose up -d

7. 常见问题

7.1 从库无法连接主库

检查以下几点:

  • 主库 pg_hba.conf 是否允许从库 IP 连接
  • 防火墙是否开放 5432 端口
  • 复制用户密码是否正确

7.2 应用无法连接数据库

# 在应用服务器上测试
docker run --rm pgvector/pgvector:pg17-trixie psql -h <数据库IP> -U postgres -d mydatabase

7.3 存储不同步

各应用实例的上传文件默认不会同步。如需共享存储,可使用 NFS 或对象存储方案。


完成以上配置后,Data Agent 集群即可对外提供高可用服务。