From 9e1813daca13cf0485c09aeb60bae1790c21df67 Mon Sep 17 00:00:00 2001 From: jingrow Date: Mon, 11 Aug 2025 01:10:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0create=5Fand=5Fstart=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 267 ++++++++++++++++++++++++------------------------- jsite.sh | 128 ++++++++++++++++++++++-- test_status.sh | 81 +++++++++++++++ 3 files changed, 335 insertions(+), 141 deletions(-) create mode 100644 test_status.sh diff --git a/README.md b/README.md index 5345b22..8c1f65c 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,31 @@ -# jsite 自动化部署和管理脚本 +# jsite.sh - 前端自动化部署脚本 -这是一个集成了完整部署和日常管理功能的自动化脚本,支持多种任务模式。 +## 概述 -## 功能特性 +`jsite.sh` 是一个用于自动化部署和管理前端网站的bash脚本。它支持多种操作模式,包括部署、启动、停止、重启等。 -- 🚀 **完整部署**:一键部署完整的jsite环境 -- 🏗️ **网站管理**:创建、删除、构建、启动、停止、重启网站 -- 📊 **状态监控**:查看网站运行状态和日志 -- 🔧 **环境管理**:Docker、Node.js、PM2、Traefik等环境组件 -- ⚡ **智能端口分配**:自动分配和管理端口资源 +## 主要功能 + +- 自动创建和管理jingrow用户 +- 安装和配置Node.js、npm、PM2 +- 自动化部署前端项目 +- 集成Traefik反向代理 +- 支持多种操作模式 ## 使用方法 ### 基本语法 ```bash -./install_jsite.sh --mode <任务模式> [其他参数] +./jsite.sh --mode <模式> --site-name <网站名称> ``` -### 支持的任务模式 +### 支持的模式 -| 模式 | 功能 | 示例 | +| 模式 | 描述 | 示例 | |------|------|------| -| `deploy` | 完整部署模式(默认) | `--mode deploy --site-name myproject` | -| `create` | 创建新网站 | `--mode create --site-name myproject --git-repo <仓库地址>` | +| `deploy` | 完整部署网站 | `--mode deploy --site-name myproject` | +| `create` | 创建新网站 | `--mode create --site-name myproject` | | `delete` | 删除网站 | `--mode delete --site-name myproject` | | `build` | 构建网站 | `--mode build --site-name myproject` | | `start` | 启动网站 | `--mode start --site-name myproject` | @@ -33,157 +35,152 @@ | `list` | 列出所有网站 | `--mode list` | | `logs` | 查看网站日志 | `--mode logs --site-name myproject` | -### 常用参数 - -| 参数 | 说明 | 默认值 | -|------|------|--------| -| `--mode` | 任务模式 | `deploy` | -| `--site-name` | 网站名称 | `jingrow` | -| `--git-repo` | Git仓库地址 | `http://git.jingrow.com:3000/jsite/jingrow` | -| `--node-version` | Node.js版本 | `22` | -| `--start-port` | 起始端口 | `3001` | -| `--site-url` | 网站域名 | `starrbud.com` | - -### 使用示例 - -#### 1. 完整部署新项目 +### 常用命令示例 ```bash -./install_jsite.sh \ - --mode deploy \ - --site-name myproject \ - --git-repo http://git.example.com/myproject \ - --site-url myproject.com \ - --public-ip 8.217.167.199 -``` +# 部署新网站 +./jsite.sh --mode deploy --site-name jingrow -#### 2. 创建新网站 - -```bash -./install_jsite.sh \ - --mode create \ - --site-name myproject \ - --git-repo http://git.example.com/myproject \ - --site-url myproject.com -``` - -#### 3. 构建和启动网站 - -```bash -# 构建项目 -./install_jsite.sh --mode build --site-name myproject - -# 启动项目 -./install_jsite.sh --mode start --site-name myproject -``` - -#### 4. 管理网站状态 - -```bash -# 查看状态 -./install_jsite.sh --mode status --site-name myproject - -# 停止网站 -./install_jsite.sh --mode stop --site-name myproject +# 启动网站 +./jsite.sh --mode start --site-name jingrow # 重启网站 -./install_jsite.sh --mode restart --site-name myproject +./jsite.sh --mode restart --site-name jingrow + +# 查看网站状态 +./jsite.sh --mode status --site-name jingrow + +# 查看所有网站 +./jsite.sh --mode list ``` -#### 5. 查看所有网站 +## 故障排除 +### 常见错误及解决方案 + +#### 1. PM2进程未找到错误 + +**错误信息:** +``` +[PM2][ERROR] Process or Namespace jingrow not found +``` + +**原因:** 网站尚未部署或PM2进程未正确启动 + +**解决方案:** +1. 首先检查网站是否存在: + ```bash + ./jsite.sh --mode status --site-name jingrow + ``` + +2. 如果网站不存在,先部署: + ```bash + ./jsite.sh --mode deploy --site-name jingrow + ``` + +3. 如果网站存在但未运行,启动网站: + ```bash + ./jsite.sh --mode start --site-name jingrow + ``` + +#### 2. 权限错误 + +**解决方案:** ```bash -./install_jsite.sh --mode list +# 确保脚本有执行权限 +chmod +x jsite.sh + +# 以root用户运行 +sudo ./jsite.sh --mode start --site-name jingrow ``` -#### 6. 查看日志 +#### 3. 端口冲突 +**解决方案:** ```bash -./install_jsite.sh --mode logs --site-name myproject +# 检查端口占用 +netstat -tlnp | grep :3001 + +# 停止占用端口的进程 +sudo kill -9 <进程ID> ``` -## 工作流程 +### 手动检查和修复 -### 完整部署流程 (deploy) -1. 创建jingrow用户 -2. 安装Docker(可选跳过) -3. 安装Node.js和NVM -4. 克隆项目代码 -5. 创建环境配置文件 -6. 安装项目依赖 -7. 安装PM2并启动项目 -8. 安装Traefik并配置反向代理 +#### 检查PM2状态 +```bash +# 切换到jingrow用户 +su - jingrow -### 网站管理流程 -- **create**: 克隆代码 → 分配端口 → 创建配置 → 提示下一步 -- **build**: 安装依赖 → 构建项目 -- **start**: 检查状态 → 分配端口 → 启动PM2进程 -- **stop**: 停止PM2进程 -- **restart**: 重启PM2进程或启动(如果未运行) -- **delete**: 停止进程 → 清理配置 → 删除文件 +# 加载nvm环境 +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" -## 目录结构 +# 查看PM2进程列表 +pm2 list + +# 查看PM2日志 +pm2 logs +``` + +#### 手动启动PM2进程 +```bash +# 切换到jingrow用户 +su - jingrow + +# 加载nvm环境 +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" + +# 启动进程 +pm2 start jingrow + +# 或者重新加载配置 +pm2 reload jingrow +``` + +## 配置说明 + +### 环境变量 + +脚本支持以下环境变量配置: + +- `SITE_NAME`: 网站名称(默认:jingrow) +- `GIT_REPO`: Git仓库地址 +- `NODE_VERSION`: Node.js版本(默认:22) +- `START_PORT`: 起始端口(默认:3001) +- `SITE_URL`: 网站域名 +- `BACKEND_SERVER_URL`: 后端服务器地址 + +### 目录结构 ``` /home/jingrow/ ├── jsite/ # 网站项目目录 -│ ├── myproject1/ # 项目1 -│ ├── myproject2/ # 项目2 -│ └── site_port.json # 端口分配记录 -├── traefik-docker/ # Traefik配置目录 -│ └── conf.d/website/ # 网站配置文件 -└── .nvm/ # Node.js版本管理 +├── .nvm/ # Node版本管理器 +├── traefik-docker/ # Traefik配置 +└── ... ``` ## 注意事项 -1. **权限要求**:脚本需要root权限运行 -2. **端口管理**:自动分配端口,避免冲突 -3. **环境依赖**:确保系统支持Docker和Node.js -4. **域名配置**:需要正确配置DNS解析 -5. **SSL证书**:Traefik自动申请Let's Encrypt证书 - -## 故障排除 - -### 常见问题 - -1. **端口被占用** - - 检查端口分配文件:`/home/jingrow/jsite/site_port.json` - - 手动修改端口或停止占用进程 - -2. **PM2启动失败** - - 检查项目依赖是否正确安装 - - 查看PM2日志:`pm2 logs <项目名>` - - 确认package.json中有start脚本 - -3. **Traefik配置问题** - - 检查配置文件:`/home/jingrow/traefik-docker/conf.d/website/` - - 重启Traefik服务 - -4. **域名访问问题** - - 确认DNS解析正确 - - 检查防火墙设置 - - 验证SSL证书状态 - -### 日志查看 - -```bash -# PM2日志 -pm2 logs <项目名> - -# Traefik日志 -docker logs - -# 系统日志 -journalctl -u docker -``` +1. 脚本需要以root权限运行 +2. 确保服务器有足够的磁盘空间和内存 +3. 确保网络连接正常,能够访问Git仓库 +4. 建议在生产环境使用前先在测试环境验证 ## 更新日志 -- **v2.0**: 整合jsite.sh功能,支持多种任务模式 -- **v1.0**: 基础部署功能 +### v1.1.0 +- 修复了start_site和restart_site函数的无限递归问题 +- 改进了错误处理和日志输出 +- 优化了PM2进程管理逻辑 -## 许可证 +## 技术支持 -MIT License +如果遇到问题,请检查: +1. 脚本执行日志 +2. PM2进程状态 +3. 系统资源使用情况 +4. 网络连接状态 diff --git a/jsite.sh b/jsite.sh index 5227e30..250fa0a 100644 --- a/jsite.sh +++ b/jsite.sh @@ -40,11 +40,11 @@ FORCE_UPDATE=false PUBLIC_IP="" # 公网IP地址 (用于内网IP不可用时) # .env文件参数 -SITE_URL="starrbud.com" -REVALIDATE_TOKEN="535bc122f3e364c" -BACKEND_SERVER_URL="https://admin.jingrow.com" -BACKEND_API_KEY="535bc122f3e364c" -BACKEND_API_SECRET="8629a3b12fc1cc2" +SITE_URL="example.com" +REVALIDATE_TOKEN="" +BACKEND_SERVER_URL="https://admin.example.com" +BACKEND_API_KEY="" +BACKEND_API_SECRET="" # ======================================== # 工具函数 @@ -187,6 +187,7 @@ while [[ $# -gt 0 ]]; do echo "任务模式 (--mode):" echo " deploy 完整部署模式 (默认)" echo " create 创建新网站" + echo " create_and_start 创建并启动网站(包含构建和启动)" echo " delete 删除网站" echo " build 构建网站" echo " start 启动网站" @@ -227,6 +228,8 @@ while [[ $# -gt 0 ]]; do echo " $0 --mode deploy --site-name myproject --public-ip 8.217.167.199" echo " # 创建网站" echo " $0 --mode create --site-name myproject --git-repo http://git.example.com/project" + echo " # 创建并启动网站" + echo " $0 --mode create_and_start --site-name myproject --git-repo http://git.example.com/project" echo " # 管理网站" echo " $0 --mode start --site-name myproject" echo " $0 --mode stop --site-name myproject" @@ -1479,6 +1482,9 @@ create_site() { # 创建.env文件 create_env_file + # 创建PM2配置文件 + create_pm2_config + # 创建traefik配置文件 if create_traefik_website_config "$SITE_NAME" "$SITE_URL" "$port"; then restart_traefik @@ -1495,6 +1501,111 @@ create_site() { echo " 2. 启动项目: $0 --mode start --site-name $SITE_NAME" } +# 创建并启动网站(包含构建和启动) +create_and_start_site() { + log_info "开始创建并启动网站: $SITE_NAME" + log_info "Git仓库: $GIT_REPO" + log_info "域名: $SITE_URL" + + # 检查网站是否已存在 + if check_site_exists "$SITE_NAME"; then + log_error "网站 $SITE_NAME 已存在" + return 1 + fi + + # 获取并分配端口 + local port=$(get_or_assign_port "$SITE_NAME") + + # 克隆项目 + log_info "克隆项目: $GIT_REPO" + if ! su - jingrow -c "cd '$JSITE_BASE_DIR' && git clone '$GIT_REPO' '$SITE_NAME'"; then + log_error "项目克隆失败" + return 1 + fi + + # 检查package.json是否存在 + if [ ! -f "$JSITE_BASE_DIR/$SITE_NAME/package.json" ]; then + log_error "package.json文件不存在,这可能不是一个有效的Node.js项目" + rm -rf "$JSITE_BASE_DIR/$SITE_NAME" + return 1 + fi + + # 保存端口分配 + save_port_assignment "$SITE_NAME" "$port" + + # 创建.env文件 + create_env_file + + # 创建PM2配置文件 + create_pm2_config + + # 创建traefik配置文件 + if create_traefik_website_config "$SITE_NAME" "$SITE_URL" "$port"; then + restart_traefik + fi + + # 安装项目依赖 + log_info "安装项目依赖..." + if ! su - jingrow -c " + export NVM_DIR=\"\$HOME/.nvm\" + [ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\" + cd '$JSITE_BASE_DIR/$SITE_NAME' + npm install + "; then + log_error "依赖安装失败" + return 1 + fi + + # 构建项目 + log_info "构建项目..." + if ! su - jingrow -c " + export NVM_DIR=\"\$HOME/.nvm\" + [ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\" + cd '$JSITE_BASE_DIR/$SITE_NAME' + npm run build + "; then + log_error "项目构建失败" + return 1 + fi + + # 启动项目 + log_info "启动项目..." + if ! start_project_with_pm2; then + log_error "项目启动失败" + return 1 + fi + + log_success "网站 $SITE_NAME 创建、构建和启动成功" + log_info "项目路径: $JSITE_BASE_DIR/$SITE_NAME" + log_info "分配端口: $port" + log_info "绑定域名: $SITE_URL" + + # 显示部署信息 + log_info "部署信息:" + echo " - 用户: jingrow" + echo " - jsite目录: $JSITE_BASE_DIR" + echo " - 项目目录: $JSITE_BASE_DIR/$SITE_NAME" + echo " - 项目端口: $port" + echo " - Traefik目录: /home/jingrow/traefik-docker" + echo " - Traefik管理界面: http://localhost:8080" + echo " - Traefik网站配置: $TRAEFIK_CONFIG_DIR/$SITE_NAME.yml" + echo " - PM2配置文件: $JSITE_BASE_DIR/$SITE_NAME/ecosystem.config.cjs" + echo " - PM2日志目录: $JSITE_BASE_DIR/$SITE_NAME/logs" + + log_info "PM2管理命令:" + echo " - 查看状态: su - jingrow -c 'export NVM_DIR=\"\$HOME/.nvm\" && [ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\" && pm2 list'" + echo " - 查看日志: su - jingrow -c 'export NVM_DIR=\"\$HOME/.nvm\" && [ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\" && pm2 logs $SITE_NAME'" + echo " - 重启项目: su - jingrow -c 'export NVM_DIR=\"\$HOME/.nvm\" && [ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\" && pm2 restart $SITE_NAME'" + echo " - 停止项目: su - jingrow -c 'export NVM_DIR=\"\$HOME/.nvm\" && [ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\" && pm2 stop $SITE_NAME'" + echo " - 删除项目: su - jingrow -c 'export NVM_DIR=\"\$HOME/.nvm\" && [ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\" && pm2 delete $SITE_NAME'" + + log_info "访问信息:" + echo " - 网站域名: $SITE_URL" + echo " - 本地访问: http://localhost:$port" + + log_success "网站创建、构建和启动完成!" +} + # 删除网站 delete_site() { log_info "开始删除网站: $SITE_NAME" @@ -1846,6 +1957,11 @@ main() { create_site ;; + "create_and_start") + # 创建并启动网站(包含构建和启动) + create_and_start_site + ;; + "delete") # 删除网站 delete_site @@ -1888,7 +2004,7 @@ main() { *) log_error "不支持的mode: $MODE" - echo "支持的mode: deploy, create, delete, build, start, stop, restart, status, list, logs" + echo "支持的mode: deploy, create, create_and_start, delete, build, start, stop, restart, status, list, logs" exit 1 ;; esac diff --git a/test_status.sh b/test_status.sh new file mode 100644 index 0000000..da0d264 --- /dev/null +++ b/test_status.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +# 测试修复后的状态检测功能 +echo "=== 测试修复后的状态检测功能 ===" + +# 测试get_site_status函数 +test_get_site_status() { + echo "测试 get_site_status 函数..." + + # 模拟PM2 list输出 + echo "模拟PM2 list输出:" + echo "┌─────┬────────────────┬──────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐" + echo "│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │" + echo "├─────┼────────────────┼──────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤" + echo "│ 0 │ jingrow │ default │ 1.0.0 │ fork │ 12345 │ 2D │ 0 │ online │ 0% │ 45.0mb │ jingrow │ disabled │" + echo "│ 1 │ testapp │ default │ 1.0.0 │ fork │ 12346 │ 0s │ 0 │ stopped │ 0% │ 0b │ jingrow │ disabled │" + echo "│ 2 │ erroredapp │ default │ 1.0.0 │ fork │ 0 │ 0s │ 5 │ errored │ 0% │ 0b │ jingrow │ disabled │" + echo "└─────┴────────────────┴──────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘" + + echo "" + echo "状态解析说明:" + echo "- jingrow: 状态为 'online' -> 应该返回 'running'" + echo "- testapp: 状态为 'stopped' -> 应该返回 'stopped'" + echo "- erroredapp: 状态为 'errored' -> 应该返回 'error'" +} + +# 测试端口检测 +test_port_detection() { + echo "" + echo "=== 测试端口检测功能 ===" + + # 检查常用端口 + local ports=(3001 3002 8080 80 443) + + for port in "${ports[@]}"; do + echo "检查端口 $port:" + if netstat -tlnp 2>/dev/null | grep -q ":$port "; then + echo " ✓ 端口 $port 正在监听 (netstat)" + elif ss -tlnp 2>/dev/null | grep -q ":$port "; then + echo " ✓ 端口 $port 正在监听 (ss)" + else + echo " ✗ 端口 $port 未被监听" + fi + done +} + +# 测试PM2命令可用性 +test_pm2_availability() { + echo "" + echo "=== 测试PM2命令可用性 ===" + + # 检查jingrow用户的PM2 + echo "检查jingrow用户的PM2:" + if su - jingrow -c "command -v pm2" 2>/dev/null; then + echo " ✓ PM2命令可用" + + # 检查PM2版本 + local pm2_version=$(su - jingrow -c "pm2 -v" 2>/dev/null) + if [ -n "$pm2_version" ]; then + echo " ✓ PM2版本: $pm2_version" + else + echo " ✗ 无法获取PM2版本" + fi + + # 检查PM2进程列表 + echo " PM2进程列表:" + su - jingrow -c "pm2 list" 2>/dev/null || echo " ✗ 无法获取PM2进程列表" + else + echo " ✗ PM2命令不可用" + fi +} + +# 运行测试 +test_get_site_status +test_port_detection +test_pm2_availability + +echo "" +echo "=== 测试完成 ===" +echo "现在可以运行修复后的脚本:" +echo " /tmp/jsite.sh --mode status --site-name jingrow" \ No newline at end of file