From 85bed1f480c10424db23f8b14822d5b700c93c28 Mon Sep 17 00:00:00 2001 From: ethanqzheng Date: Wed, 10 Sep 2025 14:58:59 +0800 Subject: [PATCH 1/3] feat: update installer files --- installer.sh | 878 ----------------------------------- installer/.env | 37 ++ installer/docker-compose.yml | 117 +++++ start.sh | 98 ---- status.sh | 71 --- 5 files changed, 154 insertions(+), 1047 deletions(-) delete mode 100755 installer.sh create mode 100644 installer/.env create mode 100644 installer/docker-compose.yml delete mode 100755 start.sh delete mode 100755 status.sh diff --git a/installer.sh b/installer.sh deleted file mode 100755 index 3a4387d..0000000 --- a/installer.sh +++ /dev/null @@ -1,878 +0,0 @@ -#!/bin/bash - -# SeaChartCode 一键安装器 -# 支持指定版本和默认latest版本,一键安装启动和一键卸载 - -set -e - -# 信号处理 - 优雅退出 -cleanup_on_exit() { - local exit_code=$? - if [ $exit_code -ne 0 ]; then - log_error "脚本异常退出 (退出码: $exit_code)" - if [ -n "${INSTALL_DIR:-}" ] && [ -f "${INSTALL_DIR}/docker-compose.yml" ]; then - log_info "尝试清理可能的残留进程..." - cd "$INSTALL_DIR" 2>/dev/null || true - if command -v docker-compose &> /dev/null; then - docker-compose kill 2>/dev/null || true - else - docker compose kill 2>/dev/null || true - fi - fi - fi -} - -trap cleanup_on_exit EXIT -trap 'log_warn "收到中断信号,正在清理..."; exit 130' INT TERM - -# 颜色定义 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -PURPLE='\033[0;35m' -CYAN='\033[0;36m' -NC='\033[0m' # No Color - -# 配置变量 -SCRIPT_VERSION="1.0.0" -DEFAULT_VERSION="latest" -DOCKER_REGISTRY="swr.cn-east-3.myhuaweicloud.com/cloud-mdgx" # 华为云容器镜像服务 -PROJECT_NAME="seachartcode" -INSTALL_DIR="${HOME}/.seachartcode" -COMPOSE_FILE="$INSTALL_DIR/docker-compose.yml" -ENV_FILE="$INSTALL_DIR/.env" - -# 显示横幅 -show_banner() { - echo -e "${CYAN}" - echo "==================================================" - echo " SeaChartCode 一键安装器 v${SCRIPT_VERSION}" - echo "==================================================" - echo -e "${NC}" -} - -# 显示使用说明 -show_usage() { - echo -e "${YELLOW}使用方法:${NC}" - echo " $0 install [版本号] # 安装指定版本 (默认: latest)" - echo " $0 start # 启动服务" - echo " $0 stop # 停止服务" - echo " $0 restart # 重启服务" - echo " $0 reset # 重置服务(保留数据)" - echo " $0 status # 查看服务状态" - echo " $0 logs [服务名] # 查看日志" - echo " $0 diagnose # 诊断服务状态" - echo " $0 update [版本号] # 更新到指定版本" - echo " $0 uninstall # 卸载服务" - echo " $0 --help # 显示此帮助信息" - echo "" - echo -e "${YELLOW}示例:${NC}" - echo " $0 install # 安装最新版本" - echo " $0 install v1.0.0 # 安装v1.0.0版本" - echo " $0 logs server # 查看后端服务日志" - echo " $0 diagnose # 全面诊断系统状态" - echo " $0 reset # 重置服务解决问题" - echo "" -} - -# 日志函数 -log_info() { - echo -e "${GREEN}[INFO]${NC} $1" -} - -log_warn() { - echo -e "${YELLOW}[WARN]${NC} $1" -} - -log_error() { - echo -e "${RED}[ERROR]${NC} $1" -} - -log_debug() { - echo -e "${BLUE}[DEBUG]${NC} $1" -} - -# 检查依赖 -check_dependencies() { - log_info "检查系统依赖..." - - # 检查Docker - if ! command -v docker &> /dev/null; then - log_error "Docker 未安装,请先安装 Docker" - echo "安装指南: https://docs.docker.com/get-docker/" - exit 1 - fi - - # 检查Docker Compose - if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then - log_error "Docker Compose 未安装,请先安装 Docker Compose" - echo "安装指南: https://docs.docker.com/compose/install/" - exit 1 - fi - - # 检查Docker服务状态 - if ! docker info &> /dev/null; then - log_error "Docker 服务未运行,请启动 Docker 服务" - exit 1 - fi - - log_info "✅ 所有依赖检查完成" -} - -# 创建安装目录 -create_install_dir() { - log_info "创建安装目录: $INSTALL_DIR" - mkdir -p "$INSTALL_DIR" - mkdir -p "$INSTALL_DIR/logs" -} - -# 生成环境变量文件 -generate_env_file() { - log_info "生成环境变量文件..." - - if [ -f "$ENV_FILE" ]; then - log_warn "环境变量文件已存在,跳过生成" - return - fi - - # 生成随机密码 - POSTGRES_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-16) - REDIS_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-16) - ADMIN_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-12) - - cat > "$ENV_FILE" << EOF -# SeaChartCode 环境配置文件 -# 此文件由 installer.sh 自动生成 - -# 基础配置 -SEACHARTCODE_VERSION=${VERSION} -ENABLE_PUBLIC_ACCESS=true -LOCAL_IP=localhost -REMOTE_IP=localhost - -# 端口配置 -NGINX_PORT=8080 -SERVER_PORT=8888 -POSTGRES_PORT=5432 -REDIS_PORT=6379 - -# 管理员配置 -ADMIN_USER=admin -ADMIN_PASSWORD=${ADMIN_PASSWORD} - -# 数据库配置 -POSTGRES_DB=seachartcode -POSTGRES_USER=seachartcode -POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - -# Redis配置 -REDIS_PASSWORD=${REDIS_PASSWORD} - -# AI模型配置 (可选) -INIT_MODEL_NAME= -INIT_MODEL_KEY= -INIT_MODEL_URL= - -# 数据报告配置 (可选) -SEACHARTCODE_DATA_REPORT_KEY= - -# 扩展下载配置 (可选) -# SEACHARTCODE_EXTENSION_BASEURL= -EOF - - log_info "✅ 环境变量文件已生成: $ENV_FILE" - log_warn "🔐 管理员密码: ${ADMIN_PASSWORD}" -} - -# 生成Docker Compose文件 -generate_compose_file() { - local version=$1 - log_info "生成 Docker Compose 文件 (版本: $version)..." - - cat > "$COMPOSE_FILE" << EOF -services: - # PostgreSQL数据库 - seachartcode-db: - image: postgres:15 - container_name: seachartcode-db - environment: - POSTGRES_DB: \${POSTGRES_DB} - POSTGRES_USER: \${POSTGRES_USER} - POSTGRES_PASSWORD: \${POSTGRES_PASSWORD} - POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --locale=C" - volumes: - - postgres_data:/var/lib/postgresql/data - ports: - - "\${POSTGRES_PORT:-5432}:5432" - restart: unless-stopped - healthcheck: - test: ["CMD-SHELL", "pg_isready -U \${POSTGRES_USER}"] - interval: 10s - timeout: 5s - retries: 5 - - # Redis缓存 - seachartcode-redis: - image: redis:7-alpine - container_name: seachartcode-redis - environment: - REDIS_PASSWORD: \${REDIS_PASSWORD} - command: redis-server --requirepass \${REDIS_PASSWORD} --port \${REDIS_PORT:-6379} - ports: - - "\${REDIS_PORT:-6379}:\${REDIS_PORT:-6379}" - volumes: - - redis_data:/data - restart: unless-stopped - healthcheck: - test: ["CMD", "redis-cli", "-p", "\${REDIS_PORT:-6379}", "--raw", "incr", "ping"] - interval: 10s - timeout: 3s - retries: 5 - - # Backend服务 - seachartcode-server: - image: ${DOCKER_REGISTRY}/seachartcode-server:${version} - container_name: seachartcode-server - environment: - # 基础配置 - ENABLE_PUBLIC_ACCESS: \${ENABLE_PUBLIC_ACCESS:-true} - LOCAL_IP: \${LOCAL_IP:-localhost} - REMOTE_IP: \${REMOTE_IP:-localhost} - NGINX_PORT: \${NGINX_PORT:-80} - - # 管理员配置 - SEACHARTCODE_ADMIN_USER: \${ADMIN_USER:-admin} - SEACHARTCODE_ADMIN_PASSWORD: \${ADMIN_PASSWORD:-admin123} - - # 数据报告配置 - SEACHARTCODE_DATA_REPORT_KEY: \${SEACHARTCODE_DATA_REPORT_KEY:-} - - # 数据库配置 - POSTGRES_USER: \${POSTGRES_USER} - POSTGRES_PASSWORD: \${POSTGRES_PASSWORD} - POSTGRES_DB: \${POSTGRES_DB} - SEACHARTCODE_DATABASE_MASTER: "postgres://\${POSTGRES_USER}:\${POSTGRES_PASSWORD}@seachartcode-db:\${POSTGRES_PORT}/\${POSTGRES_DB}?sslmode=disable" - SEACHARTCODE_DATABASE_SLAVE: "postgres://\${POSTGRES_USER}:\${POSTGRES_PASSWORD}@seachartcode-db:\${POSTGRES_PORT}/\${POSTGRES_DB}?sslmode=disable" - - # Redis配置 - REDIS_PASSWORD: \${REDIS_PASSWORD} - SEACHARTCODE_REDIS_HOST: "seachartcode-redis" - SEACHARTCODE_REDIS_PORT: \${REDIS_PORT} - SEACHARTCODE_REDIS_PASS: \${REDIS_PASSWORD} - - # AI模型配置 (可选) - INIT_MODEL_NAME: "\${INIT_MODEL_NAME:-}" - INIT_MODEL_KEY: "\${INIT_MODEL_KEY:-}" - INIT_MODEL_URL: "\${INIT_MODEL_URL:-}" - - # 扩展下载配置 - SEACHARTCODE_EXTENSION_BASEURL: "\${SEACHARTCODE_EXTENSION_BASEURL:-}" - ports: - - "\${SERVER_PORT:-8888}:8888" - depends_on: - seachartcode-db: - condition: service_healthy - seachartcode-redis: - condition: service_healthy - volumes: - - ./logs:/app/logs - restart: unless-stopped - healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://\${LOCAL_IP}:\${SERVER_PORT:-8888}/v1/health"] - interval: 30s - timeout: 10s - retries: 3 - - # Frontend Nginx服务 - seachartcode-frontend: - image: ${DOCKER_REGISTRY}/seachartcode-frontend:${version} - container_name: seachartcode-frontend - ports: - - "\${NGINX_PORT:-80}:80" - depends_on: - - seachartcode-server - restart: unless-stopped - healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1"] - interval: 30s - timeout: 10s - retries: 3 - -volumes: - postgres_data: - driver: local - redis_data: - driver: local - -networks: - default: - driver: bridge -EOF - - log_info "✅ Docker Compose 文件已生成: $COMPOSE_FILE" -} - -# 检查并清理冲突的容器 -cleanup_conflicting_containers() { - log_info "检查并清理冲突的容器..." - - local containers=("seachartcode-db" "seachartcode-redis" "seachartcode-server" "seachartcode-frontend") - local cleaned=false - - for container in "${containers[@]}"; do - if docker ps -a --format "table {{.Names}}" | grep -q "^${container}$"; then - log_warn "发现冲突容器: $container" - if docker ps --format "table {{.Names}}" | grep -q "^${container}$"; then - log_info "停止运行中的容器: $container" - docker stop "$container" &> /dev/null || true - fi - log_info "删除容器: $container" - docker rm "$container" &> /dev/null || true - cleaned=true - fi - done - - if [ "$cleaned" = true ]; then - log_info "✅ 冲突容器清理完成" - else - log_info "✅ 未发现冲突容器" - fi -} - -# 检查镜像仓库登录状态 -check_registry_login() { - local registry="$DOCKER_REGISTRY" - log_info "检查镜像仓库登录状态..." - - # 检查是否已登录 - if ! docker info 2>/dev/null | grep -q "Registry"; then - log_warn "Docker 信息获取失败,尝试测试登录状态" - fi - - # 尝试拉取一个小的测试镜像来验证登录状态 - local test_image="${registry}/seachartcode-server:${version}" - if ! docker manifest inspect "$test_image" &> /dev/null; then - log_warn "⚠️ 似乎未登录到镜像仓库或没有访问权限" - log_warn "请确保已经登录到华为云镜像仓库:" - echo " docker login $registry" - echo "" - echo -e "${YELLOW}是否继续安装?(y/N): ${NC}" - read -r continue_install - if [[ ! "$continue_install" =~ ^[Yy]$ ]]; then - log_error "安装已取消" - exit 1 - fi - else - log_info "✅ 镜像仓库连接正常" - fi -} - -# 拉取Docker镜像 -pull_images() { - local version=$1 - log_info "拉取 Docker 镜像 (版本: $version)..." - - cd "$INSTALL_DIR" - - # 设置拉取超时 - export DOCKER_CLIENT_TIMEOUT=300 - export COMPOSE_HTTP_TIMEOUT=300 - - # 使用docker-compose拉取镜像,添加重试机制 - local max_retries=3 - local retry_count=0 - - while [ $retry_count -lt $max_retries ]; do - log_info "尝试拉取镜像 (第 $((retry_count + 1)) 次)..." - - if command -v docker-compose &> /dev/null; then - if docker-compose pull; then - break - fi - else - if docker compose pull; then - break - fi - fi - - retry_count=$((retry_count + 1)) - if [ $retry_count -lt $max_retries ]; then - log_warn "镜像拉取失败,等待 10 秒后重试..." - sleep 10 - fi - done - - if [ $retry_count -eq $max_retries ]; then - log_error "镜像拉取失败,已达到最大重试次数" - log_error "请检查网络连接和镜像仓库登录状态" - exit 1 - fi - - log_info "✅ Docker 镜像拉取完成" -} - -# 安装服务 -install_service() { - local version=${1:-$DEFAULT_VERSION} - VERSION=$version - - log_info "开始安装 SeaChartCode (版本: $version)" - - check_dependencies - cleanup_conflicting_containers - create_install_dir - generate_env_file - generate_compose_file "$version" - check_registry_login - pull_images "$version" - - log_info "✅ SeaChartCode 安装完成!" - echo "" - echo -e "${GREEN}===========================================${NC}" - echo -e "${GREEN}🎉 SeaChartCode 安装成功!${NC}" - echo -e "${GREEN}===========================================${NC}" - echo "" - echo -e "${YELLOW}下一步操作:${NC}" - echo " 启动服务: $0 start" - echo " 查看状态: $0 status" - echo " 查看日志: $0 logs" - echo "" - echo -e "${YELLOW}配置文件位置:${NC}" - echo " 安装目录: $INSTALL_DIR" - echo " 环境配置: $ENV_FILE" - echo " 服务配置: $COMPOSE_FILE" - echo "" -} - -# 启动服务 -start_service() { - if [ ! -f "$COMPOSE_FILE" ]; then - log_error "服务未安装,请先运行: $0 install" - exit 1 - fi - - log_info "启动 SeaChartCode 服务..." - - # 清理可能存在的冲突容器 - cleanup_conflicting_containers - - cd "$INSTALL_DIR" - - # 尝试启动服务,添加错误处理 - local start_success=false - if command -v docker-compose &> /dev/null; then - if docker-compose up -d; then - start_success=true - fi - else - if docker compose up -d; then - start_success=true - fi - fi - - if [ "$start_success" = false ]; then - log_error "服务启动失败" - log_info "正在查看错误日志..." - if command -v docker-compose &> /dev/null; then - docker-compose logs --tail=50 - else - docker compose logs --tail=50 - fi - exit 1 - fi - - log_info "⏳ 等待服务启动..." - - # 等待服务健康检查 - local max_wait=60 - local wait_count=0 - local all_healthy=false - - while [ $wait_count -lt $max_wait ] && [ "$all_healthy" = false ]; do - sleep 5 - wait_count=$((wait_count + 5)) - - # 检查容器健康状态 - local unhealthy_count=0 - if command -v docker-compose &> /dev/null; then - unhealthy_count=$(docker-compose ps | grep -E "(unhealthy|starting)" | wc -l) - else - unhealthy_count=$(docker compose ps | grep -E "(unhealthy|starting)" | wc -l) - fi - - if [ "$unhealthy_count" -eq 0 ]; then - all_healthy=true - else - log_info "等待服务健康检查... (${wait_count}s/${max_wait}s)" - fi - done - - if [ "$all_healthy" = false ]; then - log_warn "⚠️ 某些服务可能未完全启动,请检查服务状态" - fi - - # 检查服务状态 - show_status - - # 显示访问信息 - source "$ENV_FILE" - echo "" - echo -e "${GREEN}===========================================${NC}" - echo -e "${GREEN}🚀 SeaChartCode 启动完成!${NC}" - echo -e "${GREEN}===========================================${NC}" - echo "" - echo -e "${YELLOW}🌐 访问地址:${NC}" - echo " 前端界面: http://localhost:${NGINX_PORT:-80}" - echo " 后端API: http://localhost:${SERVER_PORT:-8888}" - echo "" - echo -e "${YELLOW}👤 登录信息:${NC}" - echo " 用户名: ${ADMIN_USER:-admin}" - echo " 密码: ${ADMIN_PASSWORD}" - echo "" - echo -e "${YELLOW}📊 数据库连接:${NC}" - echo " PostgreSQL: localhost:${POSTGRES_PORT:-5432}" - echo " Redis: localhost:${REDIS_PORT:-6379}" - echo "" -} - -# 停止服务 -stop_service() { - if [ ! -f "$COMPOSE_FILE" ]; then - log_error "服务未安装" - exit 1 - fi - - log_info "停止 SeaChartCode 服务..." - cd "$INSTALL_DIR" - - if command -v docker-compose &> /dev/null; then - docker-compose down - else - docker compose down - fi - - log_info "✅ SeaChartCode 服务已停止" -} - -# 重启服务 -restart_service() { - log_info "重启 SeaChartCode 服务..." - stop_service - sleep 2 - start_service -} - -# 查看服务状态 -show_status() { - if [ ! -f "$COMPOSE_FILE" ]; then - log_error "服务未安装" - exit 1 - fi - - cd "$INSTALL_DIR" - - echo -e "${CYAN}======================= 服务状态 =======================${NC}" - if command -v docker-compose &> /dev/null; then - docker-compose ps - else - docker compose ps - fi - echo -e "${CYAN}=======================================================${NC}" -} - -# 查看日志 -show_logs() { - local service_name=$1 - - if [ ! -f "$COMPOSE_FILE" ]; then - log_error "服务未安装" - exit 1 - fi - - cd "$INSTALL_DIR" - - if [ -n "$service_name" ]; then - log_info "查看服务日志: $service_name" - if command -v docker-compose &> /dev/null; then - docker-compose logs -f "seachart-$service_name" - else - docker compose logs -f "seachart-$service_name" - fi - else - log_info "查看所有服务日志" - if command -v docker-compose &> /dev/null; then - docker-compose logs -f - else - docker compose logs -f - fi - fi -} - -# 更新服务 -update_service() { - local version=${1:-$DEFAULT_VERSION} - - log_info "更新 SeaChartCode 到版本: $version" - - # 备份当前环境变量 - if [ -f "$ENV_FILE" ]; then - cp "$ENV_FILE" "$ENV_FILE.backup" - log_info "已备份环境变量文件" - fi - - # 停止当前服务 - if [ -f "$COMPOSE_FILE" ]; then - stop_service - fi - - # 重新生成配置文件 - generate_compose_file "$version" - - # 拉取新镜像 - pull_images "$version" - - # 启动服务 - start_service - - log_info "✅ SeaChartCode 更新完成!" -} - -# 重置服务(保留数据) -reset_service() { - log_info "重置 SeaChartCode 服务(保留数据)..." - - # 停止服务 - if [ -f "$COMPOSE_FILE" ]; then - stop_service - fi - - # 清理容器但保留数据卷 - cleanup_conflicting_containers - - # 重新启动 - start_service - - log_info "✅ SeaChartCode 服务重置完成!" -} - -# 诊断服务状态 -diagnose_service() { - log_info "开始诊断 SeaChartCode 服务状态..." - echo "" - - # 检查Docker - echo -e "${CYAN}=== Docker 状态 ===${NC}" - if docker info &> /dev/null; then - echo "✅ Docker 服务正常" - else - echo "❌ Docker 服务异常" - fi - echo "" - - # 检查安装 - echo -e "${CYAN}=== 安装状态 ===${NC}" - if [ -f "$COMPOSE_FILE" ]; then - echo "✅ Docker Compose 文件存在: $COMPOSE_FILE" - else - echo "❌ Docker Compose 文件不存在" - fi - - if [ -f "$ENV_FILE" ]; then - echo "✅ 环境配置文件存在: $ENV_FILE" - else - echo "❌ 环境配置文件不存在" - fi - echo "" - - # 检查容器状态 - if [ -f "$COMPOSE_FILE" ]; then - echo -e "${CYAN}=== 容器状态 ===${NC}" - cd "$INSTALL_DIR" - if command -v docker-compose &> /dev/null; then - docker-compose ps - else - docker compose ps - fi - echo "" - - # 检查健康状态 - echo -e "${CYAN}=== 健康检查 ===${NC}" - local containers=("seachartcode-db" "seachartcode-redis" "seachartcode-server" "seachartcode-frontend") - for container in "${containers[@]}"; do - if docker ps --format "table {{.Names}}\t{{.Status}}" | grep -q "$container"; then - local status=$(docker ps --format "table {{.Names}}\t{{.Status}}" | grep "$container" | awk '{print $2}') - if [[ "$status" == *"healthy"* ]]; then - echo "✅ $container: 健康" - elif [[ "$status" == *"unhealthy"* ]]; then - echo "❌ $container: 不健康" - else - echo "⏳ $container: $status" - fi - else - echo "❌ $container: 未运行" - fi - done - echo "" - - # 检查端口 - echo -e "${CYAN}=== 端口状态 ===${NC}" - source "$ENV_FILE" 2>/dev/null || true - local ports=("${NGINX_PORT:-80}" "${SERVER_PORT:-8888}" "${POSTGRES_PORT:-5432}" "${REDIS_PORT:-6379}") - local port_names=("Frontend" "Backend" "PostgreSQL" "Redis") - - for i in "${!ports[@]}"; do - local port="${ports[$i]}" - local name="${port_names[$i]}" - if ss -tuln 2>/dev/null | grep -q ":$port " || netstat -tuln 2>/dev/null | grep -q ":$port "; then - echo "✅ $name (端口 $port): 已绑定" - else - echo "❌ $name (端口 $port): 未绑定" - fi - done - echo "" - fi - - # 检查镜像 - echo -e "${CYAN}=== 镜像状态 ===${NC}" - local found_images=false - local target_images=( - "${DOCKER_REGISTRY}/seachartcode-server" - "${DOCKER_REGISTRY}/seachartcode-frontend" - ) - - for image_repo in "${target_images[@]}"; do - local images=$(docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep "^${image_repo}" || true) - if [ -n "$images" ]; then - if [ "$found_images" = false ]; then - echo "Repository Tag Size" - found_images=true - fi - echo "$images" - fi - done - - if [ "$found_images" = false ]; then - echo "未找到相关镜像" - fi - echo "" - - # 检查磁盘空间 - echo -e "${CYAN}=== 磁盘空间 ===${NC}" - df -h "$INSTALL_DIR" 2>/dev/null || df -h / - echo "" - - log_info "诊断完成" -} - -# 卸载服务 -uninstall_service() { - echo -e "${YELLOW}⚠️ 确定要卸载 SeaChartCode 吗?这将删除所有数据!${NC}" - echo -e "${YELLOW}输入 'yes' 确认卸载: ${NC}" - read -r confirmation - - if [ "$confirmation" != "yes" ]; then - log_info "取消卸载" - exit 0 - fi - - log_info "开始卸载 SeaChartCode..." - - # 停止并删除容器 - if [ -f "$COMPOSE_FILE" ]; then - cd "$INSTALL_DIR" - log_info "停止并删除容器..." - if command -v docker-compose &> /dev/null; then - docker-compose down -v --remove-orphans - else - docker compose down -v --remove-orphans - fi - fi - - # 删除镜像 - log_info "删除相关镜像..." - local images_to_remove=( - "${DOCKER_REGISTRY}/seachartcode-server" - "${DOCKER_REGISTRY}/seachartcode-frontend" - ) - - for image_repo in "${images_to_remove[@]}"; do - # 获取该仓库的所有标签 - local image_tags=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^${image_repo}:" || true) - if [ -n "$image_tags" ]; then - log_info "删除镜像: $image_repo" - echo "$image_tags" | xargs -r docker rmi 2>/dev/null || true - fi - done - - # 删除安装目录 - log_info "删除安装目录..." - rm -rf "$INSTALL_DIR" - - # 清理Docker系统 - log_info "清理Docker系统..." - docker system prune -f 2>/dev/null || true - - echo "" - echo -e "${GREEN}===========================================${NC}" - echo -e "${GREEN}🗑️ SeaChartCode 卸载完成!${NC}" - echo -e "${GREEN}===========================================${NC}" - echo "" - log_info "感谢使用 SeaChartCode!" -} - -# 主函数 -main() { - show_banner - - case "${1:-}" in - "install") - install_service "$2" - ;; - "start") - start_service - ;; - "stop") - stop_service - ;; - "restart") - restart_service - ;; - "reset") - reset_service - ;; - "status") - show_status - ;; - "logs") - show_logs "$2" - ;; - "diagnose") - diagnose_service - ;; - "update") - update_service "$2" - ;; - "uninstall") - uninstall_service - ;; - "--help"|"-h"|"help") - show_usage - ;; - "") - log_error "缺少操作参数" - echo "" - show_usage - exit 1 - ;; - *) - log_error "未知操作: $1" - echo "" - show_usage - exit 1 - ;; - esac -} - -# 执行主函数 -main "$@" diff --git a/installer/.env b/installer/.env new file mode 100644 index 0000000..5d2fef5 --- /dev/null +++ b/installer/.env @@ -0,0 +1,37 @@ +# SeaChartCode 环境配置文件 +# 此文件由 installer.sh 自动生成 + +# 基础配置 +SEACHARTCODE_VERSION=latest +ENABLE_PUBLIC_ACCESS=true +LOCAL_IP=localhost +REMOTE_IP=localhost + +# 端口配置 +NGINX_PORT=8080 +SERVER_PORT=8888 +POSTGRES_PORT=5432 +REDIS_PORT=6379 + +# 管理员配置 +ADMIN_USER=admin +ADMIN_PASSWORD=password123 + +# 数据库配置 +POSTGRES_DB=seachartcode +POSTGRES_USER=seachartcode +POSTGRES_PASSWORD=password123 + +# Redis配置 +REDIS_PASSWORD=password123 + +# AI模型配置 (可选) +INIT_MODEL_NAME= +INIT_MODEL_KEY= +INIT_MODEL_URL= + +# 数据报告配置 (可选) +SEACHARTCODE_DATA_REPORT_KEY= + +# 扩展下载配置 (可选) +# SEACHARTCODE_EXTENSION_BASEURL= diff --git a/installer/docker-compose.yml b/installer/docker-compose.yml new file mode 100644 index 0000000..6d79016 --- /dev/null +++ b/installer/docker-compose.yml @@ -0,0 +1,117 @@ +services: + # PostgreSQL数据库 + seachartcode-db: + image: postgres:15 + container_name: seachartcode-db + environment: + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --locale=C" + volumes: + - postgres_data:/var/lib/postgresql/data + ports: + - "${POSTGRES_PORT:-5432}:5432" + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"] + interval: 10s + timeout: 5s + retries: 5 + + # Redis缓存 + seachartcode-redis: + image: redis:7-alpine + container_name: seachartcode-redis + environment: + REDIS_PASSWORD: ${REDIS_PASSWORD} + command: redis-server --requirepass ${REDIS_PASSWORD} --port ${REDIS_PORT:-6379} + ports: + - "${REDIS_PORT:-6379}:${REDIS_PORT:-6379}" + volumes: + - redis_data:/data + restart: unless-stopped + healthcheck: + test: ["CMD", "redis-cli", "-p", "${REDIS_PORT:-6379}", "--raw", "incr", "ping"] + interval: 10s + timeout: 3s + retries: 5 + + # Backend服务 + seachartcode-server: + image: swr.cn-east-3.myhuaweicloud.com/cloud-mdgx/seachartcode-server:latest + container_name: seachartcode-server + environment: + # 基础配置 + ENABLE_PUBLIC_ACCESS: ${ENABLE_PUBLIC_ACCESS:-true} + LOCAL_IP: ${LOCAL_IP:-localhost} + REMOTE_IP: ${REMOTE_IP:-localhost} + NGINX_PORT: ${NGINX_PORT:-80} + + # 管理员配置 + SEACHARTCODE_ADMIN_USER: ${ADMIN_USER:-admin} + SEACHARTCODE_ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin123} + + # 数据报告配置 + SEACHARTCODE_DATA_REPORT_KEY: ${SEACHARTCODE_DATA_REPORT_KEY:-} + + # 数据库配置 + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} + SEACHARTCODE_DATABASE_MASTER: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@seachartcode-db:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable" + SEACHARTCODE_DATABASE_SLAVE: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@seachartcode-db:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable" + + # Redis配置 + REDIS_PASSWORD: ${REDIS_PASSWORD} + SEACHARTCODE_REDIS_HOST: "seachartcode-redis" + SEACHARTCODE_REDIS_PORT: ${REDIS_PORT} + SEACHARTCODE_REDIS_PASS: ${REDIS_PASSWORD} + + # AI模型配置 (可选) + INIT_MODEL_NAME: "${INIT_MODEL_NAME:-}" + INIT_MODEL_KEY: "${INIT_MODEL_KEY:-}" + INIT_MODEL_URL: "${INIT_MODEL_URL:-}" + + # 扩展下载配置 + SEACHARTCODE_EXTENSION_BASEURL: "${SEACHARTCODE_EXTENSION_BASEURL:-}" + ports: + - "${SERVER_PORT:-8888}:8888" + depends_on: + seachartcode-db: + condition: service_healthy + seachartcode-redis: + condition: service_healthy + volumes: + - ./logs:/app/logs + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://${LOCAL_IP}:${SERVER_PORT:-8888}/v1/health"] + interval: 30s + timeout: 10s + retries: 3 + + # Frontend Nginx服务 + seachartcode-frontend: + image: swr.cn-east-3.myhuaweicloud.com/cloud-mdgx/seachartcode-frontend:latest + container_name: seachartcode-frontend + ports: + - "${NGINX_PORT:-80}:80" + depends_on: + - seachartcode-server + restart: unless-stopped + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1"] + interval: 30s + timeout: 10s + retries: 3 + +volumes: + postgres_data: + driver: local + redis_data: + driver: local + +networks: + default: + driver: bridge diff --git a/start.sh b/start.sh deleted file mode 100755 index 9579a7f..0000000 --- a/start.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash - -# SeaChartCode 启动脚本 -# 自动启动所有服务组件 - -set -e - -# 加载环境变量 -if [ -f .env ]; then - echo "📄 加载环境变量文件..." - set -a # 自动导出所有变量 - source .env - set +a # 关闭自动导出 -else - echo "⚠️ 未找到 .env 文件,使用默认配置" -fi - -echo "🚀 正在启动 SeaChartCode 服务..." -echo "==================================================" - -# 检查docker和docker-compose是否安装 -if ! command -v docker &> /dev/null; then - echo "❌ Docker 未安装,请先安装 Docker" - exit 1 -fi - -if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then - echo "❌ Docker Compose 未安装,请先安装 Docker Compose" - exit 1 -fi - -# 创建必要的目录 -echo "📁 创建必要的目录..." -mkdir -p logs static - -# 检查镜像是否存在 -echo "🔍 检查 Docker 镜像..." -if ! docker images | grep -q "seachartcode-server"; then - echo "❌ Backend 镜像未找到,请先构建镜像" - echo " 运行: cd backend && make image" - exit 1 -fi - -if ! docker images | grep -q "seachartcode-frontend"; then - echo "❌ Frontend 镜像未找到,请先构建镜像" - echo " 运行: cd ui && make image" - exit 1 -fi - -echo "✅ 所有镜像检查完成" - -# 停止可能存在的旧服务 -echo "🛑 停止现有服务..." -docker-compose down --remove-orphans 2>/dev/null || docker compose down --remove-orphans 2>/dev/null || true - -# 启动服务 -echo "🚀 启动服务..." -if command -v docker-compose &> /dev/null; then - docker-compose up -d -else - docker compose up -d -fi - -# 等待服务启动 -echo "⏳ 等待服务启动..." -sleep 10 - -# 检查服务状态 -echo "📊 检查服务状态..." -if command -v docker-compose &> /dev/null; then - docker-compose ps -else - docker compose ps -fi - -echo "" -echo "==================================================" -echo "🎉 SeaChartCode 启动完成!" -echo "" -echo "📋 服务信息:" -echo " 前端访问地址: http://localhost:${NGINX_PORT:-}" -echo " 后端API地址: http://localhost:${SERVER_PORT:-8888}" -echo " 数据库端口: localhost:${POSTGRES_PORT:-5432}" -echo " Redis端口: localhost:${REDIS_PORT:-6379}" -echo "" -echo "👤 默认管理员账号:" -echo " 用户名: ${ADMIN_USER:-admin}" -echo " 密码: ${ADMIN_PASSWORD:-admin123}" -echo "" -echo "📝 服务日志查看:" -echo " 查看所有日志: docker-compose logs -f" -echo " 查看后端日志: docker-compose logs -f seachartcode-server" -echo " 查看前端日志: docker-compose logs -f seachartcode-frontend" -echo "" -echo "🛑 停止服务:" -echo " docker-compose down" -echo "" -echo "✨ 享受使用 SeaChartCode" \ No newline at end of file diff --git a/status.sh b/status.sh deleted file mode 100755 index 1516d4b..0000000 --- a/status.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash - -# SeaChartCode 服务状态检查脚本 - -# 加载环境变量 -if [ -f .env ]; then - echo "📄 加载环境变量文件..." - set -a # 自动导出所有变量 - source .env - set +a # 关闭自动导出 -else - echo "⚠️ 未找到 .env 文件,使用默认配置" -fi - -echo "🔍 SeaChartCode 服务状态检查" -echo "==================================================" - -# 检查容器状态 -echo "📦 容器状态:" -if command -v docker-compose &> /dev/null; then - docker-compose ps -else - docker compose ps -fi - -echo "" -echo "🌐 服务连通性检查:" - -# 检查前端服务 -echo -n "前端服务 (http://localhost:${NGINX_PORT:-}): " -if curl -s --connect-timeout 3 http://localhost:${NGINX_PORT:-} > /dev/null; then - echo "✅ 正常" -else - echo "❌ 无法访问" -fi - -# 检查后端API -echo -n "后端API (http://localhost:${SERVER_PORT:-8888}): " -if curl -s --connect-timeout 3 http://localhost:${SERVER_PORT:-8888}/api/health > /dev/null 2>&1; then - echo "✅ 正常" -else - echo "❌ 无法访问" -fi - -# 检查数据库连接 -echo -n "PostgreSQL数据库: " -if docker exec seachartcode-db pg_isready -U ${POSTGRES_USER} > /dev/null 2>&1; then - echo "✅ 正常" -else - echo "❌ 无法连接" -fi - -# 检查Redis连接 -echo -n "Redis缓存: " -if docker exec seachartcode-redis redis-cli -p ${REDIS_PORT:-6379} -a ${REDIS_PASSWORD} ping > /dev/null 2>&1; then - echo "✅ 正常" -else - echo "❌ 无法连接" -fi - -echo "" -echo "📊 资源使用情况:" -docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}" - -echo "" -echo "📝 查看详细日志:" -echo " 所有服务: docker-compose logs -f" -echo " 后端服务: docker-compose logs -f seachartcode-server" -echo " 前端服务: docker-compose logs -f seachartcode-frontend" -echo " 数据库: docker-compose logs -f seachartcode-db" -echo " Redis: docker-compose logs -f seachartcode-redis" \ No newline at end of file -- Gitee From cdc021f32e026327187e8753d95ef135a5d65147 Mon Sep 17 00:00:00 2001 From: ethanqzheng Date: Wed, 10 Sep 2025 16:18:33 +0800 Subject: [PATCH 2/3] feat: update seachartcode install shell --- installer/seachartcode.sh | 813 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 813 insertions(+) create mode 100755 installer/seachartcode.sh diff --git a/installer/seachartcode.sh b/installer/seachartcode.sh new file mode 100755 index 0000000..8664203 --- /dev/null +++ b/installer/seachartcode.sh @@ -0,0 +1,813 @@ +#!/bin/bash + +# SeaChartCode 一键安装器 +# 支持指定版本和默认latest版本,一键安装启动和一键卸载 + +set -e + +# 信号处理 - 优雅退出 +cleanup_on_exit() { + local exit_code=$? + if [ $exit_code -ne 0 ]; then + log_error "脚本异常退出 (退出码: $exit_code)" + fi +} + +trap cleanup_on_exit EXIT +trap 'log_warn "收到中断信号,正在清理..."; exit 130' INT TERM + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# 配置变量 +SCRIPT_VERSION="1.0.0" +DEFAULT_VERSION="latest" +DOCKER_REGISTRY="swr.cn-east-3.myhuaweicloud.com/cloud-mdgx" # 华为云容器镜像服务 +GITEE_REPO="https://gitee.com/metastone-project/SeachartCode/raw/dev/ethan-20250910-update-installer/installer/" +PROJECT_NAME="seachartcode" +INSTALL_DIR="${HOME}/.seachartcode" +COMPOSE_FILE="$INSTALL_DIR/docker-compose.yml" +ENV_FILE="$INSTALL_DIR/.env" + +# 显示横幅 +show_banner() { + echo -e "${CYAN}" + echo "==================================================" + echo " SeaChartCode 一键安装器 v${SCRIPT_VERSION}" + echo "==================================================" + echo -e "${NC}" +} + +# 显示使用说明 +show_usage() { + echo -e "${YELLOW}使用方法:${NC}" + echo " $0 install [版本号] # 安装指定版本 (默认: latest)" + echo " $0 start # 启动服务" + echo " $0 stop # 停止服务" + echo " $0 restart # 重启服务" + echo " $0 reset # 重置服务(保留数据)" + echo " $0 status # 查看服务状态" + echo " $0 logs [服务名] # 查看日志" + echo " $0 diagnose # 诊断服务状态" + echo " $0 update [版本号] # 更新到指定版本" + echo " $0 uninstall # 卸载服务" + echo " $0 --help # 显示此帮助信息" + echo "" + echo -e "${YELLOW}示例:${NC}" + echo " $0 install # 安装最新版本" + echo " $0 install v1.0.0 # 安装v1.0.0版本" + echo " $0 logs server # 查看后端服务日志" + echo " $0 diagnose # 全面诊断系统状态" + echo " $0 reset # 重置服务解决问题" + echo "" +} + +# 日志函数 +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_debug() { + echo -e "${BLUE}[DEBUG]${NC} $1" +} + +# 检查依赖 +check_dependencies() { + log_info "检查系统依赖..." + + # 检查Docker + if ! command -v docker &> /dev/null; then + log_error "Docker 未安装,请先安装 Docker" + echo "安装指南: https://docs.docker.com/get-docker/" + exit 1 + fi + + # 检查Docker Compose + if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then + log_error "Docker Compose 未安装,请先安装 Docker Compose" + echo "安装指南: https://docs.docker.com/compose/install/" + exit 1 + fi + + # 检查Docker服务状态 + if ! docker info &> /dev/null; then + log_error "Docker 服务未运行,请启动 Docker 服务" + exit 1 + fi + + log_info "✅ 所有依赖检查完成" +} + +# 创建安装目录 +create_install_dir() { + log_info "创建安装目录: $INSTALL_DIR" + mkdir -p "$INSTALL_DIR" + mkdir -p "$INSTALL_DIR/logs" +} + +# 下载环境变量文件 +download_env_file() { + log_info "下载环境变量文件..." + + if [ -f "$ENV_FILE" ]; then + log_warn "✅ 环境变量文件已存在,跳过下载" + return + fi + + # Gitee项目配置 + local env_file_url="${GITEE_REPO}/.env" + + # 检查是否有下载工具 + if ! command -v curl &> /dev/null && ! command -v wget &> /dev/null; then + log_error "❌ 未找到下载工具 (curl 或 wget),请安装 curl 或 wget 后重试,或手动下载 .env 文件到: $ENV_FILE" + exit 1 + fi + + # 尝试下载.env文件 + local download_success=false + + if command -v curl &> /dev/null; then + if curl -fsSL "$env_file_url" -o "$ENV_FILE"; then + download_success=true + fi + fi + + if [ "$download_success" = false ] && command -v wget &> /dev/null; then + if wget -q "$env_file_url" -O "$ENV_FILE"; then + download_success=true + fi + fi + + if [ "$download_success" = false ]; then + log_error "❌ 无法下载环境变量文件, 下载地址: $env_file_url" + log_error "可能的原因:" + log_error " 1. 网络连接问题" + log_error " 2. Gitee服务不可用" + log_error " 3. 文件路径不存在" + log_error "" + log_error "请检查网络连接或手动下载 .env 文件到: $ENV_FILE" + exit 1 + fi + + log_info "✅ 环境变量文件下载成功: $ENV_FILE" + + # 生成随机密码并替换到.env文件中 + log_info "生成随机密码并更新配置文件..." + + # 生成随机密码 + local POSTGRES_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-16) + local REDIS_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-16) + local ADMIN_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-12) + + # 替换密码字段 + if command -v sed &> /dev/null; then + # 使用sed替换密码 + sed -i "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=${POSTGRES_PASSWORD}/" "$ENV_FILE" + sed -i "s/^REDIS_PASSWORD=.*/REDIS_PASSWORD=${REDIS_PASSWORD}/" "$ENV_FILE" + sed -i "s/^ADMIN_PASSWORD=.*/ADMIN_PASSWORD=${ADMIN_PASSWORD}/" "$ENV_FILE" + else + log_warn "⚠️ sed命令未找到,无法自动更新密码" + log_warn "请手动更新以下密码字段:" + log_warn " POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" + log_warn " REDIS_PASSWORD=${REDIS_PASSWORD}" + log_warn " ADMIN_PASSWORD=${ADMIN_PASSWORD}" + fi + +} + +# 检查并清理冲突的容器 +cleanup_conflicting_containers() { + log_info "检查并清理冲突的容器..." + + local containers=("seachartcode-db" "seachartcode-redis" "seachartcode-server" "seachartcode-frontend") + local cleaned=false + + for container in "${containers[@]}"; do + if docker ps -a --format "table {{.Names}}" | grep -q "^${container}$"; then + log_warn "发现冲突容器: $container" + if docker ps --format "table {{.Names}}" | grep -q "^${container}$"; then + log_info "停止运行中的容器: $container" + docker stop "$container" &> /dev/null || true + fi + log_info "删除容器: $container" + docker rm "$container" &> /dev/null || true + cleaned=true + fi + done + + if [ "$cleaned" = true ]; then + log_info "✅ 冲突容器清理完成" + else + log_info "✅ 未发现冲突容器" + fi +} + +# 检查镜像仓库登录状态 +check_registry_login() { + local version=$1 + local registry="$DOCKER_REGISTRY" + log_info "检查镜像仓库登录状态..." + + # 检查是否已登录 + if ! docker info 2>/dev/null | grep -q "Registry"; then + log_warn "Docker 信息获取失败,尝试测试登录状态" + fi + + # 尝试拉取一个小的测试镜像来验证登录状态 + local test_image="${registry}/seachartcode-server:${version}" + if ! docker manifest inspect "$test_image" &> /dev/null; then + log_warn "⚠️ 似乎未登录到镜像仓库或没有访问权限" + log_warn "请确保已经登录到华为云镜像仓库:" + echo " docker login $registry" + echo "" + echo -e "${YELLOW}是否继续安装?(y/N): ${NC}" + read -r continue_install + if [[ ! "$continue_install" =~ ^[Yy]$ ]]; then + log_error "安装已取消" + exit 1 + fi + else + log_info "✅ 镜像仓库连接正常" + fi +} + +# 拉取Docker镜像 +pull_images() { + local version=$1 + log_info "拉取 Docker 镜像 (版本: $version)..." + + cd "$INSTALL_DIR" + + # 设置拉取超时 + export DOCKER_CLIENT_TIMEOUT=300 + export COMPOSE_HTTP_TIMEOUT=300 + + # 使用docker-compose拉取镜像,添加重试机制 + local max_retries=3 + local retry_count=0 + + while [ $retry_count -lt $max_retries ]; do + log_info "尝试拉取镜像 (第 $((retry_count + 1)) 次)..." + + if command -v docker-compose &> /dev/null; then + if docker-compose pull; then + break + fi + else + if docker compose pull; then + break + fi + fi + + retry_count=$((retry_count + 1)) + if [ $retry_count -lt $max_retries ]; then + log_warn "镜像拉取失败,等待 10 秒后重试..." + sleep 10 + fi + done + + if [ $retry_count -eq $max_retries ]; then + log_error "镜像拉取失败,已达到最大重试次数" + log_error "请检查网络连接和镜像仓库登录状态" + exit 1 + fi + + log_info "✅ Docker 镜像拉取完成" +} + +# 安装服务 +install_service() { + local version=${1:-$DEFAULT_VERSION} + VERSION=$version + + log_info "开始安装 SeaChartCode (版本: $version)" + + check_dependencies + cleanup_conflicting_containers + create_install_dir + download_env_file + download_docker_compose "$version" + check_registry_login "$version" + pull_images "$version" + + log_info "✅ SeaChartCode 安装完成!" + echo "" + echo -e "${GREEN}===========================================${NC}" + echo -e "${GREEN}🎉 SeaChartCode 安装成功!${NC}" + echo -e "${GREEN}===========================================${NC}" + echo "" + echo -e "${YELLOW}下一步操作:${NC}" + echo " 启动服务: $0 start" + echo " 查看状态: $0 status" + echo " 查看日志: $0 logs" + echo "" + echo -e "${YELLOW}配置文件位置:${NC}" + echo " 安装目录: $INSTALL_DIR" + echo " 环境配置: $ENV_FILE" + echo " 服务配置: $COMPOSE_FILE" + echo "" +} + +# 启动服务 +start_service() { + if [ ! -f "$COMPOSE_FILE" ]; then + log_error "服务未安装,请先运行: $0 install" + exit 1 + fi + + log_info "启动 SeaChartCode 服务..." + + # 清理可能存在的冲突容器 + cleanup_conflicting_containers + + cd "$INSTALL_DIR" + + # 尝试启动服务,添加错误处理 + local start_success=false + if command -v docker-compose &> /dev/null; then + if docker-compose up -d; then + start_success=true + fi + else + if docker compose up -d; then + start_success=true + fi + fi + + if [ "$start_success" = false ]; then + log_error "服务启动失败" + log_info "正在查看错误日志..." + if command -v docker-compose &> /dev/null; then + docker-compose logs --tail=50 + else + docker compose logs --tail=50 + fi + exit 1 + fi + + log_info "⏳ 等待服务启动..." + + # 等待服务健康检查 + local max_wait=60 + local wait_count=0 + local all_healthy=false + + while [ $wait_count -lt $max_wait ] && [ "$all_healthy" = false ]; do + sleep 5 + wait_count=$((wait_count + 5)) + + # 检查容器健康状态 + local unhealthy_count=0 + if command -v docker-compose &> /dev/null; then + unhealthy_count=$(docker-compose ps | grep -E "(unhealthy|starting)" | wc -l) + else + unhealthy_count=$(docker compose ps | grep -E "(unhealthy|starting)" | wc -l) + fi + + if [ "$unhealthy_count" -eq 0 ]; then + all_healthy=true + else + log_info "等待服务健康检查... (${wait_count}s/${max_wait}s)" + fi + done + + if [ "$all_healthy" = false ]; then + log_warn "⚠️ 某些服务可能未完全启动,请检查服务状态" + fi + + # 检查服务状态 + show_status + + # 显示访问信息 + source "$ENV_FILE" + echo "" + echo -e "${GREEN}===========================================${NC}" + echo -e "${GREEN}🚀 SeaChartCode 启动完成!${NC}" + echo -e "${GREEN}===========================================${NC}" + echo "" + echo -e "${YELLOW}🌐 访问地址:${NC}" + echo " 前端界面: http://localhost:${NGINX_PORT:-80}" + echo " 后端API: http://localhost:${SERVER_PORT:-8888}" + echo "" + echo -e "${YELLOW}👤 登录信息:${NC}" + echo " 用户名: ${ADMIN_USER:-admin}" + echo " 密码: ${ADMIN_PASSWORD}" + echo "" + echo -e "${YELLOW}📊 数据库连接:${NC}" + echo " PostgreSQL: localhost:${POSTGRES_PORT:-5432}" + echo " Redis: localhost:${REDIS_PORT:-6379}" + echo "" +} + +# 停止服务 +stop_service() { + if [ ! -f "$COMPOSE_FILE" ]; then + log_error "服务未安装" + exit 1 + fi + + log_info "停止 SeaChartCode 服务..." + cd "$INSTALL_DIR" + + if command -v docker-compose &> /dev/null; then + docker-compose down + else + docker compose down + fi + + log_info "✅ SeaChartCode 服务已停止" +} + +# 重启服务 +restart_service() { + log_info "重启 SeaChartCode 服务..." + stop_service + sleep 2 + start_service +} + +# 下载并配置docker-compose.yml文件 +download_docker_compose() { + local version=$1 + log_info "下载docker-compose.yml文件..." + local compose_file_url="${GITEE_REPO}/docker-compose.yml" + local temp_compose_file="/tmp/docker-compose.yml.tmp" + + # 下载docker-compose.yml文件 + local download_success=false + + if command -v curl &> /dev/null; then + if curl -fsSL "$compose_file_url" -o "$temp_compose_file"; then + download_success=true + fi + fi + + if [ "$download_success" = false ] && command -v wget &> /dev/null; then + if wget -q "$compose_file_url" -O "$temp_compose_file"; then + download_success=true + fi + fi + + if [ "$download_success" = false ]; then + log_error "❌ 无法下载docker-compose.yml文件, 下载地址: $compose_file_url" + exit 1 + fi + + log_info "✅ docker-compose.yml文件下载成功" + + # 配置镜像地址和版本 + log_info "配置镜像地址和版本..." + + # 设置默认的Docker镜像仓库 + local DOCKER_REGISTRY=${DOCKER_REGISTRY:-"swr.cn-east-3.myhuaweicloud.com/cloud-mdgx"} + local VERSION=${version:-"latest"} + + # 替换镜像配置 + if command -v sed &> /dev/null; then + # 替换seachartcode-server镜像 + sed -i "s|image: .*/seachartcode-server:.*|image: ${DOCKER_REGISTRY}/seachartcode-server:${VERSION}|" "$temp_compose_file" + + # 替换seachartcode-frontend镜像 + sed -i "s|image: .*/seachartcode-frontend:.*|image: ${DOCKER_REGISTRY}/seachartcode-frontend:${VERSION}|" "$temp_compose_file" + + log_info "✅ 镜像配置已更新" + else + log_warn "⚠️ sed命令未找到,无法自动更新镜像配置" + log_warn "请手动更新以下镜像配置:" + log_warn " seachartcode-server: ${DOCKER_REGISTRY}/seachartcode-server:${VERSION}" + log_warn " seachartcode-frontend: ${DOCKER_REGISTRY}/seachartcode-frontend:${VERSION}" + fi + + # 移动文件到目标位置 + mv "$temp_compose_file" "$COMPOSE_FILE" + log_info "✅ docker-compose.yml文件已配置完成: $COMPOSE_FILE" +} + +# 查看服务状态 +show_status() { + if [ ! -f "$COMPOSE_FILE" ]; then + log_error "服务未安装" + exit 1 + fi + + cd "$INSTALL_DIR" + + echo -e "${CYAN}======================= 服务状态 =======================${NC}" + if command -v docker-compose &> /dev/null; then + docker-compose ps + else + docker compose ps + fi + echo -e "${CYAN}=======================================================${NC}" +} + +# 查看日志 +show_logs() { + local service_name=$1 + + if [ ! -f "$COMPOSE_FILE" ]; then + log_error "服务未安装" + exit 1 + fi + + cd "$INSTALL_DIR" + + if [ -n "$service_name" ]; then + log_info "查看服务日志: $service_name" + if command -v docker-compose &> /dev/null; then + docker-compose logs -f "seachart-$service_name" + else + docker compose logs -f "seachart-$service_name" + fi + else + log_info "查看所有服务日志" + if command -v docker-compose &> /dev/null; then + docker-compose logs -f + else + docker compose logs -f + fi + fi +} + +# 更新服务 +update_service() { + local version=${1:-$DEFAULT_VERSION} + + log_info "更新 SeaChartCode 到版本: $version" + + # 备份当前环境变量 + if [ -f "$ENV_FILE" ]; then + cp "$ENV_FILE" "$ENV_FILE.backup" + log_info "已备份环境变量文件" + fi + + # 停止当前服务 + if [ -f "$COMPOSE_FILE" ]; then + stop_service + fi + + # 重新下载配置文件 + download_env_file + download_docker_compose "$version" + + # 拉取新镜像 + pull_images "$version" + + # 启动服务 + start_service + + log_info "✅ SeaChartCode 更新完成!" +} + +# 重置服务(保留数据) +reset_service() { + log_info "重置 SeaChartCode 服务(保留数据)..." + + # 停止服务 + if [ -f "$COMPOSE_FILE" ]; then + stop_service + fi + + # 清理容器但保留数据卷 + cleanup_conflicting_containers + + # 重新启动 + start_service + + log_info "✅ SeaChartCode 服务重置完成!" +} + +# 诊断服务状态 +diagnose_service() { + log_info "开始诊断 SeaChartCode 服务状态..." + echo "" + + # 检查Docker + echo -e "${CYAN}=== Docker 状态 ===${NC}" + if docker info &> /dev/null; then + echo "✅ Docker 服务正常" + else + echo "❌ Docker 服务异常" + fi + echo "" + + # 检查安装 + echo -e "${CYAN}=== 安装状态 ===${NC}" + if [ -f "$COMPOSE_FILE" ]; then + echo "✅ Docker Compose 文件存在: $COMPOSE_FILE" + else + echo "❌ Docker Compose 文件不存在" + fi + + if [ -f "$ENV_FILE" ]; then + echo "✅ 环境配置文件存在: $ENV_FILE" + else + echo "❌ 环境配置文件不存在" + fi + echo "" + + # 检查容器状态 + if [ -f "$COMPOSE_FILE" ]; then + echo -e "${CYAN}=== 容器状态 ===${NC}" + cd "$INSTALL_DIR" + if command -v docker-compose &> /dev/null; then + docker-compose ps + else + docker compose ps + fi + echo "" + + # 检查健康状态 + echo -e "${CYAN}=== 健康检查 ===${NC}" + local containers=("seachartcode-db" "seachartcode-redis" "seachartcode-server" "seachartcode-frontend") + for container in "${containers[@]}"; do + if docker ps --format "table {{.Names}}\t{{.Status}}" | grep -q "$container"; then + local status=$(docker ps --format "table {{.Names}}\t{{.Status}}" | grep "$container" | awk '{print $2}') + if [[ "$status" == *"healthy"* ]]; then + echo "✅ $container: 健康" + elif [[ "$status" == *"unhealthy"* ]]; then + echo "❌ $container: 不健康" + else + echo "⏳ $container: $status" + fi + else + echo "❌ $container: 未运行" + fi + done + echo "" + + # 检查端口 + echo -e "${CYAN}=== 端口状态 ===${NC}" + source "$ENV_FILE" 2>/dev/null || true + local ports=("${NGINX_PORT:-80}" "${SERVER_PORT:-8888}" "${POSTGRES_PORT:-5432}" "${REDIS_PORT:-6379}") + local port_names=("Frontend" "Backend" "PostgreSQL" "Redis") + + for i in "${!ports[@]}"; do + local port="${ports[$i]}" + local name="${port_names[$i]}" + if ss -tuln 2>/dev/null | grep -q ":$port " || netstat -tuln 2>/dev/null | grep -q ":$port "; then + echo "✅ $name (端口 $port): 已绑定" + else + echo "❌ $name (端口 $port): 未绑定" + fi + done + echo "" + fi + + # 检查镜像 + echo -e "${CYAN}=== 镜像状态 ===${NC}" + local found_images=false + local target_images=( + "${DOCKER_REGISTRY}/seachartcode-server" + "${DOCKER_REGISTRY}/seachartcode-frontend" + ) + + for image_repo in "${target_images[@]}"; do + local images=$(docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" | grep "^${image_repo}" || true) + if [ -n "$images" ]; then + if [ "$found_images" = false ]; then + echo "Repository Tag Size" + found_images=true + fi + echo "$images" + fi + done + + if [ "$found_images" = false ]; then + echo "未找到相关镜像" + fi + echo "" + + # 检查磁盘空间 + echo -e "${CYAN}=== 磁盘空间 ===${NC}" + df -h "$INSTALL_DIR" 2>/dev/null || df -h / + echo "" + + log_info "诊断完成" +} + +# 卸载服务 +uninstall_service() { + echo -e "${YELLOW}⚠️ 确定要卸载 SeaChartCode 吗?这将删除所有数据!${NC}" + echo -e "${YELLOW}输入 'yes' 确认卸载: ${NC}" + read -r confirmation + + if [ "$confirmation" != "yes" ]; then + log_info "取消卸载" + exit 0 + fi + + log_info "开始卸载 SeaChartCode..." + + # 停止并删除容器 + if [ -f "$COMPOSE_FILE" ]; then + cd "$INSTALL_DIR" + log_info "停止并删除容器..." + if command -v docker-compose &> /dev/null; then + docker-compose down -v --remove-orphans + else + docker compose down -v --remove-orphans + fi + fi + + # 删除镜像 + log_info "删除相关镜像..." + local images_to_remove=( + "${DOCKER_REGISTRY}/seachartcode-server" + "${DOCKER_REGISTRY}/seachartcode-frontend" + ) + + for image_repo in "${images_to_remove[@]}"; do + # 获取该仓库的所有标签 + local image_tags=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "^${image_repo}:" || true) + if [ -n "$image_tags" ]; then + log_info "删除镜像: $image_repo" + echo "$image_tags" | xargs -r docker rmi 2>/dev/null || true + fi + done + + # 删除安装目录 + log_info "删除安装目录..." + rm -rf "$INSTALL_DIR" + + # 清理Docker系统 + log_info "清理Docker系统..." + docker system prune -f 2>/dev/null || true + + echo "" + echo -e "${GREEN}===========================================${NC}" + echo -e "${GREEN}🗑️ SeaChartCode 卸载完成!${NC}" + echo -e "${GREEN}===========================================${NC}" + echo "" + log_info "感谢使用 SeaChartCode!" +} + +# 主函数 +main() { + show_banner + + case "${1:-}" in + "install") + install_service "$2" + ;; + "start") + start_service + ;; + "stop") + stop_service + ;; + "restart") + restart_service + ;; + "reset") + reset_service + ;; + "status") + show_status + ;; + "logs") + show_logs "$2" + ;; + "diagnose") + diagnose_service + ;; + "update") + update_service "$2" + ;; + "uninstall") + uninstall_service + ;; + "--help"|"-h"|"help") + show_usage + ;; + "") + log_error "缺少操作参数" + echo "" + show_usage + exit 1 + ;; + *) + log_error "未知操作: $1" + echo "" + show_usage + exit 1 + ;; + esac +} + +# 执行主函数 +main "$@" -- Gitee From e566afa56248d94fd666b4b6256e2e415af4a1c2 Mon Sep 17 00:00:00 2001 From: ethanqzheng Date: Wed, 10 Sep 2025 16:19:03 +0800 Subject: [PATCH 3/3] feat: update seachartcode install shell --- installer/seachartcode.sh | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/installer/seachartcode.sh b/installer/seachartcode.sh index 8664203..a7cc510 100755 --- a/installer/seachartcode.sh +++ b/installer/seachartcode.sh @@ -29,7 +29,8 @@ NC='\033[0m' # No Color SCRIPT_VERSION="1.0.0" DEFAULT_VERSION="latest" DOCKER_REGISTRY="swr.cn-east-3.myhuaweicloud.com/cloud-mdgx" # 华为云容器镜像服务 -GITEE_REPO="https://gitee.com/metastone-project/SeachartCode/raw/dev/ethan-20250910-update-installer/installer/" +GITEE_BASE_URL="https://gitee.com/metastone-project/SeachartCode" + PROJECT_NAME="seachartcode" INSTALL_DIR="${HOME}/.seachartcode" COMPOSE_FILE="$INSTALL_DIR/docker-compose.yml" @@ -112,6 +113,20 @@ check_dependencies() { log_info "✅ 所有依赖检查完成" } +# 构建版本化URL +build_versioned_url() { + local version=$1 + local file_path=$2 + + if [ "$version" = "latest" ]; then + # 对于latest版本,使用master分支 + echo "${GITEE_BASE_URL}/raw/master/installer/${file_path}" + else + # 对于指定版本,使用release标签 + echo "${GITEE_BASE_URL}/raw/${version}/installer/${file_path}" + fi +} + # 创建安装目录 create_install_dir() { log_info "创建安装目录: $INSTALL_DIR" @@ -121,6 +136,7 @@ create_install_dir() { # 下载环境变量文件 download_env_file() { + local version=${1:-$DEFAULT_VERSION} log_info "下载环境变量文件..." if [ -f "$ENV_FILE" ]; then @@ -128,8 +144,8 @@ download_env_file() { return fi - # Gitee项目配置 - local env_file_url="${GITEE_REPO}/.env" + # 构建版本化URL + local env_file_url=$(build_versioned_url "$version" ".env") # 检查是否有下载工具 if ! command -v curl &> /dev/null && ! command -v wget &> /dev/null; then @@ -299,7 +315,7 @@ install_service() { check_dependencies cleanup_conflicting_containers create_install_dir - download_env_file + download_env_file "$version" download_docker_compose "$version" check_registry_login "$version" pull_images "$version" @@ -444,7 +460,8 @@ restart_service() { download_docker_compose() { local version=$1 log_info "下载docker-compose.yml文件..." - local compose_file_url="${GITEE_REPO}/docker-compose.yml" + local compose_file_url=$(build_versioned_url "$version" "docker-compose.yml") + log_info "✅ 镜像配置url: $compose_file_url" local temp_compose_file="/tmp/docker-compose.yml.tmp" # 下载docker-compose.yml文件 @@ -561,7 +578,7 @@ update_service() { fi # 重新下载配置文件 - download_env_file + download_env_file "$version" download_docker_compose "$version" # 拉取新镜像 -- Gitee