Dify + RAGFlow 一键部署脚本

#!/usr/bin/env bash
# ============================================================
# Dify + RAGFlow 一键部署脚本 for CentOS 7/8/9 / Stream / Alibaba Cloud Linux
#
# 默认版本:
#   Dify:    1.14.0
#   RAGFlow: v0.22.0
#
# 配置原则:
#   1. Dify 不改配置,只复制 .env.example 为 .env,然后按官方默认配置启动。
#   2. RAGFlow 只改两个位置:
#      - docker/.env
#      - docker/docker-compose-base.yml 中 Redis 服务名
#   3. 不对其他 compose 文件做额外修改。
#
# 最低建议配置:
#   CPU >= 8 核
#   内存 >= 12 GB
#   可用磁盘 >= 40 GB
#
# 使用方式:
#   chmod +x install_dify_ragflow_centos_menu.sh
#   ./install_dify_ragflow_centos_menu.sh
#
# 非交互参数:
#   ./install_dify_ragflow_centos_menu.sh --all
#   ./install_dify_ragflow_centos_menu.sh --dify
#   ./install_dify_ragflow_centos_menu.sh --ragflow
#   ./install_dify_ragflow_centos_menu.sh --install-docker
#   ./install_dify_ragflow_centos_menu.sh --status
#   ./install_dify_ragflow_centos_menu.sh --stop
#   ./install_dify_ragflow_centos_menu.sh --restart
#   ./install_dify_ragflow_centos_menu.sh --uninstall
#   ./install_dify_ragflow_centos_menu.sh --uninstall --remove-files
# ============================================================

set -Eeuo pipefail

# -----------------------------
# 默认配置
# -----------------------------
BASE_DIR="/opt/ai-platform"

DIFY_VERSION="1.14.0"
RAGFLOW_VERSION="v0.22.0"

# Dify 不修改端口,使用官方默认配置。
# Dify 默认 Web 访问端口通常为 80。
DIFY_PORT="80"

# RAGFlow 按手工部署配置修改。
RAGFLOW_WEB_HTTP_PORT="8880"
RAGFLOW_WEB_HTTPS_PORT="8443"
RAGFLOW_REDIS_HOST="ragflow_redis"
RAGFLOW_REDIS_PORT="7379"

INSTALL_DOCKER="true"
DEPLOY_DIFY="false"
DEPLOY_RAGFLOW="false"
ACTION="menu"

GITHUB_MIRROR=""
DOCKER_REGISTRY_MIRROR=""
REMOVE_FILES="false"

LOG_FILE="/tmp/install_dify_ragflow_$(date +%Y%m%d_%H%M%S).log"

# -----------------------------
# 输出函数
# -----------------------------
info() {
  echo -e "\033[1;32m[INFO]\033[0m $*" | tee -a "$LOG_FILE"
}

warn() {
  echo -e "\033[1;33m[WARN]\033[0m $*" | tee -a "$LOG_FILE"
}

err() {
  echo -e "\033[1;31m[ERROR]\033[0m $*" | tee -a "$LOG_FILE"
}

die() {
  err "$*"
  exit 1
}

run() {
  info "执行:$*"
  "$@" 2>&1 | tee -a "$LOG_FILE"
}

pause_enter() {
  echo
  read -r -p "按 Enter 返回菜单..."
}

# -----------------------------
# 帮助信息
# -----------------------------
usage() {
  cat <<EOF
Dify + RAGFlow 一键部署脚本 for CentOS

用法:
  $0                 进入交互式菜单
  $0 [选项]          非交互执行

部署选项:
  --all                     部署 Dify + RAGFlow
  --dify                    只部署 Dify
  --ragflow                 只部署 RAGFlow
  --install-docker          仅安装 Docker 和 Docker Compose 插件

管理选项:
  --status                  查看 Dify 和 RAGFlow 容器状态
  --stop                    停止 Dify 和 RAGFlow
  --restart                 重启 Dify 和 RAGFlow
  --uninstall               卸载 Dify 和 RAGFlow,删除容器、网络和数据卷
  --remove-files            配合 --uninstall 使用,同时删除源码目录

版本参数:
  --dify-version VERSION    指定 Dify 版本,默认:${DIFY_VERSION}
  --ragflow-version VERSION 指定 RAGFlow 版本,默认:${RAGFLOW_VERSION}

路径参数:
  --base-dir DIR            安装目录,默认:${BASE_DIR}

RAGFlow 参数:
  --ragflow-http-port PORT  RAGFlow Web HTTP 端口,默认:${RAGFLOW_WEB_HTTP_PORT}
  --ragflow-https-port PORT RAGFlow Web HTTPS 端口,默认:${RAGFLOW_WEB_HTTPS_PORT}
  --ragflow-redis-port PORT RAGFlow Redis 映射端口,默认:${RAGFLOW_REDIS_PORT}
  --ragflow-redis-host HOST RAGFlow Redis 服务名,默认:${RAGFLOW_REDIS_HOST}

下载优化:
  --github-mirror URL       GitHub 下载代理前缀,例如:https://gh-proxy.com/
  --docker-mirror URL       Docker 镜像加速地址,例如:https://xxxx.mirror.aliyuncs.com

示例:
  $0
  $0 --all
  $0 --dify
  $0 --ragflow
  $0 --uninstall
  $0 --uninstall --remove-files
EOF
}

