From 85799af6df53deb0a817d0cb55e30422bcb16064 Mon Sep 17 00:00:00 2001 From: jingrow Date: Mon, 11 Aug 2025 01:10:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 267 +++++++++++++++++++++++++++--------------------------- jsite.sh | 115 ++++++++--------------- 2 files changed, 171 insertions(+), 211 deletions(-) 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..814a2fc 100644 --- a/jsite.sh +++ b/jsite.sh @@ -436,9 +436,6 @@ get_available_port() { # 检查项目是否已有分配的端口 if [ -f "$port_file" ]; then - # 确保jq工具已安装 - ensure_jq_installed - # 使用jq查询已分配的端口 if command -v jq &> /dev/null; then local existing_port=$(jq -r ".$site_name // empty" "$port_file" 2>/dev/null || echo "") @@ -465,15 +462,12 @@ get_available_port() { user_specified_port=true fi - if [ "$user_specified_port" = true ]; then - # 用户传入了自定义端口,优先使用用户指定的端口 - # 检查用户指定的端口是否已被使用 - local port_available=true - if [ -f "$port_file" ]; then - # 确保jq工具已安装 - ensure_jq_installed - - if command -v jq &> /dev/null; then + if [ "$user_specified_port" = true ]; then + # 用户传入了自定义端口,优先使用用户指定的端口 + # 检查用户指定的端口是否已被使用 + local port_available=true + if [ -f "$port_file" ]; then + if command -v jq &> /dev/null; then local used_ports=$(jq -r '.[]' "$port_file" 2>/dev/null || echo "") if echo "$used_ports" | grep -q "^$base_port$"; then port_available=false @@ -492,9 +486,6 @@ get_available_port() { else # 用户指定的端口已被使用,使用最大端口号 + 1 if [ -f "$port_file" ]; then - # 确保jq工具已安装 - ensure_jq_installed - if command -v jq &> /dev/null; then local max_port=$(jq -r 'max(.[])' "$port_file" 2>/dev/null || echo "$base_port") if [ -n "$max_port" ] && [ "$max_port" != "null" ]; then @@ -511,9 +502,6 @@ get_available_port() { else # 用户没有传入自定义端口,使用自动分配逻辑 if [ -f "$port_file" ]; then - # 确保jq工具已安装 - ensure_jq_installed - if command -v jq &> /dev/null; then # 使用jq找到最大端口号 local max_port=$(jq -r 'max(.[])' "$port_file" 2>/dev/null || echo "$base_port") @@ -547,9 +535,6 @@ save_port_assignment() { chown jingrow:jingrow /home/jingrow/jsite fi - # 确保jq工具已安装 - ensure_jq_installed - # 检查jq是否可用 if command -v jq &> /dev/null; then # 使用jq保存到JSON文件 @@ -601,9 +586,6 @@ get_or_assign_port() { local already_saved=false if [ -f "$port_file" ]; then - # 确保jq工具已安装 - ensure_jq_installed - if command -v jq &> /dev/null; then local existing_port=$(jq -r ".$site_name // empty" "$port_file" 2>/dev/null || echo "") if [ -n "$existing_port" ] && [ "$existing_port" != "null" ] && [ "$existing_port" != "empty" ]; then @@ -640,9 +622,6 @@ show_port_assignments() { fi log_info "当前端口分配情况:" - # 确保jq工具已安装 - ensure_jq_installed - if command -v jq &> /dev/null; then # 使用jq格式化输出 jq -r 'to_entries[] | " - \(.key): \(.value)"' "$port_file" 2>/dev/null || log_warning "无法解析端口分配文件" @@ -1142,45 +1121,6 @@ install_docker() { log_success "将jingrow用户添加到docker组" } -# 6.1 安装jq工具(如果未安装) -install_jq() { - log_info "检查jq工具安装状态..." - - if command -v jq &> /dev/null; then - log_warning "jq工具已安装" - else - log_info "开始安装jq工具..." - - # 设置非交互式环境 - export DEBIAN_FRONTEND=noninteractive - export DEBCONF_NONINTERACTIVE_SEEN=true - - # 更新包索引 - apt-get update - - # 安装jq工具 - apt-get install -y --force-yes jq - - if command -v jq &> /dev/null; then - log_success "jq工具安装完成" - else - log_error "jq工具安装失败" - return 1 - fi - fi -} - -# 6.2 确保jq工具已安装 -ensure_jq_installed() { - if ! command -v jq &> /dev/null; then - log_warning "jq工具未安装,正在安装..." - if ! install_jq; then - log_error "jq工具安装失败,无法处理JSON文件" - return 1 - fi - fi -} - # 7. 启动traefik start_traefik() { log_info "启动traefik服务..." @@ -1532,9 +1472,6 @@ delete_site() { # 删除端口分配记录 log_info "删除端口分配记录..." local port_file="$JSITE_BASE_DIR/site_port.json" - # 确保jq工具已安装 - ensure_jq_installed - if [ -f "$port_file" ] && command -v jq &> /dev/null; then if jq "del(.$SITE_NAME)" "$port_file" > "${port_file}.tmp" 2>/dev/null; then mv "${port_file}.tmp" "$port_file" @@ -1604,9 +1541,31 @@ build_site() { # 启动网站 start_site() { + local status=$(get_site_status "$SITE_NAME") + + if [ "$status" = "not_exists" ]; then + log_error "网站 $SITE_NAME 不存在,请先部署网站" + return 1 + fi + + if [ "$status" = "running" ]; then + log_warning "网站 $SITE_NAME 已在运行中" + return 0 + fi + log_info "启动网站: $SITE_NAME" - restart_site - return $? + + # 尝试启动PM2进程 + if ! su - "jingrow" -c " + export NVM_DIR=\"\$HOME/.nvm\" + [ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\" + pm2 start '$SITE_NAME' + "; then + log_error "网站启动失败" + return 1 + fi + + log_success "网站 $SITE_NAME 启动成功" } # 停止网站 @@ -1657,8 +1616,15 @@ restart_site() { fi else # 如果未运行,则启动 - start_site - return $? + log_info "网站未运行,正在启动..." + if ! su - "jingrow" -c " + export NVM_DIR=\"\$HOME/.nvm\" + [ -s \"\$NVM_DIR/nvm.sh\" ] && \. \"\$NVM_DIR/nvm.sh\" + pm2 start '$SITE_NAME' + "; then + log_error "网站启动失败" + return 1 + fi fi log_success "网站 $SITE_NAME 重启成功" @@ -1789,9 +1755,6 @@ main() { log_warning "跳过Docker安装" fi - # 安装jq工具(用于处理JSON文件) - install_jq - install_nodejs if ! clone_jsite_project; then