部署文档-从零开始.md 9.3 KB

Wenshu Platform 部署文档

Ubuntu 22.04 + 8vCPU + 32GB RAM + 100GB SSD (不含业务数据)

1. 安装系统依赖

sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg lsb-release jq unzip tar git wget

设置服务器 IP 变量(填写这台机器的真实内网/公网 IP,不要填 127.0.0.1

export SERVER_IP=<this_machine_ip>
echo 'export SERVER_IP=<this_machine_ip>' >> ~/.bashrc

2. 安装 Docker 与 Docker Compose

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo \"$VERSION_CODENAME\") stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker

docker --version
docker compose version

3. 获取代码

cd ~
git clone <你的仓库地址> wenshu-platform
cd wenshu-platform

4. 准备统一配置(.env

cp .env.example .env

编辑 .env,只需要维护人工配置项(代码参数统一在 application.yml 默认值):

  • MYSQL_URL(唯一 MySQL 地址:本地 compose 用 mysql:3306,远程数据库填 <host>:<port>
  • MYSQL_USER
  • MYSQL_PASSWORD
  • MYSQL_ROOT_PASSWORD(仅本地启动 MySQL 容器时使用)
  • SERVER_IP(必须;同机部署时只填这一项机器 IP,例如 192.168.1.10
  • POLARIS_POSTGRES_PASSWORD
  • POLARIS_CLIENT_SECRET
  • OSS_ENDPOINT
  • OSS_AK
  • OSS_SK
  • OSS_BUCKET
  • STOCK_SSH_CRYPTO_KEY(至少 32 位)
  • K8S_KUBECONFIG_PATH(宿主机 kubeconfig 绝对路径,例如 /root/.kube/config

说明:

  • 后端只认 MYSQL_URL 这一个地址配置。
  • 如果你把 MYSQL_URL 配成远程地址,后端会连接远程库。
  • StarRocks 集群创建后会自动初始化 external catalog polaris(不需要手工在 FE 里执行 CREATE EXTERNAL CATALOG)。
  • Polaris/StarRocks 地址统一按 SERVER_IP 生成:http://<SERVER_IP>:8181(仅在你手工设置 POLARIS_HOST 时才覆盖)。
  • Polaris 凭证选择顺序(给 StarRocks bootstrap 用): 1) POLARIS_CATALOG_OAUTH2_CREDENTIAL 2) 自动拼接 ${POLARIS_CLIENT_ID}:${POLARIS_CLIENT_SECRET}

5. 一键部署 Kubernetes 控制平面与 Operator(必须先执行)

cd ~/wenshu-platform
chmod +x scripts/install-k8s-control-plane.sh scripts/install-k8s-operators.sh

# 写入 kubeconfig 路径(已存在则跳过)
grep -q '^K8S_KUBECONFIG_PATH=' .env || echo "K8S_KUBECONFIG_PATH=$HOME/.kube/config" >> .env

# 1) 安装单机 K8s 控制平面
bash scripts/install-k8s-control-plane.sh

# 2) 安装 Spark + StarRocks Operator
bash scripts/install-k8s-operators.sh

# 3) 生成永久 join 命令(用于后续“新增机器/纳管”)
JOIN_CMD="$(kubeadm token create --ttl 0 --print-join-command)"
sed -i "s|^KUBEADM_JOIN_COMMAND=.*|KUBEADM_JOIN_COMMAND=${JOIN_CMD}|" .env

# 4) 验证
kubectl get nodes -o wide
kubectl get crd sparkapplications.sparkoperator.k8s.io
kubectl get crd starrocksclusters.starrocks.com
kubectl get pods -n spark-operator
kubectl get pods -n starrocks

说明:

  • Operator 以 Kubernetes Pod 方式运行(通过 Helm/kubectl 安装),不属于 docker compose 容器。

6. 启动平台全部服务(包含 k8s-orchestrator)

cd ~/wenshu-platform
mkdir -p data/mysql data/milvus/etcd data/milvus/minio data/milvus/milvus \
         data/polaris/postgres data/huggingface

docker compose up -d --build
docker compose ps

说明:

  • docker compose up -d --build 默认会启动 ws-orchestrator-apiws-orchestrator-controller,不需要单独再起。

7. 初始化 Polaris(幂等,可重复执行)

cd ~/wenshu-platform

# 等待 Polaris healthy
until [ "$(docker inspect -f '{{.State.Health.Status}}' ws-polaris 2>/dev/null)" = "healthy" ]; do
  sleep 3
done

set -a
source .env
set +a

NET="$(basename "$PWD")_default"

get_token() {
  curl -s -X POST http://localhost:8181/api/catalog/v1/oauth/tokens \
    -H "Polaris-Realm: ${POLARIS_REALM:-POLARIS}" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    --data "grant_type=client_credentials&client_id=${POLARIS_CLIENT_ID:-root}&client_secret=${POLARIS_CLIENT_SECRET}&scope=PRINCIPAL_ROLE:ALL" \
    | jq -r '.access_token // empty'
}

TOKEN="$(get_token)"
if [ -z "$TOKEN" ]; then
  docker run --rm --network "$NET" \
    --env="polaris.persistence.type=relational-jdbc" \
    --env="quarkus.datasource.username=${POLARIS_POSTGRES_USER:-polaris}" \
    --env="quarkus.datasource.password=${POLARIS_POSTGRES_PASSWORD}" \
    --env="quarkus.datasource.jdbc.url=jdbc:postgresql://polaris-postgres:5432/${POLARIS_POSTGRES_DB:-polaris}" \
    apache/polaris-admin-tool:1.3.0-incubating \
    bootstrap -r "${POLARIS_REALM:-POLARIS}" -c "${POLARIS_REALM:-POLARIS},${POLARIS_CLIENT_ID:-root},${POLARIS_CLIENT_SECRET}"

  TOKEN="$(get_token)"
fi

[ -n "$TOKEN" ] || { echo "Polaris 初始化失败"; exit 1; }

CATALOG_NAME="${POLARIS_DEFAULT_CATALOG:-demo_catalog}"
BASE_LOCATION="s3://${OSS_BUCKET}/${CATALOG_NAME}"

if curl -s http://localhost:8181/api/management/v1/catalogs \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Polaris-Realm: ${POLARIS_REALM:-POLARIS}" \
  | jq -e --arg n "$CATALOG_NAME" '.catalogs[]? | select(.name == $n)' >/dev/null; then
  echo "Catalog ${CATALOG_NAME} 已存在,跳过创建"
else
  cat <<JSON | curl -s -X POST http://localhost:8181/api/management/v1/catalogs \
    -H "Authorization: Bearer ${TOKEN}" \
    -H "Polaris-Realm: ${POLARIS_REALM:-POLARIS}" \
    -H "Content-Type: application/json" \
    -d @- | jq .
{
  "catalog": {
    "type": "INTERNAL",
    "name": "${CATALOG_NAME}",
    "properties": {
      "default-base-location": "${BASE_LOCATION}"
    },
    "storageConfigInfo": {
      "storageType": "S3",
      "allowedLocations": ["${BASE_LOCATION}"],
      "region": "${OSS_REGION:-cn-hangzhou}",
      "endpoint": "${OSS_ENDPOINT:-https://oss-cn-hangzhou.aliyuncs.com}",
      "pathStyleAccess": false,
      "stsUnavailable": true
    }
  }
}
JSON
fi

curl -s http://localhost:8181/api/management/v1/catalogs \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Polaris-Realm: ${POLARIS_REALM:-POLARIS}" | jq '.catalogs[].name'

说明:

  • 这一步只负责初始化 Polaris 服务端(管理面 catalog、凭证等)。
  • StarRocks external catalog polaris 会在“创建 StarRocks 集群并进入 READY 后”由 ws-orchestrator-controller 自动创建。
  • 任务执行阶段默认只做 SET CATALOG polaris,不会再每次重复建 catalog。

7.1 StarRocks 自动 bootstrap 验证(推荐)

创建 StarRocks 集群后,查看 controller 日志中是否出现 bootstrap 成功信息:

docker compose logs -f ws-orchestrator-controller

如果出现 Failed to load rest catalog,优先检查:

  1. SERVER_IP 是否填写为这台机器对 K8s Pod 可达的 IP(不要填 127.0.0.1)。
  2. POLARIS_CLIENT_ID / POLARIS_CLIENT_SECRET(或 POLARIS_CATALOG_OAUTH2_CREDENTIAL)是否正确。
  3. 修改 .env 后是否已重启 ws-orchestrator-controller
docker compose up -d --build ws-orchestrator-controller

8. 一键验收(全部通过即部署完成)

cd ~/wenshu-platform
set -a
source .env
set +a

echo "=== MySQL ==="
docker exec ws-mysql mysqladmin ping -h localhost -u"${MYSQL_USER}" -p"${MYSQL_PASSWORD}" --silent >/dev/null && echo "OK"

echo "=== Milvus ==="
curl -sf http://localhost:9091/healthz >/dev/null && echo "OK"

echo "=== TEI Embedding ==="
LEN=$(curl -s http://localhost:7997/v1/embeddings \
  -H 'Content-Type: application/json' \
  -d "{\"model\":\"${TEI_MODEL_ID:-intfloat/multilingual-e5-base}\",\"input\":\"passage: 测试文本\"}" | jq -r '.data[0].embedding | length')
echo "embedding_len=${LEN}"
[ "${LEN}" = "768" ] && echo "OK"

echo "=== Polaris ==="
CODE=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:8181/api/catalog/v1/config)
echo "http=${CODE}"
([ "${CODE}" = "200" ] || [ "${CODE}" = "401" ]) && echo "OK"

echo "=== Backend ==="
CODE=$(curl -s -o /dev/null -w '%{http_code}' -X POST http://localhost:8080/api/auth/login -H 'Content-Type: application/json' -d '{}')
echo "http=${CODE}"
([ "${CODE}" = "200" ] || [ "${CODE}" = "400" ] || [ "${CODE}" = "422" ]) && echo "OK"

echo "=== Python Iceberg ==="
curl -sf http://localhost:8090/health >/dev/null && echo "OK"

echo "=== Frontend ==="
CODE=$(curl -s -o /dev/null -w '%{http_code}' http://localhost/)
echo "http=${CODE}"
[ "${CODE}" = "200" ] && echo "OK"

echo "=== Orchestrator API ==="
curl -sf http://localhost:18080/healthz >/dev/null && echo "OK"

9. 常用运维命令

cd ~/wenshu-platform

# 查看状态
docker compose ps

# 查看日志
docker compose logs -f backend
docker compose logs -f ws-orchestrator-api
docker compose logs -f ws-orchestrator-controller

# 重启单个服务
docker compose restart backend

# 停止(保留数据)
docker compose down

# 停止并删除数据(谨慎)
docker compose down -v

# 代码更新后重建
git pull
docker compose up -d --build