# -----------------------------
# 参数解析
# -----------------------------
parse_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --all)
        ACTION="deploy"
        DEPLOY_DIFY="true"
        DEPLOY_RAGFLOW="true"
        shift
        ;;
      --dify)
        ACTION="deploy"
        DEPLOY_DIFY="true"
        shift
        ;;
      --ragflow)
        ACTION="deploy"
        DEPLOY_RAGFLOW="true"
        shift
        ;;
      --install-docker)
        ACTION="install-docker"
        shift
        ;;
      --status)
        ACTION="status"
        shift
        ;;
      --stop)
        ACTION="stop"
        shift
        ;;
      --restart)
        ACTION="restart"
        shift
        ;;
      --uninstall)
        ACTION="uninstall"
        shift
        ;;
      --remove-files)
        REMOVE_FILES="true"
        shift
        ;;
      --base-dir)
        BASE_DIR="$2"
        shift 2
        ;;
      --dify-version)
        DIFY_VERSION="$2"
        shift 2
        ;;
      --ragflow-version)
        RAGFLOW_VERSION="$2"
        shift 2
        ;;
      --ragflow-http-port|--ragflow-port)
        RAGFLOW_WEB_HTTP_PORT="$2"
        shift 2
        ;;
      --ragflow-https-port)
        RAGFLOW_WEB_HTTPS_PORT="$2"
        shift 2
        ;;
      --ragflow-redis-port)
        RAGFLOW_REDIS_PORT="$2"
        shift 2
        ;;
      --ragflow-redis-host)
        RAGFLOW_REDIS_HOST="$2"
        shift 2
        ;;
      --github-mirror)
        GITHUB_MIRROR="$2"
        shift 2
        ;;
      --docker-mirror)
        DOCKER_REGISTRY_MIRROR="$2"
        shift 2
        ;;
      -h|--help)
        usage
        exit 0
        ;;
      *)
        die "未知参数:$1。使用 --help 查看帮助。"
        ;;
    esac
  done
}

# -----------------------------
# 系统检测
# -----------------------------
need_root() {
  if [[ "$(id -u)" -ne 0 ]]; then
    die "请使用 root 用户执行,或使用 sudo 执行。"
  fi
}

detect_os() {
  if [[ -f /etc/os-release ]]; then
    . /etc/os-release
    OS_ID="${ID:-unknown}"
    OS_VERSION_ID="${VERSION_ID:-unknown}"
  else
    die "无法识别系统,缺少 /etc/os-release"
  fi

  info "当前系统:${OS_ID} ${OS_VERSION_ID}"

  case "$OS_ID" in
    centos|rhel|rocky|almalinux|ol|anolis|alinux)
      ;;
    *)
      warn "当前系统不是典型 CentOS/RHEL 系,脚本会继续执行,但不保证完全兼容。"
      ;;
  esac
}

