build: add docker-compose and deploy script for frontend service

This commit is contained in:
2025-11-14 13:38:37 +08:00
parent a606b5766a
commit 9ff85984e4
2 changed files with 231 additions and 0 deletions

209
deploy.sh Normal file
View File

@@ -0,0 +1,209 @@
#!/usr/bin/env bash
# filepath: deploy.sh
set -euo pipefail
# 固定镜像名(兼容你原 stop.sh 的做法)
IMAGE_NAME="teres_web_frontend:latest"
FLASK_IMAGE_NAME="teres_web_frontend_flask:latest"
SERVICE_NAME="teres_web_frontend"
NETWORK_NAME="proxy-net"
usage() {
cat <<'EOF'
用法: ./deploy.sh <命令> [选项]
常用命令:
start 拉最新代码并构建启动docker compose up -d --build
stop 按固定镜像名停止并删除容器,同时删除镜像
restart 先 stop 再 start
clean 同 stop停止容器并删除镜像
增强命令:
status 查看服务状态compose ps + 过滤容器)
logs [--follow] 查看日志(加 --follow 跟随)
health 健康检查HTTP 200
set [opts] 更新 .env 中 PORT/BUILD_MODE/RAGFLOW_BASE
pull 仅拉取最新代码
prune 清理悬空镜像与缓存
set 支持的选项:
--port <N> 设置端口(映射和构建参数)
--mode <production|flask> 设置构建模式,选择 .env.production 或 .env.flask
--base <path> 设置 ragflow 子路径(默认 /ragflow/
示例:
./deploy.sh start
./deploy.sh set --port 5173 --mode production --base /ragflow/
./deploy.sh logs --follow
./deploy.sh health
EOF
}
# 检查命令存在
require_cmd() {
local cmd="$1"; command -v "$cmd" >/dev/null 2>&1 || {
echo "错误: 未找到命令 '$cmd'"; exit 1; }
}
# 选择 compose 命令
compose_cmd() {
if command -v docker-compose >/dev/null 2>&1; then
echo docker-compose
else
echo docker compose
fi
}
ensure_network() {
if ! docker network inspect "$NETWORK_NAME" >/dev/null 2>&1; then
echo "--- 创建网络: $NETWORK_NAME ---"
docker network create "$NETWORK_NAME"
fi
}
git_pull() {
echo "--- 拉取最新的代码 ---"
git fetch --all --prune || true
git pull
}
compose_up() {
local cmd; cmd=$(compose_cmd)
ensure_network
echo "--- docker compose 构建并启动 ---"
$cmd up -d --build
}
compose_down() {
local cmd; cmd=$(compose_cmd)
echo "--- docker compose down ---"
$cmd down || true
}
stop_by_image() {
local image="$1"
echo "--- 停止并删除镜像对应的容器: $image ---"
local ids
ids=$(docker ps -a --filter "ancestor=$image" --format "{{.ID}}" || true)
if [[ -n "$ids" ]]; then
for id in $ids; do
docker stop "$id" || true
docker rm "$id" || true
done
fi
echo "--- 删除镜像: $image ---"
docker rmi "$image" || true
}
status() {
local cmd; cmd=$(compose_cmd)
echo "--- compose ps ---"
$cmd ps || true
echo "--- docker ps (过滤 $SERVICE_NAME) ---"
docker ps --format '{{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Status}}' | grep -E "$SERVICE_NAME|$IMAGE_NAME" || true
}
logs() {
local follow="false"
if [[ "${1:-}" == "--follow" ]]; then follow="true"; fi
local cmd; cmd=$(compose_cmd)
if [[ "$follow" == "true" ]]; then
$cmd logs -f "$SERVICE_NAME"
else
$cmd logs --tail=300 "$SERVICE_NAME"
fi
}
# 更新 .env 中某个键值(若不存在则追加)
update_env_var() {
local key="$1"; shift
local val="$1"; shift
touch .env
if grep -qE "^\s*${key}\s*=\s*" .env; then
# 使用正则替换整行,保留键名
sed -i.bak -E "s|^\s*(${key})\s*=\s*.*|\1=${val}|" .env
else
echo "${key}=${val}" >> .env
fi
}
health() {
# 从 .env 读取,带默认值
local PORT=${PORT:-$(grep -E '^\s*PORT\s*=' .env | sed -E 's/.*=\s*//g' || echo 5173)}
local BASE=${RAGFLOW_BASE:-$(grep -E '^\s*RAGFLOW_BASE\s*=' .env | sed -E 's/.*=\s*//g' || echo /ragflow/)}
local host="http://127.0.0.1:${PORT}"
echo "--- 健康检查: ${host}${host}${BASE} ---"
if command -v curl >/dev/null 2>&1; then
curl -fsS -o /dev/null "${host}" && echo "根应用 OK" || echo "根应用失败"
curl -fsS -o /dev/null "${host}${BASE}" && echo "ragflow 子路径 OK" || echo "ragflow 子路径失败"
else
wget -q --spider "${host}" && echo "根应用 OK" || echo "根应用失败"
wget -q --spider "${host}${BASE}" && echo "ragflow 子路径 OK" || echo "ragflow 子路径失败"
fi
}
prune() {
echo "--- 清理悬空镜像与构建缓存 ---"
docker image prune -f || true
docker builder prune -f || true
}
cmd_start() {
git_pull
compose_up
}
cmd_stop() {
compose_down
stop_by_image "$IMAGE_NAME"
stop_by_image "$FLASK_IMAGE_NAME"
}
cmd_restart() {
cmd_stop
cmd_start
}
cmd_clean() { cmd_stop; }
cmd_pull() { git_pull; }
cmd_set() {
# 解析选项
local port="" mode="" base=""
while [[ $# -gt 0 ]]; do
case "$1" in
--port) port="$2"; shift 2;;
--mode) mode="$2"; shift 2;;
--base) base="$2"; shift 2;;
*) echo "未知选项: $1"; usage; exit 1;;
esac
done
[[ -n "$port" ]] && update_env_var PORT "$port"
[[ -n "$mode" ]] && update_env_var BUILD_MODE "$mode"
[[ -n "$base" ]] && update_env_var RAGFLOW_BASE "$base"
echo "--- .env 已更新 ---"
}
main() {
require_cmd docker
local subcmd="${1:-}"
case "$subcmd" in
start) shift; cmd_start "$@" ;;
stop) shift; cmd_stop "$@" ;;
restart) shift; cmd_restart "$@" ;;
clean) shift; cmd_clean "$@" ;;
status) shift; status "$@" ;;
logs) shift; logs "${1:-}" ;;
health) shift; health "$@" ;;
set) shift; cmd_set "$@" ;;
pull) shift; cmd_pull "$@" ;;
prune) shift; prune "$@" ;;
""|help|-h|--help) usage ;;
*) echo "未知命令: $subcmd"; usage; exit 1 ;;
esac
echo "--- 完成 ---"
}
main "$@"