增加create_and_start模式

This commit is contained in:
jingrow 2025-08-11 01:10:10 +08:00
parent baf702291c
commit 9e1813daca
3 changed files with 335 additions and 141 deletions

267
README.md
View File

@ -1,29 +1,31 @@
# jsite 自动化部署和管理脚本 # jsite.sh - 前端自动化部署脚本
这是一个集成了完整部署和日常管理功能的自动化脚本,支持多种任务模式。 ## 概述
## 功能特性 `jsite.sh` 是一个用于自动化部署和管理前端网站的bash脚本。它支持多种操作模式包括部署、启动、停止、重启等。
- 🚀 **完整部署**一键部署完整的jsite环境 ## 主要功能
- 🏗️ **网站管理**:创建、删除、构建、启动、停止、重启网站
- 📊 **状态监控**:查看网站运行状态和日志 - 自动创建和管理jingrow用户
- 🔧 **环境管理**Docker、Node.js、PM2、Traefik等环境组件 - 安装和配置Node.js、npm、PM2
- ⚡ **智能端口分配**:自动分配和管理端口资源 - 自动化部署前端项目
- 集成Traefik反向代理
- 支持多种操作模式
## 使用方法 ## 使用方法
### 基本语法 ### 基本语法
```bash ```bash
./install_jsite.sh --mode <任务模式> [其他参数] ./jsite.sh --mode <模式> --site-name <网站名称>
``` ```
### 支持的任务模式 ### 支持的模式
| 模式 | 功能 | 示例 | | 模式 | 描述 | 示例 |
|------|------|------| |------|------|------|
| `deploy` | 完整部署模式(默认) | `--mode deploy --site-name myproject` | | `deploy` | 完整部署网站 | `--mode deploy --site-name myproject` |
| `create` | 创建新网站 | `--mode create --site-name myproject --git-repo <仓库地址>` | | `create` | 创建新网站 | `--mode create --site-name myproject` |
| `delete` | 删除网站 | `--mode delete --site-name myproject` | | `delete` | 删除网站 | `--mode delete --site-name myproject` |
| `build` | 构建网站 | `--mode build --site-name myproject` | | `build` | 构建网站 | `--mode build --site-name myproject` |
| `start` | 启动网站 | `--mode start --site-name myproject` | | `start` | 启动网站 | `--mode start --site-name myproject` |
@ -33,157 +35,152 @@
| `list` | 列出所有网站 | `--mode list` | | `list` | 列出所有网站 | `--mode list` |
| `logs` | 查看网站日志 | `--mode logs --site-name myproject` | | `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 ```bash
./install_jsite.sh \ # 部署新网站
--mode deploy \ ./jsite.sh --mode deploy --site-name jingrow
--site-name myproject \
--git-repo http://git.example.com/myproject \
--site-url myproject.com \
--public-ip 8.217.167.199
```
#### 2. 创建新网站 # 启动网站
./jsite.sh --mode start --site-name jingrow
```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
# 重启网站 # 重启网站
./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 ```bash
./install_jsite.sh --mode list # 确保脚本有执行权限
chmod +x jsite.sh
# 以root用户运行
sudo ./jsite.sh --mode start --site-name jingrow
``` ```
#### 6. 查看日志 #### 3. 端口冲突
**解决方案:**
```bash ```bash
./install_jsite.sh --mode logs --site-name myproject # 检查端口占用
netstat -tlnp | grep :3001
# 停止占用端口的进程
sudo kill -9 <进程ID>
``` ```
## 工作流程 ### 手动检查和修复
### 完整部署流程 (deploy) #### 检查PM2状态
1. 创建jingrow用户 ```bash
2. 安装Docker可选跳过 # 切换到jingrow用户
3. 安装Node.js和NVM su - jingrow
4. 克隆项目代码
5. 创建环境配置文件
6. 安装项目依赖
7. 安装PM2并启动项目
8. 安装Traefik并配置反向代理
### 网站管理流程 # 加载nvm环境
- **create**: 克隆代码 → 分配端口 → 创建配置 → 提示下一步 export NVM_DIR="$HOME/.nvm"
- **build**: 安装依赖 → 构建项目 [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
- **start**: 检查状态 → 分配端口 → 启动PM2进程
- **stop**: 停止PM2进程
- **restart**: 重启PM2进程或启动如果未运行
- **delete**: 停止进程 → 清理配置 → 删除文件
## 目录结构 # 查看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/ /home/jingrow/
├── jsite/ # 网站项目目录 ├── jsite/ # 网站项目目录
│ ├── myproject1/ # 项目1 ├── .nvm/ # Node版本管理器
│ ├── myproject2/ # 项目2 ├── traefik-docker/ # Traefik配置
│ └── site_port.json # 端口分配记录 └── ...
├── traefik-docker/ # Traefik配置目录
│ └── conf.d/website/ # 网站配置文件
└── .nvm/ # Node.js版本管理
``` ```
## 注意事项 ## 注意事项
1. **权限要求**脚本需要root权限运行 1. 脚本需要以root权限运行
2. **端口管理**:自动分配端口,避免冲突 2. 确保服务器有足够的磁盘空间和内存
3. **环境依赖**确保系统支持Docker和Node.js 3. 确保网络连接正常能够访问Git仓库
4. **域名配置**需要正确配置DNS解析 4. 建议在生产环境使用前先在测试环境验证
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 <traefik容器名>
# 系统日志
journalctl -u docker
```
## 更新日志 ## 更新日志
- **v2.0**: 整合jsite.sh功能支持多种任务模式 ### v1.1.0
- **v1.0**: 基础部署功能 - 修复了start_site和restart_site函数的无限递归问题
- 改进了错误处理和日志输出
- 优化了PM2进程管理逻辑
## 许可证 ## 技术支持
MIT License 如果遇到问题,请检查:
1. 脚本执行日志
2. PM2进程状态
3. 系统资源使用情况
4. 网络连接状态

128
jsite.sh
View File

@ -40,11 +40,11 @@ FORCE_UPDATE=false
PUBLIC_IP="" # 公网IP地址 (用于内网IP不可用时) PUBLIC_IP="" # 公网IP地址 (用于内网IP不可用时)
# .env文件参数 # .env文件参数
SITE_URL="starrbud.com" SITE_URL="example.com"
REVALIDATE_TOKEN="535bc122f3e364c" REVALIDATE_TOKEN=""
BACKEND_SERVER_URL="https://admin.jingrow.com" BACKEND_SERVER_URL="https://admin.example.com"
BACKEND_API_KEY="535bc122f3e364c" BACKEND_API_KEY=""
BACKEND_API_SECRET="8629a3b12fc1cc2" BACKEND_API_SECRET=""
# ======================================== # ========================================
# 工具函数 # 工具函数
@ -187,6 +187,7 @@ while [[ $# -gt 0 ]]; do
echo "任务模式 (--mode):" echo "任务模式 (--mode):"
echo " deploy 完整部署模式 (默认)" echo " deploy 完整部署模式 (默认)"
echo " create 创建新网站" echo " create 创建新网站"
echo " create_and_start 创建并启动网站(包含构建和启动)"
echo " delete 删除网站" echo " delete 删除网站"
echo " build 构建网站" echo " build 构建网站"
echo " start 启动网站" echo " start 启动网站"
@ -227,6 +228,8 @@ while [[ $# -gt 0 ]]; do
echo " $0 --mode deploy --site-name myproject --public-ip 8.217.167.199" echo " $0 --mode deploy --site-name myproject --public-ip 8.217.167.199"
echo " # 创建网站" echo " # 创建网站"
echo " $0 --mode create --site-name myproject --git-repo http://git.example.com/project" 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 " # 管理网站"
echo " $0 --mode start --site-name myproject" echo " $0 --mode start --site-name myproject"
echo " $0 --mode stop --site-name myproject" echo " $0 --mode stop --site-name myproject"
@ -1479,6 +1482,9 @@ create_site() {
# 创建.env文件 # 创建.env文件
create_env_file create_env_file
# 创建PM2配置文件
create_pm2_config
# 创建traefik配置文件 # 创建traefik配置文件
if create_traefik_website_config "$SITE_NAME" "$SITE_URL" "$port"; then if create_traefik_website_config "$SITE_NAME" "$SITE_URL" "$port"; then
restart_traefik restart_traefik
@ -1495,6 +1501,111 @@ create_site() {
echo " 2. 启动项目: $0 --mode start --site-name $SITE_NAME" 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() { delete_site() {
log_info "开始删除网站: $SITE_NAME" log_info "开始删除网站: $SITE_NAME"
@ -1846,6 +1957,11 @@ main() {
create_site create_site
;; ;;
"create_and_start")
# 创建并启动网站(包含构建和启动)
create_and_start_site
;;
"delete") "delete")
# 删除网站 # 删除网站
delete_site delete_site
@ -1888,7 +2004,7 @@ main() {
*) *)
log_error "不支持的mode: $MODE" 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 exit 1
;; ;;
esac esac

81
test_status.sh Normal file
View File

@ -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"