check_resources() {
  local cpu_count mem_gb disk_gb
  cpu_count="$(nproc || echo 0)"
  mem_gb="$(free -g | awk '/Mem:/ {print $2}')"
  disk_gb="$(df -BG "$BASE_DIR" 2>/dev/null | awk 'NR==2 {gsub("G","",$4); print $4}')"

  if [[ -z "${disk_gb:-}" ]]; then
    disk_gb="$(df -BG / | awk 'NR==2 {gsub("G","",$4); print $4}')"
  fi

  info "安装目录:${BASE_DIR}"
  info "CPU 核心数:${cpu_count}"
  info "内存大小:${mem_gb} GB"
  info "可用磁盘:${disk_gb} GB"

  if [[ "$DEPLOY_RAGFLOW" == "true" ]]; then
    if [[ "$cpu_count" -lt 8 ]]; then
      warn "RAGFlow 最低建议 CPU >= 8 核,当前 ${cpu_count} 核。"
    fi

    if [[ "$mem_gb" -lt 12 ]]; then
      warn "RAGFlow 最低建议内存 >= 12GB,当前 ${mem_gb}GB。"
    fi

    if [[ "$disk_gb" -lt 40 ]]; then
      warn "RAGFlow 最低建议磁盘可用空间 >= 40GB,当前 ${disk_gb}GB。"
    fi
  fi
}

prepare_dirs() {
  mkdir -p "$BASE_DIR"
}

github_url() {
  local raw="$1"
  if [[ -n "$GITHUB_MIRROR" ]]; then
    echo "${GITHUB_MIRROR}${raw}"
  else
    echo "$raw"
  fi
}

replace_env_value() {
  local file="$1"
  local key="$2"
  local value="$3"

  if grep -qE "^${key}=" "$file"; then
    sed -i "s#^${key}=.*#${key}=${value}#g" "$file"
  else
    echo "${key}=${value}" >> "$file"
  fi
}

port_in_use() {
  local port="$1"
  if ss -lnt 2>/dev/null | awk '{print $4}' | grep -Eq "[:.]${port}$"; then
    return 0
  fi
  return 1
}

check_ports() {
  if [[ "$DEPLOY_DIFY" == "true" ]] && port_in_use "$DIFY_PORT"; then
    warn "端口 ${DIFY_PORT} 已被占用。若 Dify 已经运行可忽略。"
  fi

  if [[ "$DEPLOY_RAGFLOW" == "true" ]] && port_in_use "$RAGFLOW_WEB_HTTP_PORT"; then
    warn "端口 ${RAGFLOW_WEB_HTTP_PORT} 已被占用。RAGFlow HTTP 访问端口可能冲突。"
  fi

  if [[ "$DEPLOY_RAGFLOW" == "true" ]] && port_in_use "$RAGFLOW_WEB_HTTPS_PORT"; then
    warn "端口 ${RAGFLOW_WEB_HTTPS_PORT} 已被占用。RAGFlow HTTPS 访问端口可能冲突。"
  fi

  if [[ "$DEPLOY_RAGFLOW" == "true" ]] && port_in_use "$RAGFLOW_REDIS_PORT"; then
    warn "端口 ${RAGFLOW_REDIS_PORT} 已被占用。RAGFlow Redis 映射端口可能冲突。"
  fi
}

# -----------------------------
# Docker 安装
# -----------------------------
install_base_tools() {
  info "安装基础工具..."
  if command -v dnf >/dev/null 2>&1; then
    run dnf install -y yum-utils device-mapper-persistent-data lvm2 git wget curl tar sed grep gawk ca-certificates
  else
    run yum install -y yum-utils device-mapper-persistent-data lvm2 git wget curl tar sed grep gawk ca-certificates
  fi
}

install_docker() {
  if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then
    info "Docker 与 Docker Compose 插件已安装。"
    docker --version | tee -a "$LOG_FILE"
    docker compose version | tee -a "$LOG_FILE"
    return
  fi

  install_base_tools

  info "安装 Docker CE..."
  if command -v dnf >/dev/null 2>&1; then
    run dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    run dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  else
    run yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    run yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  fi

  mkdir -p /etc/docker

  if [[ -n "$DOCKER_REGISTRY_MIRROR" ]]; then
    info "配置 Docker 镜像加速。"
    cat >/etc/docker/daemon.json <<EOF
{
  "registry-mirrors": ["${DOCKER_REGISTRY_MIRROR}"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}
EOF
  else
    if [[ ! -f /etc/docker/daemon.json ]]; then
      cat >/etc/docker/daemon.json <<EOF
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
  }
}
EOF
    fi
  fi

  run systemctl enable docker
  run systemctl restart docker

  docker --version | tee -a "$LOG_FILE"
  docker compose version | tee -a "$LOG_FILE"
}

