#!/usr/bin/env bash # filepath: deploy.sh # git clone https://code.deep-pilot.chat/AI_POC/TERES_web_frontend.git set -e if [ -n "${BASH_VERSION:-}" ]; then set -o pipefail fi # 固定镜像名(兼容你原 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 设置端口(映射和构建参数) --mode 设置构建模式,选择 .env.production 或 .env.flask --base 设置 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 "$@"