代码部署说明
This commit is contained in:
1 parent
221e947488
commit
55b5c2cc9f
7 files changed
+727
No files matched your search
@@ -0,0 +1,17 @@
|
||||
.git
|
||||
.pytest_cache
|
||||
.ruff_cache
|
||||
.venv
|
||||
__pycache__
|
||||
*.py[cod]
|
||||
*.pyo
|
||||
*.zip
|
||||
|
||||
# Runtime state is mounted from the host in Docker deployments.
|
||||
.deer-flow
|
||||
logs
|
||||
|
||||
# Local/offline artifacts should not be baked into the runtime image.
|
||||
docker-data
|
||||
dist
|
||||
wheelhouse
|
||||
@@ -0,0 +1,52 @@
|
||||
# Backend Docker Offline Deployment
|
||||
|
||||
Build once on an online Linux server:
|
||||
|
||||
```bash
|
||||
cd offline-backend-20260512/backend
|
||||
chmod +x build-backend-image.sh save-backend-image.sh start-backend-docker.sh
|
||||
./build-backend-image.sh
|
||||
./save-backend-image.sh
|
||||
```
|
||||
|
||||
The build script defaults to Aliyun for apt packages and Tsinghua for Python packages:
|
||||
|
||||
```bash
|
||||
APT_MIRROR=mirrors.aliyun.com \
|
||||
UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple/ \
|
||||
./build-backend-image.sh
|
||||
```
|
||||
|
||||
The Docker build installs the pinned `requirements-offline.txt` with pip from
|
||||
the configured Python mirror, so the dependency image contains the backend
|
||||
runtime dependencies and can be moved to an offline machine.
|
||||
|
||||
Move `dist/deerflow-backend-offline.tar` plus this backend directory to the
|
||||
offline machine, then load and start:
|
||||
|
||||
```bash
|
||||
docker load -i deerflow-backend-offline.tar
|
||||
./start-backend-docker.sh 8001
|
||||
```
|
||||
|
||||
Useful overrides:
|
||||
|
||||
```bash
|
||||
BACKEND_PORT=9001 ./start-backend-docker.sh
|
||||
IMAGE_NAME=your-image:tag ./start-backend-docker.sh 9001
|
||||
DATA_DIR=/data/deerflow-backend ./start-backend-docker.sh
|
||||
```
|
||||
|
||||
The startup script bind-mounts these host paths:
|
||||
|
||||
- backend code: current backend directory -> `/app/backend`
|
||||
- config: `docker-data/config/config.yaml`, `extensions_config.json`, `.env`
|
||||
- agents and SQLite/runtime data: `docker-data/.deer-flow`
|
||||
- skills: `docker-data/skills`
|
||||
- logs: `docker-data/logs`
|
||||
|
||||
Edit files under `docker-data/` on the host, then restart the container:
|
||||
|
||||
```bash
|
||||
docker restart deerflow-backend
|
||||
```
|
||||
@@ -0,0 +1,108 @@
|
||||
# Backend-only DeerFlow image for offline delivery.
|
||||
#
|
||||
# Build online once, then export with:
|
||||
# docker save deerflow-backend-offline:latest -o deerflow-backend-offline.tar
|
||||
#
|
||||
# Runtime code/config/data are bind-mounted by start-backend-docker.sh so the
|
||||
# customer can edit code, agents, skills, config.yaml, .env, and SQLite data
|
||||
# without rebuilding this dependency image.
|
||||
|
||||
ARG PYTHON_IMAGE=python:3.12-slim-bookworm
|
||||
|
||||
FROM ${PYTHON_IMAGE} AS builder
|
||||
|
||||
ARG APT_MIRROR=mirrors.aliyun.com
|
||||
ARG UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple/
|
||||
ARG UV_VERSION=0.7.20
|
||||
ARG UV_NO_CACHE=1
|
||||
ARG UV_COMPILE_BYTECODE=0
|
||||
|
||||
ENV UV_PROJECT_ENVIRONMENT=/opt/venv \
|
||||
UV_INDEX_URL=${UV_INDEX_URL} \
|
||||
UV_LINK_MODE=copy \
|
||||
UV_NO_CACHE=${UV_NO_CACHE} \
|
||||
UV_COMPILE_BYTECODE=${UV_COMPILE_BYTECODE} \
|
||||
PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1
|
||||
|
||||
WORKDIR /build/backend
|
||||
|
||||
RUN if [ -n "${APT_MIRROR}" ]; then \
|
||||
sed -i "s|deb.debian.org|${APT_MIRROR}|g" /etc/apt/sources.list.d/debian.sources 2>/dev/null || true; \
|
||||
sed -i "s|security.debian.org|${APT_MIRROR}|g" /etc/apt/sources.list.d/debian.sources 2>/dev/null || true; \
|
||||
sed -i "s|deb.debian.org|${APT_MIRROR}|g" /etc/apt/sources.list 2>/dev/null || true; \
|
||||
sed -i "s|security.debian.org|${APT_MIRROR}|g" /etc/apt/sources.list 2>/dev/null || true; \
|
||||
fi \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
curl \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& python -m pip install --no-cache-dir -i "${UV_INDEX_URL}" "uv==${UV_VERSION}"
|
||||
|
||||
ARG UV_HTTP_TIMEOUT=300
|
||||
ARG UV_CONCURRENT_DOWNLOADS=4
|
||||
ARG UV_CONCURRENT_INSTALLS=4
|
||||
ARG UV_CONCURRENT_BUILDS=2
|
||||
|
||||
ENV UV_HTTP_TIMEOUT=${UV_HTTP_TIMEOUT} \
|
||||
UV_CONCURRENT_DOWNLOADS=${UV_CONCURRENT_DOWNLOADS} \
|
||||
UV_CONCURRENT_INSTALLS=${UV_CONCURRENT_INSTALLS} \
|
||||
UV_CONCURRENT_BUILDS=${UV_CONCURRENT_BUILDS}
|
||||
|
||||
COPY pyproject.toml uv.lock README.md requirements-offline.txt ./
|
||||
COPY packages ./packages
|
||||
|
||||
RUN python -m venv /opt/venv \
|
||||
&& /opt/venv/bin/python -m pip install --no-cache-dir --upgrade -i "${UV_INDEX_URL}" pip setuptools wheel \
|
||||
&& sed -E '/--hash=/d; s/[[:space:]]+\\$//; s|^-e[[:space:]]+./packages/harness$|./packages/harness|' requirements-offline.txt > /tmp/requirements-docker.txt \
|
||||
&& /opt/venv/bin/pip install --no-cache-dir -i "${UV_INDEX_URL}" -r /tmp/requirements-docker.txt \
|
||||
&& /opt/venv/bin/pip install --no-cache-dir -i "${UV_INDEX_URL}" "asyncmy>=0.2.11"
|
||||
|
||||
COPY . .
|
||||
|
||||
FROM ${PYTHON_IMAGE} AS runtime
|
||||
|
||||
ARG APT_MIRROR=mirrors.aliyun.com
|
||||
|
||||
ENV PATH=/opt/venv/bin:$PATH \
|
||||
PYTHONPATH=/app/backend:/app/backend/packages/harness \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
DEER_FLOW_PROJECT_ROOT=/app/backend \
|
||||
DEER_FLOW_HOME=/app/backend/.deer-flow \
|
||||
DEER_FLOW_CONFIG_PATH=/app/backend/config.yaml \
|
||||
DEER_FLOW_EXTENSIONS_CONFIG_PATH=/app/backend/extensions_config.json \
|
||||
DEER_FLOW_SKILLS_PATH=/app/backend/skills \
|
||||
BACKEND_PORT=8001
|
||||
|
||||
WORKDIR /app/backend
|
||||
|
||||
RUN if [ -n "${APT_MIRROR}" ]; then \
|
||||
sed -i "s|deb.debian.org|${APT_MIRROR}|g" /etc/apt/sources.list.d/debian.sources 2>/dev/null || true; \
|
||||
sed -i "s|security.debian.org|${APT_MIRROR}|g" /etc/apt/sources.list.d/debian.sources 2>/dev/null || true; \
|
||||
sed -i "s|deb.debian.org|${APT_MIRROR}|g" /etc/apt/sources.list 2>/dev/null || true; \
|
||||
sed -i "s|security.debian.org|${APT_MIRROR}|g" /etc/apt/sources.list 2>/dev/null || true; \
|
||||
fi \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
curl \
|
||||
docker.io \
|
||||
libmagic1 \
|
||||
nodejs \
|
||||
npm \
|
||||
poppler-utils \
|
||||
tini \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /opt/venv /opt/venv
|
||||
COPY --from=builder /build/backend /app/backend
|
||||
|
||||
EXPOSE 8001
|
||||
|
||||
ENTRYPOINT ["tini", "--"]
|
||||
CMD ["sh", "-c", "cd /app/backend && exec uvicorn app.gateway.app:app --host 0.0.0.0 --port ${BACKEND_PORT:-8001}"]
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
IMAGE_NAME="${IMAGE_NAME:-deerflow-backend-offline:latest}"
|
||||
APT_MIRROR="${APT_MIRROR:-mirrors.aliyun.com}"
|
||||
UV_INDEX_URL="${UV_INDEX_URL:-https://pypi.tuna.tsinghua.edu.cn/simple/}"
|
||||
UV_HTTP_TIMEOUT="${UV_HTTP_TIMEOUT:-300}"
|
||||
UV_NO_CACHE="${UV_NO_CACHE:-1}"
|
||||
UV_COMPILE_BYTECODE="${UV_COMPILE_BYTECODE:-0}"
|
||||
UV_CONCURRENT_DOWNLOADS="${UV_CONCURRENT_DOWNLOADS:-4}"
|
||||
UV_CONCURRENT_INSTALLS="${UV_CONCURRENT_INSTALLS:-4}"
|
||||
UV_CONCURRENT_BUILDS="${UV_CONCURRENT_BUILDS:-2}"
|
||||
PYTHON_IMAGE="${PYTHON_IMAGE:-python:3.12-slim-bookworm}"
|
||||
|
||||
cd "${SCRIPT_DIR}"
|
||||
|
||||
docker build \
|
||||
-f Dockerfile.backend-offline \
|
||||
-t "${IMAGE_NAME}" \
|
||||
--build-arg "PYTHON_IMAGE=${PYTHON_IMAGE}" \
|
||||
--build-arg "APT_MIRROR=${APT_MIRROR}" \
|
||||
--build-arg "UV_INDEX_URL=${UV_INDEX_URL}" \
|
||||
--build-arg "UV_HTTP_TIMEOUT=${UV_HTTP_TIMEOUT}" \
|
||||
--build-arg "UV_NO_CACHE=${UV_NO_CACHE}" \
|
||||
--build-arg "UV_COMPILE_BYTECODE=${UV_COMPILE_BYTECODE}" \
|
||||
--build-arg "UV_CONCURRENT_DOWNLOADS=${UV_CONCURRENT_DOWNLOADS}" \
|
||||
--build-arg "UV_CONCURRENT_INSTALLS=${UV_CONCURRENT_INSTALLS}" \
|
||||
--build-arg "UV_CONCURRENT_BUILDS=${UV_CONCURRENT_BUILDS}" \
|
||||
.
|
||||
|
||||
echo "Built image: ${IMAGE_NAME}"
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
IMAGE_NAME="${IMAGE_NAME:-deerflow-backend-offline:latest}"
|
||||
OUT_DIR="${OUT_DIR:-${SCRIPT_DIR}/dist}"
|
||||
OUT_FILE="${OUT_FILE:-${OUT_DIR}/deerflow-backend-offline.tar}"
|
||||
|
||||
mkdir -p "${OUT_DIR}"
|
||||
docker save "${IMAGE_NAME}" -o "${OUT_FILE}"
|
||||
|
||||
echo "Saved image: ${OUT_FILE}"
|
||||
echo "Offline load command: docker load -i ${OUT_FILE}"
|
||||
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
IMAGE_NAME="${IMAGE_NAME:-deerflow-backend-offline:latest}"
|
||||
CONTAINER_NAME="${CONTAINER_NAME:-deerflow-backend}"
|
||||
BACKEND_PORT="${1:-${BACKEND_PORT:-8001}}"
|
||||
|
||||
CODE_DIR="${CODE_DIR:-${SCRIPT_DIR}}"
|
||||
DATA_DIR="${DATA_DIR:-${SCRIPT_DIR}/docker-data}"
|
||||
CONFIG_DIR="${CONFIG_DIR:-${DATA_DIR}/config}"
|
||||
RUNTIME_DIR="${RUNTIME_DIR:-${DATA_DIR}/.deer-flow}"
|
||||
SKILLS_DIR="${SKILLS_DIR:-${DATA_DIR}/skills}"
|
||||
KNOWLEDGE_DIR="${KNOWLEDGE_DIR:-${DATA_DIR}/knowledge}"
|
||||
LOGS_DIR="${LOGS_DIR:-${DATA_DIR}/logs}"
|
||||
|
||||
CONFIG_FILE="${CONFIG_DIR}/config.yaml"
|
||||
EXTENSIONS_FILE="${CONFIG_DIR}/extensions_config.json"
|
||||
LANGGRAPH_FILE="${CONFIG_DIR}/langgraph.json"
|
||||
ENV_FILE="${CONFIG_DIR}/.env"
|
||||
|
||||
copy_if_missing() {
|
||||
local src="$1"
|
||||
local dst="$2"
|
||||
if [[ ! -e "${dst}" && -e "${src}" ]]; then
|
||||
mkdir -p "$(dirname "${dst}")"
|
||||
cp -a "${src}" "${dst}"
|
||||
fi
|
||||
}
|
||||
|
||||
copy_dir_if_missing() {
|
||||
local src="$1"
|
||||
local dst="$2"
|
||||
if [[ ! -e "${dst}" && -d "${src}" ]]; then
|
||||
mkdir -p "$(dirname "${dst}")"
|
||||
cp -a "${src}" "${dst}"
|
||||
fi
|
||||
}
|
||||
|
||||
mkdir -p "${CONFIG_DIR}" "${RUNTIME_DIR}/data" "${LOGS_DIR}"
|
||||
|
||||
copy_if_missing "${CODE_DIR}/config.yaml" "${CONFIG_FILE}"
|
||||
copy_if_missing "${CODE_DIR}/extensions_config.json" "${EXTENSIONS_FILE}"
|
||||
copy_if_missing "${CODE_DIR}/langgraph.json" "${LANGGRAPH_FILE}"
|
||||
copy_if_missing "${CODE_DIR}/.env" "${ENV_FILE}"
|
||||
touch "${ENV_FILE}"
|
||||
|
||||
copy_dir_if_missing "${CODE_DIR}/skills" "${SKILLS_DIR}"
|
||||
mkdir -p "${SKILLS_DIR}"
|
||||
|
||||
copy_dir_if_missing "${CODE_DIR}/knowledge" "${KNOWLEDGE_DIR}"
|
||||
mkdir -p "${KNOWLEDGE_DIR}"
|
||||
|
||||
copy_dir_if_missing "${CODE_DIR}/.deer-flow/agents" "${RUNTIME_DIR}/agents"
|
||||
copy_dir_if_missing "${CODE_DIR}/.deer-flow/channels" "${RUNTIME_DIR}/channels"
|
||||
copy_dir_if_missing "${CODE_DIR}/.deer-flow/users" "${RUNTIME_DIR}/users"
|
||||
copy_if_missing "${CODE_DIR}/.deer-flow/SOUL.md" "${RUNTIME_DIR}/SOUL.md"
|
||||
copy_if_missing "${CODE_DIR}/.deer-flow/USER.md" "${RUNTIME_DIR}/USER.md"
|
||||
copy_if_missing "${CODE_DIR}/.deer-flow/system_settings.json" "${RUNTIME_DIR}/system_settings.json"
|
||||
|
||||
if docker ps -a --format '{{.Names}}' | grep -Fxq "${CONTAINER_NAME}"; then
|
||||
docker rm -f "${CONTAINER_NAME}" >/dev/null
|
||||
fi
|
||||
|
||||
DOCKER_ARGS=(
|
||||
run -d
|
||||
--name "${CONTAINER_NAME}"
|
||||
--restart unless-stopped
|
||||
-p "${BACKEND_PORT}:${BACKEND_PORT}"
|
||||
--add-host host.docker.internal:host-gateway
|
||||
-e "BACKEND_PORT=${BACKEND_PORT}"
|
||||
-e "DEER_FLOW_GATEWAY_PORT=${BACKEND_PORT}"
|
||||
-e "DEER_FLOW_PROJECT_ROOT=/app/backend"
|
||||
-e "DEER_FLOW_HOME=/app/backend/.deer-flow"
|
||||
-e "DEER_FLOW_HOST_BASE_DIR=${RUNTIME_DIR}"
|
||||
-e "DEER_FLOW_CONFIG_PATH=/app/backend/config.yaml"
|
||||
-e "DEER_FLOW_EXTENSIONS_CONFIG_PATH=/app/backend/extensions_config.json"
|
||||
-e "DEER_FLOW_SKILLS_PATH=/app/backend/skills"
|
||||
-v "${CODE_DIR}:/app/backend"
|
||||
-v "${CONFIG_FILE}:/app/backend/config.yaml"
|
||||
-v "${EXTENSIONS_FILE}:/app/backend/extensions_config.json"
|
||||
-v "${LANGGRAPH_FILE}:/app/backend/langgraph.json"
|
||||
-v "${ENV_FILE}:/app/backend/.env"
|
||||
-v "${RUNTIME_DIR}:/app/backend/.deer-flow"
|
||||
-v "${SKILLS_DIR}:/app/backend/skills"
|
||||
-v "${KNOWLEDGE_DIR}:/app/backend/knowledge"
|
||||
-v "${LOGS_DIR}:/app/backend/logs"
|
||||
)
|
||||
|
||||
if [[ -S /var/run/docker.sock ]]; then
|
||||
DOCKER_ARGS+=(-v /var/run/docker.sock:/var/run/docker.sock)
|
||||
fi
|
||||
|
||||
DOCKER_ARGS+=("${IMAGE_NAME}")
|
||||
|
||||
docker "${DOCKER_ARGS[@]}"
|
||||
|
||||
echo "Started ${CONTAINER_NAME}"
|
||||
echo "Backend: http://127.0.0.1:${BACKEND_PORT}"
|
||||
echo "Config: ${CONFIG_DIR}"
|
||||
echo "Data: ${DATA_DIR}"
|
||||
@@ -0,0 +1,403 @@
|
||||
# DeerFlow 后台离线部署说明
|
||||
|
||||
本文档只说明“后台服务”的离线部署,不包含前端。
|
||||
|
||||
## 1. 当前服务器文件位置
|
||||
|
||||
当前已经在服务器上准备好的部署目录是:
|
||||
|
||||
```bash
|
||||
/opt/deerflow-backend
|
||||
```
|
||||
|
||||
主要文件和目录如下:
|
||||
|
||||
```text
|
||||
/opt/deerflow-backend/
|
||||
├── dist/deerflow-backend-offline.tar # 离线 Docker 镜像包
|
||||
├── start-backend-docker.sh # 启动脚本
|
||||
├── save-backend-image.sh # 镜像导出脚本
|
||||
├── build-backend-image.sh # 在线构建脚本
|
||||
├── config.yaml # 默认配置模板
|
||||
├── extensions_config.json # 默认扩展配置模板
|
||||
├── langgraph.json # LangGraph 配置
|
||||
├── .env # 环境变量文件,没有则启动脚本会创建空文件
|
||||
├── .deer-flow/agents/ # 默认智能体模板目录
|
||||
├── skills/ # 默认技能模板目录
|
||||
└── docker-data/ # 实际运行时挂载数据,启动后生成
|
||||
```
|
||||
|
||||
当前服务器已验证:
|
||||
|
||||
```bash
|
||||
cd /opt/deerflow-backend
|
||||
./start-backend-docker.sh 8001
|
||||
```
|
||||
|
||||
健康检查:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8001/health
|
||||
curl http://127.0.0.1:8001/api/health
|
||||
```
|
||||
|
||||
## 2. 客户现场更换部署目录
|
||||
|
||||
客户现场可以换任意部署目录,不需要改脚本。把整个 `deerflow-backend` 目录放到目标位置即可。
|
||||
|
||||
示例:客户现场部署到 `/data/deerflow-backend`
|
||||
|
||||
```bash
|
||||
DEPLOY_DIR=/data/deerflow-backend
|
||||
mkdir -p "$DEPLOY_DIR"
|
||||
|
||||
# 将交付的 deerflow-backend 目录内容放到 $DEPLOY_DIR
|
||||
cd "$DEPLOY_DIR"
|
||||
chmod +x *.sh
|
||||
```
|
||||
|
||||
加载离线镜像:
|
||||
|
||||
```bash
|
||||
docker load -i dist/deerflow-backend-offline.tar
|
||||
```
|
||||
|
||||
启动后台,端口可改:
|
||||
|
||||
```bash
|
||||
./start-backend-docker.sh 8001
|
||||
```
|
||||
|
||||
如果客户现场要用 `9001` 端口:
|
||||
|
||||
```bash
|
||||
./start-backend-docker.sh 9001
|
||||
```
|
||||
|
||||
脚本会自动把当前目录作为代码目录,把数据放到:
|
||||
|
||||
```text
|
||||
$DEPLOY_DIR/docker-data
|
||||
```
|
||||
|
||||
## 3. 数据、配置、智能体、技能目录
|
||||
|
||||
启动后,实际可修改的文件都在宿主机目录,不在容器内部。
|
||||
|
||||
默认目录如下:
|
||||
|
||||
```text
|
||||
$DEPLOY_DIR/docker-data/config # 配置目录
|
||||
$DEPLOY_DIR/docker-data/.deer-flow # 运行时目录:智能体、用户数据、SQLite 数据
|
||||
$DEPLOY_DIR/docker-data/skills # 技能目录
|
||||
$DEPLOY_DIR/docker-data/knowledge # 知识库目录
|
||||
$DEPLOY_DIR/docker-data/logs # 日志目录
|
||||
```
|
||||
|
||||
配置文件位置:
|
||||
|
||||
```text
|
||||
$DEPLOY_DIR/docker-data/config/config.yaml
|
||||
$DEPLOY_DIR/docker-data/config/extensions_config.json
|
||||
$DEPLOY_DIR/docker-data/config/langgraph.json
|
||||
$DEPLOY_DIR/docker-data/config/.env
|
||||
```
|
||||
|
||||
智能体目录:
|
||||
|
||||
```text
|
||||
$DEPLOY_DIR/docker-data/.deer-flow/agents
|
||||
```
|
||||
|
||||
技能目录:
|
||||
|
||||
```text
|
||||
$DEPLOY_DIR/docker-data/skills/public
|
||||
$DEPLOY_DIR/docker-data/skills/custom
|
||||
```
|
||||
|
||||
SQLite 聊天/checkpointer 数据库目录:
|
||||
|
||||
```text
|
||||
$DEPLOY_DIR/docker-data/.deer-flow/data
|
||||
$DEPLOY_DIR/docker-data/.deer-flow/.deer-flow/data
|
||||
```
|
||||
|
||||
注意:当前部署使用 **MySQL 业务库 + SQLite 聊天/checkpointer 库**,不使用 PostgreSQL。SQLite 运行时可能同时有以下文件,备份或替换时要一起处理:
|
||||
|
||||
```text
|
||||
deerflow.db
|
||||
deerflow.db-wal
|
||||
deerflow.db-shm
|
||||
```
|
||||
|
||||
## 4. 客户现场加载智能体和技能
|
||||
|
||||
推荐流程:
|
||||
|
||||
1. 先启动一次,让目录自动生成。
|
||||
2. 停止容器。
|
||||
3. 复制客户的智能体、技能、SQLite 聊天库文件,并配置 MySQL 地址。
|
||||
4. 再启动容器。
|
||||
|
||||
命令示例:
|
||||
|
||||
```bash
|
||||
cd "$DEPLOY_DIR"
|
||||
./start-backend-docker.sh 8001
|
||||
docker rm -f deerflow-backend
|
||||
```
|
||||
|
||||
复制智能体:
|
||||
|
||||
```bash
|
||||
mkdir -p "$DEPLOY_DIR/docker-data/.deer-flow/agents"
|
||||
cp -a /path/to/customer-agents/. "$DEPLOY_DIR/docker-data/.deer-flow/agents/"
|
||||
```
|
||||
|
||||
复制技能:
|
||||
|
||||
```bash
|
||||
mkdir -p "$DEPLOY_DIR/docker-data/skills/public"
|
||||
mkdir -p "$DEPLOY_DIR/docker-data/skills/custom"
|
||||
|
||||
cp -a /path/to/customer-skills/public/. "$DEPLOY_DIR/docker-data/skills/public/"
|
||||
cp -a /path/to/customer-skills/custom/. "$DEPLOY_DIR/docker-data/skills/custom/"
|
||||
```
|
||||
|
||||
重新启动:
|
||||
|
||||
```bash
|
||||
cd "$DEPLOY_DIR"
|
||||
./start-backend-docker.sh 8001
|
||||
```
|
||||
|
||||
如果只更新技能或智能体,不换数据库,也可以复制后直接重启:
|
||||
|
||||
```bash
|
||||
docker restart deerflow-backend
|
||||
```
|
||||
|
||||
## 5. 修改或替换 SQLite 聊天/checkpointer 数据库
|
||||
|
||||
SQLite 只保存聊天运行时、LangGraph checkpointer、部分本地运行数据。业务表使用 MySQL,MySQL 地址见第 6 节。
|
||||
|
||||
最稳的方式是停容器后整体替换运行时目录:
|
||||
|
||||
```bash
|
||||
cd "$DEPLOY_DIR"
|
||||
docker rm -f deerflow-backend
|
||||
|
||||
mv docker-data/.deer-flow docker-data/.deer-flow.bak.$(date +%Y%m%d%H%M%S)
|
||||
cp -a /path/to/customer-dot-deer-flow "$DEPLOY_DIR/docker-data/.deer-flow"
|
||||
|
||||
./start-backend-docker.sh 8001
|
||||
```
|
||||
|
||||
如果只替换数据库文件,至少要处理这两个目录里的 `deerflow.db*`:
|
||||
|
||||
```text
|
||||
$DEPLOY_DIR/docker-data/.deer-flow/data/deerflow.db*
|
||||
$DEPLOY_DIR/docker-data/.deer-flow/.deer-flow/data/deerflow.db*
|
||||
```
|
||||
|
||||
操作示例:
|
||||
|
||||
```bash
|
||||
cd "$DEPLOY_DIR"
|
||||
docker rm -f deerflow-backend
|
||||
|
||||
mkdir -p docker-data/.deer-flow/data
|
||||
mkdir -p docker-data/.deer-flow/.deer-flow/data
|
||||
|
||||
cp -a /path/to/db-main/deerflow.db* docker-data/.deer-flow/data/
|
||||
cp -a /path/to/db-runtime/deerflow.db* docker-data/.deer-flow/.deer-flow/data/
|
||||
|
||||
./start-backend-docker.sh 8001
|
||||
```
|
||||
|
||||
不要在容器运行时直接覆盖 SQLite 文件,容易损坏 WAL 数据。
|
||||
|
||||
## 6. 修改配置和数据库配置
|
||||
|
||||
默认配置会在第一次启动时复制到:
|
||||
|
||||
```text
|
||||
$DEPLOY_DIR/docker-data/config/config.yaml
|
||||
```
|
||||
|
||||
要改配置,改这个文件,不要进容器改。
|
||||
|
||||
本项目现场部署按 **MySQL + SQLite** 使用:
|
||||
|
||||
- MySQL:业务表,例如用户、智能体、技能、任务、菜单、按钮、敏感词、轻应用等。
|
||||
- SQLite:聊天运行时和 LangGraph checkpointer,继续放在挂载出来的 `.deer-flow` 目录。
|
||||
- 不使用 PostgreSQL,不要配置 `database.backend: postgres`,也不要配置 `POSTGRES_URL`。
|
||||
|
||||
MySQL 地址主要改两个文件:
|
||||
|
||||
```text
|
||||
$DEPLOY_DIR/docker-data/config/config.yaml
|
||||
$DEPLOY_DIR/docker-data/config/.env
|
||||
```
|
||||
|
||||
`config.yaml` 里的数据库配置建议改成:
|
||||
|
||||
```yaml
|
||||
database:
|
||||
backend: mysql
|
||||
sqlite_dir: .deer-flow/data
|
||||
mysql_url: $MYSQL_DATABASE_URL
|
||||
pool_size: 20
|
||||
max_overflow: 20
|
||||
pool_timeout: 30
|
||||
echo_sql: false
|
||||
|
||||
checkpointer:
|
||||
type: sqlite
|
||||
connection_string: .deer-flow/data/deerflow.db
|
||||
```
|
||||
|
||||
然后在 `.env` 里写 MySQL 连接地址:
|
||||
|
||||
```bash
|
||||
MYSQL_DATABASE_URL=mysql+asyncmy://deerflow:密码@192.168.1.10:3306/deerflow?charset=utf8mb4
|
||||
```
|
||||
|
||||
把上面示例里的内容换成客户现场真实值:
|
||||
|
||||
```text
|
||||
deerflow # MySQL 用户名
|
||||
密码 # MySQL 密码
|
||||
192.168.1.10 # MySQL 服务器 IP
|
||||
3306 # MySQL 端口
|
||||
deerflow # MySQL 数据库名
|
||||
```
|
||||
|
||||
如果 MySQL 就装在 Docker 宿主机这台服务器上,容器里不要写 `127.0.0.1`,建议写:
|
||||
|
||||
```bash
|
||||
MYSQL_DATABASE_URL=mysql+asyncmy://deerflow:密码@host.docker.internal:3306/deerflow?charset=utf8mb4
|
||||
```
|
||||
|
||||
如果密码里有特殊字符,需要做 URL 编码,常见示例:
|
||||
|
||||
```text
|
||||
@ 写成 %40
|
||||
# 写成 %23
|
||||
% 写成 %25
|
||||
空格 写成 %20
|
||||
```
|
||||
|
||||
MySQL 数据库建议提前建好:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE deerflow CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
```
|
||||
|
||||
如果 MySQL 用户有建库权限,服务启动时也会尝试自动创建缺失的数据库。客户现场更稳的做法是先建库、导入 MySQL 备份,再启动后台。
|
||||
|
||||
如果客户现场已有 MySQL 备份,先在客户 MySQL 中导入:
|
||||
|
||||
```bash
|
||||
mysql -h 192.168.1.10 -P 3306 -u deerflow -p deerflow < deerflow_mysql.sql
|
||||
```
|
||||
|
||||
SQLite 聊天库仍按第 5 节复制到:
|
||||
|
||||
```text
|
||||
$DEPLOY_DIR/docker-data/.deer-flow/data/deerflow.db*
|
||||
$DEPLOY_DIR/docker-data/.deer-flow/.deer-flow/data/deerflow.db*
|
||||
```
|
||||
|
||||
如果需要把数据目录单独放到别的位置,不需要改 `config.yaml`,启动时指定 `DATA_DIR` 更稳:
|
||||
|
||||
```bash
|
||||
cd "$DEPLOY_DIR"
|
||||
DATA_DIR=/data/deerflow-backend-data ./start-backend-docker.sh 8001
|
||||
```
|
||||
|
||||
此时实际目录变成:
|
||||
|
||||
```text
|
||||
/data/deerflow-backend-data/config
|
||||
/data/deerflow-backend-data/.deer-flow
|
||||
/data/deerflow-backend-data/skills
|
||||
/data/deerflow-backend-data/knowledge
|
||||
/data/deerflow-backend-data/logs
|
||||
```
|
||||
|
||||
如果客户现场部署目录变化,只需要换 `DEPLOY_DIR` 或把整包放到新目录;MySQL 地址仍然只改 `$DEPLOY_DIR/docker-data/config/.env`,SQLite/智能体/技能仍然跟着 `DATA_DIR` 走。
|
||||
|
||||
如果要改 `.env`,位置是:
|
||||
|
||||
```text
|
||||
$DEPLOY_DIR/docker-data/config/.env
|
||||
```
|
||||
|
||||
修改配置后重启:
|
||||
|
||||
```bash
|
||||
cd "$DEPLOY_DIR"
|
||||
docker rm -f deerflow-backend
|
||||
./start-backend-docker.sh 8001
|
||||
```
|
||||
|
||||
## 7. 常用运维命令
|
||||
|
||||
查看容器:
|
||||
|
||||
```bash
|
||||
docker ps -a --filter name=deerflow-backend
|
||||
```
|
||||
|
||||
查看日志:
|
||||
|
||||
```bash
|
||||
docker logs -f --tail 200 deerflow-backend
|
||||
```
|
||||
|
||||
停止:
|
||||
|
||||
```bash
|
||||
docker rm -f deerflow-backend
|
||||
```
|
||||
|
||||
重启:
|
||||
|
||||
```bash
|
||||
docker restart deerflow-backend
|
||||
```
|
||||
|
||||
重新启动并换端口:
|
||||
|
||||
```bash
|
||||
cd "$DEPLOY_DIR"
|
||||
./start-backend-docker.sh 9001
|
||||
```
|
||||
|
||||
检查接口:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8001/health
|
||||
curl http://127.0.0.1:8001/api/health
|
||||
```
|
||||
|
||||
## 8. 交付清单
|
||||
|
||||
客户离线部署至少需要:
|
||||
|
||||
```text
|
||||
deerflow-backend/
|
||||
├── dist/deerflow-backend-offline.tar
|
||||
├── start-backend-docker.sh
|
||||
├── config.yaml
|
||||
├── extensions_config.json
|
||||
├── langgraph.json
|
||||
├── .env
|
||||
├── .deer-flow/agents/
|
||||
├── skills/
|
||||
└── 其他后台代码文件
|
||||
```
|
||||
|
||||
客户机器需要提前安装好 Docker。离线部署时不需要再下载 Python 依赖,依赖已经包含在 Docker 镜像里。
|
||||
Reference in new issue
Block a user