check_docker_version() {
  command -v docker >/dev/null 2>&1 || die "Docker 未安装。"
  docker compose version >/dev/null 2>&1 || die "Docker Compose 插件未安装。"

  local docker_ver compose_ver
  docker_ver="$(docker version --format '{{.Server.Version}}' 2>/dev/null || echo unknown)"
  compose_ver="$(docker compose version --short 2>/dev/null || echo unknown)"
  info "Docker Server 版本:${docker_ver}"
  info "Docker Compose 版本:${compose_ver}"
}

# -----------------------------
# Dify 部署
# -----------------------------
deploy_dify() {
  info "开始部署 Dify ${DIFY_VERSION}..."

  local dify_tar dify_url dify_dir
  dify_tar="${BASE_DIR}/dify-${DIFY_VERSION}.tar.gz"
  dify_dir="${BASE_DIR}/dify-${DIFY_VERSION}"
  dify_url="$(github_url "https://github.com/langgenius/dify/archive/refs/tags/${DIFY_VERSION}.tar.gz")"

  if [[ ! -d "$dify_dir" ]]; then
    info "下载 Dify 源码包。"
    run wget -O "$dify_tar" "$dify_url"
    run tar -xf "$dify_tar" -C "$BASE_DIR"
  else
    info "Dify 目录已存在:${dify_dir}"
  fi

  [[ -d "${dify_dir}/docker" ]] || die "Dify docker 目录不存在:${dify_dir}/docker"

  cd "${dify_dir}/docker"

  if [[ ! -f .env ]]; then
    [[ -f .env.example ]] || die "Dify 缺少 .env.example 文件"
    run cp .env.example .env
  else
    info "Dify .env 已存在,保持原配置。"
  fi

  info "启动 Dify..."
  run docker compose -p dify up -d

  info "Dify 部署完成。"
}

# -----------------------------
# RAGFlow 部署
# -----------------------------
patch_ragflow_env() {
  local env_file="$1"

  [[ -f "$env_file" ]] || die "RAGFlow .env 文件不存在:$env_file"

  replace_env_value "$env_file" "SVR_WEB_HTTP_PORT" "$RAGFLOW_WEB_HTTP_PORT"
  replace_env_value "$env_file" "SVR_WEB_HTTPS_PORT" "$RAGFLOW_WEB_HTTPS_PORT"
  replace_env_value "$env_file" "REDIS_HOST" "$RAGFLOW_REDIS_HOST"
  replace_env_value "$env_file" "REDIS_PORT" "$RAGFLOW_REDIS_PORT"

  info "RAGFlow .env 配置完成。"
}

patch_ragflow_compose_base() {
  local compose_base="$1"

  [[ -f "$compose_base" ]] || die "RAGFlow docker-compose-base.yml 文件不存在:$compose_base"

  python3 - "$compose_base" "$RAGFLOW_REDIS_HOST" <<'PY'
import sys
from pathlib import Path

path = Path(sys.argv[1])
new_name = sys.argv[2]

text = path.read_text(encoding="utf-8")

# 只修改 services 下的 redis 服务名:
#   redis:
# 修改为:
#   ragflow_redis:
text = text.replace("\n  redis:\n", f"\n  {new_name}:\n")

path.write_text(text, encoding="utf-8")
PY

  info "RAGFlow docker-compose-base.yml 配置完成。"
}

deploy_ragflow() {
  info "开始部署 RAGFlow ${RAGFLOW_VERSION}..."

  local ragflow_dir ragflow_url
  ragflow_dir="${BASE_DIR}/RAGFlow"
  ragflow_url="$(github_url "https://github.com/infiniflow/RAGFlow.git")"

  if [[ ! -d "$ragflow_dir/.git" ]]; then
    info "克隆 RAGFlow 源码。"
    run git clone "$ragflow_url" "$ragflow_dir"
  else
    info "RAGFlow 目录已存在:${ragflow_dir}"
  fi

  cd "$ragflow_dir"
  run git fetch --tags --all
  run git checkout -f "$RAGFLOW_VERSION"

  [[ -d "${ragflow_dir}/docker" ]] || die "RAGFlow docker 目录不存在:${ragflow_dir}/docker"
  cd "${ragflow_dir}/docker"

  if [[ ! -f .env ]]; then
    if [[ -f .env.example ]]; then
      run cp .env.example .env
    else
      die "RAGFlow 缺少 .env 文件,请检查源码版本。"
    fi
  fi

  patch_ragflow_env ".env"
  patch_ragflow_compose_base "docker-compose-base.yml"

  info "启动 RAGFlow..."
  run docker compose -p ragflow up -d

  info "RAGFlow 部署完成。"
}

