#!/bin/bash # ============================================================ # live.fuhua91.com 一键部署脚本 # # 用法: # ./deploy.sh 拉取 latest 最新镜像并重启 # ./deploy.sh v1.0.0 部署指定版本 # # 建议: 放到 /root/deploy.sh,执行 chmod 700 /root/deploy.sh # 依赖: 服务器已安装 docker,且能访问 harbor.fuhua91.com # ============================================================ set -euo pipefail # ---------- 可按需调整的参数 ---------- REGISTRY="harbor.fuhua91.com" PROJECT="live" # Harbor 机器人账号(密码只通过 HARBOR_PASSWORD 环境变量提供) HARBOR_USER_DEFAULT='robot$live+live' BASE_DIR="/www/wwwroot/live.fuhua91.com" CONFIG_DIR="$BASE_DIR/config" # 后端配置目录 -> 容器内 /data/conf LOG_DIR="$BASE_DIR/log" # 后端日志目录 -> 容器内 /app/logs UPLOADS_DIR="$BASE_DIR/uploads" # 上传文件目录 -> 容器内 /app/uploads FRONTEND_PORT=9501 # admin 管理后台 nginx 容器 BACKEND_PORT=9502 # 后端 API/WebSocket 容器 LIVEWEB_PORT=9503 # live 用户端(PC 直播页) nginx 容器 LIVE_UDP_PORT="${KRA_LIVE_UDP_PORT:-9504}" # WebRTC 音视频固定 UDP 端口(与 9501-9503 顺延配套) LIVE_PUBLIC_IP="${KRA_LIVE_PUBLIC_IP:-}" # 留空时从站点域名解析 LIVE_HOST="${KRA_LIVE_HOST:-live.fuhua91.com}" NETWORK="live-net" BACKEND_NAME="live-backend" FRONTEND_NAME="live-frontend" LIVEWEB_NAME="live-web" # -------------------------------------- TAG="${1:-latest}" BACKEND_IMAGE="$REGISTRY/$PROJECT/backend:$TAG" FRONTEND_IMAGE="$REGISTRY/$PROJECT/frontend:$TAG" LIVEWEB_IMAGE="$REGISTRY/$PROJECT/live-web:$TAG" echo "==> 部署版本: $TAG" # 1. 准备挂载目录 mkdir -p "$CONFIG_DIR" "$LOG_DIR" "$UPLOADS_DIR" # 2. 首次运行检查配置文件 if [ ! -f "$CONFIG_DIR/config.yaml" ]; then echo "错误: 缺少 $CONFIG_DIR/config.yaml" echo "请先将项目 configs/config.yaml 复制到该路径," echo "并修改其中的 MySQL / Redis 等连接信息后重新执行本脚本。" exit 1 fi if [ -z "$LIVE_PUBLIC_IP" ]; then LIVE_PUBLIC_IP="$(getent ahostsv4 "$LIVE_HOST" | awk 'NR == 1 { print $1 }')" fi if ! printf '%s' "$LIVE_PUBLIC_IP" | grep -Eq '^[0-9]+(\.[0-9]+){3}$'; then echo "错误: 无法确定直播服务公网 IPv4,请通过 KRA_LIVE_PUBLIC_IP 显式设置" exit 1 fi echo "==> WebRTC 媒体地址: $LIVE_PUBLIC_IP:$LIVE_UDP_PORT/udp" # 3. 登录 Harbor;未传密码时复用服务器现有的 Docker 登录态 HARBOR_USER="${HARBOR_USER:-$HARBOR_USER_DEFAULT}" HARBOR_LOGGED_IN=false if [ -n "${HARBOR_PASSWORD:-}" ]; then echo "==> 登录 $REGISTRY" echo "$HARBOR_PASSWORD" | docker login "$REGISTRY" --username "$HARBOR_USER" --password-stdin >/dev/null HARBOR_LOGGED_IN=true else echo "==> 未提供 HARBOR_PASSWORD,复用服务器现有 Docker 登录态" fi # 4. 拉取最新镜像 echo "==> 拉取镜像" docker pull "$BACKEND_IMAGE" docker pull "$FRONTEND_IMAGE" docker pull "$LIVEWEB_IMAGE" # 5. 重建容器 echo "==> 重启容器" docker network create "$NETWORK" >/dev/null 2>&1 || true docker rm -f "$BACKEND_NAME" "$FRONTEND_NAME" "$LIVEWEB_NAME" 2>/dev/null || true # 容器内进程以 uid 1000 (kra) 运行,日志/上传目录需要写权限 chown -R 1000:1000 "$LOG_DIR" "$UPLOADS_DIR" 2>/dev/null || \ chmod -R 777 "$LOG_DIR" "$UPLOADS_DIR" # 后端: 配置 /data/conf,日志 /app/logs,上传 /app/uploads docker run -d --name "$BACKEND_NAME" \ --restart always \ --network "$NETWORK" \ -p "$BACKEND_PORT:8000" \ -p "$LIVE_UDP_PORT:$LIVE_UDP_PORT/udp" \ -e KRA_LIVE_PUBLIC_IP="$LIVE_PUBLIC_IP" \ -e KRA_LIVE_UDP_PORT="$LIVE_UDP_PORT" \ -v "$CONFIG_DIR:/data/conf" \ -v "$LOG_DIR:/app/logs" \ -v "$UPLOADS_DIR:/app/uploads" \ "$BACKEND_IMAGE" # 前端: nginx 静态站点,容器内已配置 /api -> live-backend:8000 docker run -d --name "$FRONTEND_NAME" \ --restart always \ --network "$NETWORK" \ -p "$FRONTEND_PORT:80" \ "$FRONTEND_IMAGE" # live 用户端(PC 直播页): nginx 静态站点,主域名 / 反代到该容器 docker run -d --name "$LIVEWEB_NAME" \ --restart always \ --network "$NETWORK" \ -p "$LIVEWEB_PORT:80" \ "$LIVEWEB_IMAGE" if [ "$HARBOR_LOGGED_IN" = true ]; then docker logout "$REGISTRY" >/dev/null 2>&1 || true fi echo "==> 部署完成" docker ps --filter "name=$BACKEND_NAME" --filter "name=$FRONTEND_NAME" --filter "name=$LIVEWEB_NAME" echo "" echo "admin 前端容器: http://<服务器IP>:$FRONTEND_PORT" echo "后端容器: http://<服务器IP>:$BACKEND_PORT" echo "live 前端容器: http://<服务器IP>:$LIVEWEB_PORT" echo "提示: 网站正常访问走宝塔 nginx 反代(80/443),9501/9502 为直连调试端口,记得放行防火墙。"