From 85e96ca585a4bb9564bc8c4cc43144aec4d9d4ec Mon Sep 17 00:00:00 2001 From: jingrow Date: Fri, 8 Aug 2025 02:36:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=BC=A0=E5=85=A5=E7=AB=AF?= =?UTF-8?q?=E5=8F=A3=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install_jsite.sh | 238 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 182 insertions(+), 56 deletions(-) diff --git a/install_jsite.sh b/install_jsite.sh index 6bdf5bf..3672b0b 100755 --- a/install_jsite.sh +++ b/install_jsite.sh @@ -175,11 +175,11 @@ log_success() { } log_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" + echo -e "${YELLOW}[WARNING]${NC} $1" >&2 } log_error() { - echo -e "${RED}[ERROR]${NC} $1" + echo -e "${RED}[ERROR]${NC} $1" >&2 } # 检查是否为root用户 @@ -280,51 +280,101 @@ get_available_port() { local base_port="$START_PORT" local increment="$PORT_INCREMENT" - # 检查jq是否可用 - if ! command -v jq &> /dev/null; then - log_warning "jq命令不可用,使用默认端口 $base_port" - echo "$base_port" - return 0 + # 端口分配文件路径 + local port_file="/home/jingrow/jsite/site_port.json" + + # 确保jsite目录存在 + if [ ! -d "/home/jingrow/jsite" ]; then + mkdir -p /home/jingrow/jsite + chown jingrow:jingrow /home/jingrow/jsite fi # 检查项目是否已有分配的端口 - local port_file="/home/jingrow/jsite/port_assignments.json" - if [ -f "$port_file" ]; 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 - echo "$existing_port" - return 0 - fi - fi - - # 查找可用端口 - local port="$base_port" - local max_attempts=1000 - local attempts=0 - - while [ $attempts -lt $max_attempts ]; do - # 检查端口是否被占用 - if ! netstat -tuln 2>/dev/null | grep -q ":$port "; then - # 检查端口是否已被分配 - if [ -f "$port_file" ]; then - local used_ports=$(jq -r '.[]' "$port_file" 2>/dev/null || echo "") - if ! echo "$used_ports" | grep -q "^$port$"; then - echo "$port" - return 0 - fi - else - echo "$port" + # 使用jq查询已分配的端口 + 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 + echo "$existing_port" + return 0 + fi + else + # 如果没有jq,使用grep和cut来解析JSON + local existing_port=$(grep -o "\"$site_name\"[[:space:]]*:[[:space:]]*[0-9]*" "$port_file" 2>/dev/null | cut -d: -f2 | tr -d ' ' || echo "") + if [ -n "$existing_port" ]; then + echo "$existing_port" return 0 fi fi - port=$((port + increment)) - attempts=$((attempts + 1)) - done + fi - log_error "无法找到可用端口,已尝试 $max_attempts 次" - return 1 + # 如果没有分配的端口,检查是否使用用户指定的起始端口 + local next_port="$base_port" + + # 检查用户是否传入了自定义起始端口(通过比较START_PORT是否等于默认值3001) + local user_specified_port=false + if [ "$base_port" != "3001" ]; then + user_specified_port=true + fi + + 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 + fi + else + local used_ports=$(grep -o ":[[:space:]]*[0-9]*" "$port_file" 2>/dev/null | cut -d: -f2 | tr -d ' ' || echo "") + if echo "$used_ports" | grep -q "^$base_port$"; then + port_available=false + fi + fi + fi + + if [ "$port_available" = true ]; then + # 用户指定的端口可用,直接使用 + next_port="$base_port" + else + # 用户指定的端口已被使用,使用最大端口号 + 1 + if [ -f "$port_file" ]; then + 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 + next_port=$((max_port + increment)) + fi + else + local max_port=$(grep -o ":[[:space:]]*[0-9]*" "$port_file" 2>/dev/null | cut -d: -f2 | tr -d ' ' | sort -n | tail -1 || echo "$base_port") + if [ -n "$max_port" ]; then + next_port=$((max_port + increment)) + fi + fi + fi + fi + else + # 用户没有传入自定义端口,使用自动分配逻辑 + if [ -f "$port_file" ]; then + if command -v jq &> /dev/null; then + # 使用jq找到最大端口号 + local max_port=$(jq -r 'max(.[])' "$port_file" 2>/dev/null || echo "$base_port") + if [ -n "$max_port" ] && [ "$max_port" != "null" ]; then + next_port=$((max_port + increment)) + fi + else + # 使用grep和sort找到最大端口号 + local max_port=$(grep -o ":[[:space:]]*[0-9]*" "$port_file" 2>/dev/null | cut -d: -f2 | tr -d ' ' | sort -n | tail -1 || echo "$base_port") + if [ -n "$max_port" ]; then + next_port=$((max_port + increment)) + fi + fi + fi + fi + + echo "$next_port" + return 0 } # 2.7. 保存端口分配 @@ -332,21 +382,36 @@ save_port_assignment() { local site_name="$1" local port="$2" - local port_file="/home/jingrow/jsite/port_assignments.json" + local port_file="/home/jingrow/jsite/site_port.json" - # 检查jq是否可用 - if ! command -v jq &> /dev/null; then - log_warning "jq命令不可用,跳过端口分配保存" - return 0 + # 确保jsite目录存在 + if [ ! -d "/home/jingrow/jsite" ]; then + mkdir -p /home/jingrow/jsite + chown jingrow:jingrow /home/jingrow/jsite fi - # 创建或更新端口分配文件 - if [ -f "$port_file" ]; then - # 更新现有文件 - jq ". + {\"$site_name\": $port}" "$port_file" > "${port_file}.tmp" && mv "${port_file}.tmp" "$port_file" + # 检查jq是否可用 + if command -v jq &> /dev/null; then + # 使用jq保存到JSON文件 + if [ -f "$port_file" ]; then + # 更新现有文件 + jq ". + {\"$site_name\": $port}" "$port_file" > "${port_file}.tmp" && mv "${port_file}.tmp" "$port_file" + else + # 创建新文件 + echo "{\"$site_name\": $port}" > "$port_file" + fi else - # 创建新文件 - echo "{\"$site_name\": $port}" > "$port_file" + # 如果没有jq,使用简单的文本处理 + if [ -f "$port_file" ]; then + # 移除已存在的条目(如果存在) + grep -v "\"$site_name\"" "$port_file" > "${port_file}.tmp" 2>/dev/null || true + mv "${port_file}.tmp" "$port_file" + # 在最后一个大括号前添加新条目 + sed -i "s/}$/ \"$site_name\": $port\n}/" "$port_file" 2>/dev/null || echo "{\"$site_name\": $port}" > "$port_file" + else + # 创建新文件 + echo "{\"$site_name\": $port}" > "$port_file" + fi fi # 设置文件权限 @@ -356,6 +421,64 @@ save_port_assignment() { log_success "端口 $port 已分配给项目 $site_name" } +# 2.8. 获取或分配端口(确保一致性) +get_or_assign_port() { + local site_name="$1" + + # 获取或分配端口 + local port=$(get_available_port "$site_name") + + if [ -n "$port" ]; then + # 检查是否已经保存过这个端口分配 + local port_file="/home/jingrow/jsite/site_port.json" + local already_saved=false + + if [ -f "$port_file" ]; then + 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 + already_saved=true + fi + else + local existing_port=$(grep -o "\"$site_name\"[[:space:]]*:[[:space:]]*[0-9]*" "$port_file" 2>/dev/null | cut -d: -f2 | tr -d ' ' || echo "") + if [ -n "$existing_port" ]; then + already_saved=true + fi + fi + fi + + # 如果没有保存过,则保存端口分配 + if [ "$already_saved" = false ]; then + save_port_assignment "$site_name" "$port" + fi + + echo "$port" + return 0 + else + log_error "无法为项目 $site_name 分配端口" + return 1 + fi +} + +# 2.9. 显示端口分配情况 +show_port_assignments() { + local port_file="/home/jingrow/jsite/site_port.json" + + if [ ! -f "$port_file" ]; then + log_info "暂无端口分配记录" + return 0 + fi + + log_info "当前端口分配情况:" + if command -v jq &> /dev/null; then + # 使用jq格式化输出 + jq -r 'to_entries[] | " - \(.key): \(.value)"' "$port_file" 2>/dev/null || log_warning "无法解析端口分配文件" + else + # 使用grep和sed格式化输出 + grep -o '"[^"]*"[[:space:]]*:[[:space:]]*[0-9]*' "$port_file" 2>/dev/null | sed 's/"//g' | sed 's/[[:space:]]*:[[:space:]]*/: /' | sed 's/^/ - /' || log_warning "无法解析端口分配文件" + fi +} + # 3. 克隆jsite项目 clone_jsite_project() { log_info "开始克隆jsite项目: $SITE_NAME..." @@ -417,8 +540,7 @@ create_env_file() { cd /home/jingrow/jsite/$SITE_NAME # 获取项目端口 - local project_port=$(get_available_port "$SITE_NAME") - save_port_assignment "$SITE_NAME" "$project_port" + local project_port=$(get_or_assign_port "$SITE_NAME") # 更新SITE_URL以使用分配的端口 local site_url_with_port=$(echo "$SITE_URL" | sed "s|:[0-9]*|:$project_port|") @@ -463,7 +585,7 @@ create_pm2_config() { cd /home/jingrow/jsite/$SITE_NAME # 获取项目端口 - local project_port=$(get_available_port "$SITE_NAME") + local project_port=$(get_or_assign_port "$SITE_NAME") # 创建logs目录 mkdir -p "/home/jingrow/jsite/$SITE_NAME/logs" @@ -748,7 +870,7 @@ create_traefik_website_config() { log_info "创建traefik网站配置文件..." # 获取项目端口 - local project_port=$(get_available_port "$SITE_NAME") + local project_port=$(get_or_assign_port "$SITE_NAME") # 生成Host规则 local host_rule=$(generate_host_rule "$SITE_URL") @@ -860,7 +982,7 @@ show_deployment_info() { echo " - 用户: jingrow" echo " - jsite目录: /home/jingrow/jsite" echo " - 项目目录: /home/jingrow/jsite/$SITE_NAME" - echo " - 项目端口: $(get_available_port "$SITE_NAME")" + echo " - 项目端口: $(get_or_assign_port "$SITE_NAME")" echo " - Traefik目录: /home/jingrow/traefik-docker" echo " - Traefik管理界面: http://localhost:8080" echo " - Traefik网站配置: /home/jingrow/traefik-docker/conf.d/website/$SITE_NAME.yml" @@ -886,7 +1008,10 @@ show_deployment_info() { log_info "Traefik配置信息:" echo " - 网站配置文件: /home/jingrow/traefik-docker/conf.d/website/$SITE_NAME.yml" echo " - 访问域名: $(generate_host_rule "$SITE_URL" | sed 's/Host(`//g' | sed 's/`)//g' | sed 's/ || / 或 /g')" - echo " - 后端端口: $(get_available_port "$SITE_NAME")" + echo " - 后端端口: $(get_or_assign_port "$SITE_NAME")" + echo "" + # 显示端口分配情况 + show_port_assignments echo "" log_info "下一步操作:" echo " 1. 进入项目目录: cd /home/jingrow/jsite/$SITE_NAME" @@ -895,6 +1020,7 @@ show_deployment_info() { echo " 4. 访问Traefik管理界面: http://localhost:8080" echo " 5. 访问项目: $SITE_URL" echo " 6. 检查traefik配置: cat /home/jingrow/traefik-docker/conf.d/website/$SITE_NAME.yml" + echo " 7. 查看端口分配: cat /home/jingrow/jsite/site_port.json" echo "" log_warning "注意:请确保防火墙允许80、443、8080端口访问" }