# -----------------------------
# 管理命令
# -----------------------------
show_status() {
  info "查看 Dify 状态..."
  local dify_dir="${BASE_DIR}/dify-${DIFY_VERSION}/docker"
  if [[ -d "$dify_dir" ]]; then
    (cd "$dify_dir" && docker compose -p dify ps) || true
  else
    warn "未找到 Dify 目录:$dify_dir"
  fi

  info "查看 RAGFlow 状态..."
  local ragflow_dir="${BASE_DIR}/RAGFlow/docker"
  if [[ -d "$ragflow_dir" ]]; then
    (cd "$ragflow_dir" && docker compose -p ragflow ps) || true
  else
    warn "未找到 RAGFlow 目录:$ragflow_dir"
  fi
}

stop_services() {
  local dify_dir="${BASE_DIR}/dify-${DIFY_VERSION}/docker"
  local ragflow_dir="${BASE_DIR}/RAGFlow/docker"

  if [[ -d "$dify_dir" ]]; then
    info "停止 Dify..."
    (cd "$dify_dir" && docker compose -p dify stop) || true
  fi

  if [[ -d "$ragflow_dir" ]]; then
    info "停止 RAGFlow..."
    (cd "$ragflow_dir" && docker compose -p ragflow stop) || true
  fi
}

restart_services() {
  local dify_dir="${BASE_DIR}/dify-${DIFY_VERSION}/docker"
  local ragflow_dir="${BASE_DIR}/RAGFlow/docker"

  if [[ -d "$dify_dir" ]]; then
    info "重启 Dify..."
    (cd "$dify_dir" && docker compose -p dify restart) || true
  fi

  if [[ -d "$ragflow_dir" ]]; then
    info "重启 RAGFlow..."
    (cd "$ragflow_dir" && docker compose -p ragflow restart) || true
  fi
}

uninstall_services() {
  local dify_dir="${BASE_DIR}/dify-${DIFY_VERSION}/docker"
  local ragflow_dir="${BASE_DIR}/RAGFlow/docker"

  warn "即将卸载 Dify 和 RAGFlow。"
  warn "卸载会删除容器、网络和 Compose 数据卷,业务数据将被删除。"

  if [[ -d "$dify_dir" ]]; then
    info "卸载 Dify..."
    (cd "$dify_dir" && docker compose -p dify down -v --remove-orphans) || true
  else
    warn "未找到 Dify docker 目录:$dify_dir"
  fi

  if [[ -d "$ragflow_dir" ]]; then
    info "卸载 RAGFlow..."
    (cd "$ragflow_dir" && docker compose -p ragflow down -v --remove-orphans) || true
  else
    warn "未找到 RAGFlow docker 目录:$ragflow_dir"
  fi

  # 兼容历史上未指定 -p 时产生的默认项目名 docker。
  if [[ -d "$dify_dir" ]]; then
    (cd "$dify_dir" && docker compose -p docker down -v --remove-orphans) >/dev/null 2>&1 || true
  fi

  if [[ -d "$ragflow_dir" ]]; then
    (cd "$ragflow_dir" && docker compose -p docker down -v --remove-orphans) >/dev/null 2>&1 || true
  fi

  if [[ "$REMOVE_FILES" == "true" ]]; then
    info "删除源码目录..."
    rm -rf "${BASE_DIR}/dify-${DIFY_VERSION}" \
           "${BASE_DIR}/dify-${DIFY_VERSION}.tar.gz" \
           "${BASE_DIR}/RAGFlow"
  else
    warn "源码目录已保留。如需删除源码目录,请使用:--uninstall --remove-files"
  fi

  info "卸载完成。"
}

print_summary() {
  local ip
  ip="$(hostname -I 2>/dev/null | awk '{print $1}')"
  [[ -z "$ip" ]] && ip="服务器IP"

  echo
  echo "============================================================"
  echo "部署信息"
  echo "============================================================"
  if [[ "$DEPLOY_DIFY" == "true" ]]; then
    echo "Dify 访问地址:       http://${ip}:${DIFY_PORT}"
    echo "Dify 安装目录:       ${BASE_DIR}/dify-${DIFY_VERSION}/docker"
  fi

  if [[ "$DEPLOY_RAGFLOW" == "true" ]]; then
    echo "RAGFlow HTTP地址:    http://${ip}:${RAGFLOW_WEB_HTTP_PORT}"
    echo "RAGFlow HTTPS地址:   https://${ip}:${RAGFLOW_WEB_HTTPS_PORT}"
    echo "RAGFlow Redis配置:   ${RAGFLOW_REDIS_HOST}:${RAGFLOW_REDIS_PORT}"
    echo "RAGFlow 安装目录:    ${BASE_DIR}/RAGFlow/docker"
  fi

  echo "日志文件:            ${LOG_FILE}"
  echo
  echo "常用命令:"
  echo "  查看容器:docker ps"
  echo "  查看 Dify:cd ${BASE_DIR}/dify-${DIFY_VERSION}/docker && docker compose -p dify ps"
  echo "  查看 RAGFlow:cd ${BASE_DIR}/RAGFlow/docker && docker compose -p ragflow ps"
  echo "  查看日志:docker compose logs -f"
  echo "============================================================"
}

deploy_selected() {
  prepare_dirs
  check_resources

  if [[ "$INSTALL_DOCKER" == "true" ]]; then
    install_docker
  fi

  check_docker_version
  check_ports

  if [[ "$DEPLOY_DIFY" == "true" ]]; then
    deploy_dify
  fi

  if [[ "$DEPLOY_RAGFLOW" == "true" ]]; then
    deploy_ragflow
  fi

  show_status
  print_summary
}

# -----------------------------
# 菜单功能
# -----------------------------
show_menu() {
  clear
  echo "============================================================"
  echo " Dify + RAGFlow 一键部署管理菜单"
  echo "============================================================"
  echo " 安装目录:${BASE_DIR}"
  echo " Dify版本:${DIFY_VERSION}"
  echo " RAGFlow版本:${RAGFLOW_VERSION}"
  echo "------------------------------------------------------------"
  echo " 1. 安装 Docker 和 Docker Compose"
  echo " 2. 部署 Dify"
  echo " 3. 部署 RAGFlow"
  echo " 4. 部署 Dify + RAGFlow"
  echo " 5. 查看服务状态"
  echo " 6. 停止服务"
  echo " 7. 重启服务"
  echo " 8. 卸载服务(保留源码目录)"
  echo " 9. 卸载服务(删除源码目录)"
  echo " 0. 退出"
  echo "============================================================"
}

menu_loop() {
  while true; do
    show_menu
    read -r -p "请输入选项 [0-9]:" choice

    case "$choice" in
      1)
        install_docker
        pause_enter
        ;;
      2)
        DEPLOY_DIFY="true"
        DEPLOY_RAGFLOW="false"
        deploy_selected
        pause_enter
        ;;
      3)
        DEPLOY_DIFY="false"
        DEPLOY_RAGFLOW="true"
        deploy_selected
        pause_enter
        ;;
      4)
        DEPLOY_DIFY="true"
        DEPLOY_RAGFLOW="true"
        deploy_selected
        pause_enter
        ;;
      5)
        show_status
        pause_enter
        ;;
      6)
        stop_services
        pause_enter
        ;;
      7)
        restart_services
        pause_enter
        ;;
      8)
        REMOVE_FILES="false"
        uninstall_services
        pause_enter
        ;;
      9)
        REMOVE_FILES="true"
        uninstall_services
        pause_enter
        ;;
      0)
        echo "已退出。"
        exit 0
        ;;
      *)
        echo "无效选项,请重新输入。"
        sleep 1
        ;;
    esac
  done
}

main() {
  parse_args "$@"
  need_root
  detect_os

  case "$ACTION" in
    menu)
      menu_loop
      ;;
    install-docker)
      install_docker
      ;;
    status)
      show_status
      ;;
    stop)
      stop_services
      ;;
    restart)
      restart_services
      ;;
    uninstall)
      uninstall_services
      ;;
    deploy)
      deploy_selected
      ;;
    *)
      die "未知动作:$ACTION"
      ;;
  esac
}

main "$@"
posted @ 2026-06-09 07:57  静心笃行。  阅读(32)  评论(0)    收藏  举报