From 0cb6a49aa5c0e407d6ab233b5cf9d3a5ffeb9552 Mon Sep 17 00:00:00 2001 From: Toyas Date: Mon, 3 Aug 2026 20:00:32 +0800 Subject: [PATCH] feat(deploy): Add 1Panel deployment configuration - Add Docker Compose stack for single-server 1Panel deployments - Add backend and frontend Dockerfiles for 1Panel builds - Add Nginx and RocketMQ configuration for container orchestration - Document required environment variables and deployment steps --- DEPLOY_1PANEL.md | 402 +++++++++++++ backend/.env.1panel.example | 41 ++ backend/Dockerfile.service.1panel | 31 + backend/config/rocketmq/broker-1panel.conf | 23 + backend/docker-compose.1panel.yml | 542 ++++++++++++++++++ .../video-frontend-admin/Dockerfile.1panel | 22 + .../deploy/nginx.1panel.conf | 44 ++ frontend/video-frontend-web/Dockerfile.1panel | 22 + .../deploy/nginx.1panel.conf | 44 ++ 9 files changed, 1171 insertions(+) create mode 100644 DEPLOY_1PANEL.md create mode 100644 backend/.env.1panel.example create mode 100644 backend/Dockerfile.service.1panel create mode 100644 backend/config/rocketmq/broker-1panel.conf create mode 100644 backend/docker-compose.1panel.yml create mode 100644 frontend/video-frontend-admin/Dockerfile.1panel create mode 100644 frontend/video-frontend-admin/deploy/nginx.1panel.conf create mode 100644 frontend/video-frontend-web/Dockerfile.1panel create mode 100644 frontend/video-frontend-web/deploy/nginx.1panel.conf diff --git a/DEPLOY_1PANEL.md b/DEPLOY_1PANEL.md new file mode 100644 index 0000000..7255bfa --- /dev/null +++ b/DEPLOY_1PANEL.md @@ -0,0 +1,402 @@ +# HAOVP 1Panel 单机部署指南 + +本文档面向一台服务器上的 1Panel 部署。目标是用 1Panel 的容器编排启动后端、基础设施、前端 Nginx,并用 1Panel 网站/OpenResty 对外提供域名访问。 + +## 1. 部署结构 + +默认编排文件: + +```text +backend/docker-compose.1panel.yml +``` + +配套文件: + +```text +backend/.env.1panel.example +backend/Dockerfile.service.1panel +backend/config/rocketmq/broker-1panel.conf +frontend/video-frontend-web/Dockerfile.1panel +frontend/video-frontend-web/deploy/nginx.1panel.conf +frontend/video-frontend-admin/Dockerfile.1panel +frontend/video-frontend-admin/deploy/nginx.1panel.conf +``` + +默认服务分层: + +| 层级 | 服务 | +| --- | --- | +| 基础设施 | MySQL, Redis, Redis Sentinel, Nacos, RocketMQ, MinIO, Sentinel Dashboard | +| 后端 | video-gateway, video-auth, video-user, video-content, video-comment, video-recommend, video-admin | +| 前端 | frontend-web, frontend-admin | +| 可选监控 | Prometheus, Grafana, exporters,默认不启动 | + +## 2. 服务器要求 + +建议配置: + +| 用途 | 建议 | +| --- | --- | +| CPU | 最低 4 核,建议 8 核 | +| 内存 | 最低 8 GB,建议 16 GB | +| 磁盘 | 最低 80 GB,视频上传环境建议更大 | +| 系统 | Debian 12 / Ubuntu 22.04+ / CentOS Stream 类系统 | + +1Panel 需已安装 Docker 和 OpenResty。首次构建后端镜像会下载 Maven 依赖,耗时较长。 + +## 3. 端口策略 + +1Panel 版默认不直接占用公网 `80/443`,避免和 1Panel OpenResty 冲突。 + +默认端口绑定: + +| 服务 | 宿主机绑定 | 说明 | +| --- | --- | --- | +| 用户前端 | `127.0.0.1:18080` | 给 1Panel 网站反代 | +| 管理前端 | `127.0.0.1:18081` | 给 1Panel 网站反代 | +| API Gateway | `127.0.0.1:9000` | 调试用,不建议公网开放 | +| Nacos | `127.0.0.1:8848` | 控制台,仅本机 | +| MinIO API | `127.0.0.1:9100` | 对象存储 API,仅本机 | +| MinIO Console | `127.0.0.1:9101` | 控制台,仅本机 | +| Sentinel | `127.0.0.1:8880` | 控制台,仅本机 | +| Prometheus | `127.0.0.1:9090` | 可选监控 | +| Grafana | `127.0.0.1:3000` | 可选监控 | + +生产环境防火墙建议只放行: + +```text +80/tcp +443/tcp +1Panel 面板端口 +SSH 端口 +``` + +不要把 MySQL、Redis、Nacos、RocketMQ、MinIO Console 直接暴露到公网。 + +如确需临时从外部访问前端容器端口,可在 `.env.1panel` 中把: + +```env +FRONTEND_BIND_ADDR=127.0.0.1 +``` + +改为: + +```env +FRONTEND_BIND_ADDR=0.0.0.0 +``` + +不建议在生产长期这样配置。 + +## 4. 上传项目 + +在服务器上准备项目目录,例如: + +```bash +cd /opt +git clone <你的仓库地址> HAOVP +cd /opt/HAOVP/backend +``` + +如果通过 1Panel 文件管理上传压缩包,保证目录结构仍然是: + +```text +/opt/HAOVP/backend +/opt/HAOVP/frontend +``` + +因为 `docker-compose.1panel.yml` 会从 `../frontend/...` 构建前端镜像。 + +## 5. 配置环境变量 + +复制示例文件: + +```bash +cd /opt/HAOVP/backend +cp .env.1panel.example .env.1panel +``` + +必须修改这些值: + +```env +MYSQL_ROOT_PASSWORD=强密码 +MYSQL_APP_PASSWORD=强密码 +REDIS_PASSWORD=强密码 +MINIO_SECRET_KEY=强密码 +USER_JWT_SECRET=至少32字节随机字符串 +ADMIN_JWT_SECRET=至少32字节随机字符串 +SERVICE_AUTH_TOKEN=至少32字节随机字符串 +ADMIN_INIT_PASSWORD=后台管理员初始密码 +NACOS_AUTH_TOKEN=至少32字节随机字符串 +GRAFANA_ADMIN_PASSWORD=强密码 +``` + +首次部署建议保持: + +```env +NACOS_USERNAME=nacos +NACOS_PASSWORD=nacos +``` + +原因:Nacos 默认初始化用户是 `nacos/nacos`。如果想改 Nacos 密码,先部署成功,再进入 Nacos 控制台修改用户密码,并同步更新 `.env.1panel` 后重启后端微服务。 + +## 6. 在 1Panel 创建编排 + +进入 1Panel: + +```text +容器 -> 编排 -> 创建编排 +``` + +推荐配置: + +| 项 | 值 | +| --- | --- | +| 名称 | `haovp-1panel` | +| 工作目录 | `/opt/HAOVP/backend` | +| Compose 文件 | `docker-compose.1panel.yml` | +| 环境变量文件 | `.env.1panel` | + +创建后启动编排。 + +首次构建会执行: + +| 镜像 | 构建内容 | +| --- | --- | +| 后端微服务 | Maven 多阶段构建 | +| 用户前端 | Node 构建 Vue/Vite,然后 Nginx 托管 | +| 管理前端 | Node 构建 Vue/Vite,然后 Nginx 托管 | +| Sentinel Dashboard | 下载并打包 Sentinel Dashboard | + +如果服务器网络访问 Maven/npm/Docker Hub 较慢,首次构建可能需要较长时间。 + +## 7. 配置 1Panel 网站反代 + +推荐用两个域名: + +```text +www.example.com -> 用户端 +admin.example.com -> 管理端 +``` + +### 用户端 + +在 1Panel 创建反向代理网站: + +| 项 | 值 | +| --- | --- | +| 主域名 | `www.example.com` | +| 代理地址 | `http://127.0.0.1:18080` | + +### 管理端 + +在 1Panel 创建反向代理网站: + +| 项 | 值 | +| --- | --- | +| 主域名 | `admin.example.com` | +| 代理地址 | `http://127.0.0.1:18081` | + +然后在两个网站里申请 HTTPS 证书。 + +前端容器内部已经处理: + +| 路径 | 转发目标 | +| --- | --- | +| 用户端 `/api/*` | `video-gateway:9000/*` | +| 管理端 `/api/admin/*` | `video-gateway:9000/admin/*` | +| `/media/*` | `minio:9000/*` | + +所以 1Panel OpenResty 只需要代理到前端容器端口,不需要再单独配置 `/api`。 + +## 8. 启动验证 + +在服务器执行: + +```bash +cd /opt/HAOVP/backend +docker compose --env-file .env.1panel -f docker-compose.1panel.yml ps +``` + +查看关键日志: + +```bash +docker logs -f haovp-mysql +docker logs -f haovp-nacos +docker logs -f haovp-video-gateway +docker logs -f haovp-video-content +``` + +本机健康检查: + +```bash +curl http://127.0.0.1:18080/health +curl http://127.0.0.1:18081/health +curl http://127.0.0.1:9000/actuator/health +``` + +浏览器访问: + +```text +https://www.example.com +https://admin.example.com +``` + +Nacos 控制台仅建议本机 SSH 隧道或 1Panel 终端访问: + +```text +http://127.0.0.1:8848/nacos +``` + +## 9. 可选启用监控 + +默认不会启动 Prometheus/Grafana,节省单机资源。 + +命令行启用: + +```bash +cd /opt/HAOVP/backend +COMPOSE_PROFILES=monitoring docker compose --env-file .env.1panel -f docker-compose.1panel.yml up -d +``` + +1Panel 中可在环境变量里增加: + +```env +COMPOSE_PROFILES=monitoring +``` + +Grafana 默认本机端口: + +```text +http://127.0.0.1:3000 +``` + +不建议直接公网开放 Grafana。 + +## 10. 更新部署 + +拉取代码后重新构建: + +```bash +cd /opt/HAOVP +git pull +cd backend +docker compose --env-file .env.1panel -f docker-compose.1panel.yml up -d --build +``` + +只重启某个服务: + +```bash +docker compose --env-file .env.1panel -f docker-compose.1panel.yml restart video-gateway +``` + +查看资源占用: + +```bash +docker stats +``` + +## 11. 数据备份 + +先加载部署环境变量: + +```bash +cd /opt/HAOVP/backend +set -a +source .env.1panel +set +a +``` + +MySQL: + +```bash +docker exec haovp-mysql mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --all-databases > haovp_mysql_$(date +%F).sql +``` + +Redis: + +```bash +docker exec haovp-redis redis-cli -a "$REDIS_PASSWORD" BGSAVE +docker cp haovp-redis:/data/dump.rdb haovp_redis_$(date +%F).rdb +``` + +MinIO: + +```bash +docker run --rm --network haovp-1panel_haovp-network -v "$PWD/backup:/backup" minio/mc sh -c \ + "mc alias set local http://minio:9000 $MINIO_ACCESS_KEY $MINIO_SECRET_KEY && mc mirror local/$MINIO_BUCKET /backup/$MINIO_BUCKET" +``` + +也可以直接备份 Docker volume,但数据库类服务建议优先使用逻辑备份。 + +## 12. 常见问题 + +### 首次启动很慢 + +后端镜像会在 Docker 构建阶段执行 Maven 构建,前端镜像会执行 npm 构建。国内服务器建议提前配置 Docker、Maven、npm 镜像源,或在 CI 中构建镜像后推送到私有镜像仓库。 + +### 后端连接 RocketMQ 失败 + +1Panel 版已使用单机配置: + +```text +backend/config/rocketmq/broker-1panel.conf +NAMESRV_ADDR=rmqnamesrv:9876 +``` + +如果仍失败,检查: + +```bash +docker logs haovp-rmqnamesrv +docker logs haovp-rmqbroker +docker logs haovp-video-content +``` + +### 前端接口 404 + +确认前端环境变量没有改错: + +| 前端 | 构建参数 | +| --- | --- | +| 用户端 | `VITE_API_BASE_URL=/api` | +| 管理端 | `VITE_API_BASE_URL=/api/admin` | + +前端 Nginx 会把用户端 `/api/auth/login` 转发为网关 `/auth/login`,把管理端 `/api/admin/auth/login` 转发为网关 `/admin/auth/login`。 + +### 图片或视频无法访问 + +前端使用: + +```text +VITE_MEDIA_BASE_URL=/media/video-platform +``` + +前端 Nginx 会把 `/media/video-platform/...` 转发到 MinIO 的 `/video-platform/...`。确认 `minio-init` 已成功创建 bucket: + +```bash +docker logs haovp-minio-init +``` + +### Nacos 密码修改后服务启动失败 + +如果在 Nacos 控制台改了 `nacos` 用户密码,必须同步修改 `.env.1panel`: + +```env +NACOS_PASSWORD=新密码 +``` + +然后重启后端服务: + +```bash +docker compose --env-file .env.1panel -f docker-compose.1panel.yml restart video-gateway video-auth video-user video-content video-comment video-recommend video-admin +``` + +### 内存不足 + +降低 `.env.1panel` 中各服务 JVM 参数,例如: + +```env +CONTENT_JAVA_OPTS=-Xms128m -Xmx384m +AUTH_JAVA_OPTS=-Xms96m -Xmx192m +``` + +同时不要启用 `monitoring` profile。 diff --git a/backend/.env.1panel.example b/backend/.env.1panel.example new file mode 100644 index 0000000..b2a2f77 --- /dev/null +++ b/backend/.env.1panel.example @@ -0,0 +1,41 @@ +MYSQL_ROOT_PASSWORD=change-me-mysql-root-password +MYSQL_APP_USER=video +MYSQL_APP_PASSWORD=change-me-mysql-app-password +REDIS_PASSWORD=change-me-redis-password + +MINIO_ACCESS_KEY=minioadmin +MINIO_SECRET_KEY=change-me-minio-secret-password +MINIO_BUCKET=video-platform + +USER_JWT_SECRET=change-me-user-jwt-secret-at-least-32-bytes +ADMIN_JWT_SECRET=change-me-admin-jwt-secret-at-least-32-bytes +SERVICE_AUTH_TOKEN=change-me-internal-service-token-at-least-32-bytes +ADMIN_INIT_PASSWORD=change-me-admin-initial-password +JWT_EXPIRATION=86400 + +NACOS_USERNAME=nacos +NACOS_PASSWORD=nacos +NACOS_AUTH_TOKEN=change-me-nacos-auth-token-at-least-32-bytes-long + +GRAFANA_ADMIN_USER=admin +GRAFANA_ADMIN_PASSWORD=change-me-grafana-password + +LOCAL_BIND_ADDR=127.0.0.1 +FRONTEND_BIND_ADDR=127.0.0.1 +WEB_HTTP_PORT=18080 +ADMIN_HTTP_PORT=18081 +GATEWAY_HTTP_PORT=9000 +NACOS_HTTP_PORT=8848 +MINIO_API_PORT=9100 +MINIO_CONSOLE_PORT=9101 +SENTINEL_HTTP_PORT=8880 +PROMETHEUS_HTTP_PORT=9090 +GRAFANA_HTTP_PORT=3000 + +GATEWAY_JAVA_OPTS=-Xms128m -Xmx256m +AUTH_JAVA_OPTS=-Xms128m -Xmx256m +USER_JAVA_OPTS=-Xms128m -Xmx256m +CONTENT_JAVA_OPTS=-Xms256m -Xmx512m +COMMENT_JAVA_OPTS=-Xms128m -Xmx256m +RECOMMEND_JAVA_OPTS=-Xms128m -Xmx256m +ADMIN_JAVA_OPTS=-Xms128m -Xmx256m diff --git a/backend/Dockerfile.service.1panel b/backend/Dockerfile.service.1panel new file mode 100644 index 0000000..a1b570d --- /dev/null +++ b/backend/Dockerfile.service.1panel @@ -0,0 +1,31 @@ +# syntax=docker/dockerfile:1 + +FROM maven:3.9-eclipse-temurin-17 AS build + +WORKDIR /workspace + +COPY . . + +ARG MODULE +RUN mvn -pl "${MODULE}" -am package -Dmaven.test.skip=true + +FROM eclipse-temurin:17-jre + +ARG MODULE +ARG JAR_PREFIX +ARG INSTALL_FFMPEG=false + +RUN if [ "$INSTALL_FFMPEG" = "true" ]; then \ + apt-get update && \ + apt-get install -y --no-install-recommends ffmpeg && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/*; \ + fi + +WORKDIR /app + +COPY --from=build /workspace/${MODULE}/target/${JAR_PREFIX}-*.jar /app/app.jar + +ENV JAVA_OPTS="" + +ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app/app.jar"] diff --git a/backend/config/rocketmq/broker-1panel.conf b/backend/config/rocketmq/broker-1panel.conf new file mode 100644 index 0000000..54a25e1 --- /dev/null +++ b/backend/config/rocketmq/broker-1panel.conf @@ -0,0 +1,23 @@ +brokerClusterName = DefaultCluster +brokerName = broker-single +brokerId = 0 + +namesrvAddr = rmqnamesrv:9876 +listenPort = 10911 + +storePathRootDir = /home/rocketmq/store + +sendMessageThreadPoolNums = 8 +pullMessageThreadPoolNums = 8 +queryMessageThreadPoolNums = 4 + +flushDiskType = ASYNC_FLUSH +brokerRole = ASYNC_MASTER +fileReservedTime = 72 + +mapedFileSizeCommitLog = 1073741824 +mapedFileSizeConsumeQueue = 300000 + +autoCreateTopicEnable = true +autoCreateSubscriptionGroup = true +maxMessageSize = 4194304 diff --git a/backend/docker-compose.1panel.yml b/backend/docker-compose.1panel.yml new file mode 100644 index 0000000..1eaccfb --- /dev/null +++ b/backend/docker-compose.1panel.yml @@ -0,0 +1,542 @@ +name: haovp-1panel + +x-common-env: &common-env + TZ: Asia/Shanghai + +x-service-env: &service-env + <<: *common-env + SPRING_PROFILES_ACTIVE: ha + NACOS_HOST: nacos + NACOS_PORT: 8848 + NACOS_USERNAME: ${NACOS_USERNAME:-nacos} + NACOS_PASSWORD: ${NACOS_PASSWORD:-nacos} + SPRING_CLOUD_NACOS_DISCOVERY_USERNAME: ${NACOS_USERNAME:-nacos} + SPRING_CLOUD_NACOS_DISCOVERY_PASSWORD: ${NACOS_PASSWORD:-nacos} + SPRING_CLOUD_NACOS_CONFIG_USERNAME: ${NACOS_USERNAME:-nacos} + SPRING_CLOUD_NACOS_CONFIG_PASSWORD: ${NACOS_PASSWORD:-nacos} + MYSQL_HOST: mysql + MYSQL_PORT: 3306 + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} + MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD} + REDIS_PASSWORD: ${REDIS_PASSWORD} + REDIS_SENTINEL_NODES: redis-sentinel:26379 + SERVICE_AUTH_TOKEN: ${SERVICE_AUTH_TOKEN} + JWT_EXPIRATION: ${JWT_EXPIRATION:-86400} + SENTINEL_DASHBOARD_HOST: sentinel + SENTINEL_DASHBOARD_PORT: 8080 + +x-backend-build: &backend-build + context: . + dockerfile: Dockerfile.service.1panel + +services: + mysql: + image: mysql:8.0 + container_name: haovp-mysql + restart: unless-stopped + environment: + <<: *common-env + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} + MYSQL_DATABASE: video_platform + MYSQL_USER: ${MYSQL_APP_USER:-video} + MYSQL_PASSWORD: ${MYSQL_APP_PASSWORD} + volumes: + - mysql_data:/var/lib/mysql + - ./sql/init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro + - ./sql/nacos-schema.sql:/docker-entrypoint-initdb.d/02-nacos-schema.sql:ro + - ./sql/03-nacos-config-init.sh:/docker-entrypoint-initdb.d/03-nacos-config-init.sh:ro + - ./sql/nacos-config-init.sql:/init-sql/nacos-config-init.sql:ro + command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --default-authentication-plugin=mysql_native_password + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"] + interval: 10s + timeout: 5s + retries: 15 + networks: + - haovp-network + + redis: + image: redis:7.0-alpine + container_name: haovp-redis + restart: unless-stopped + command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes + volumes: + - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] + interval: 10s + timeout: 5s + retries: 10 + networks: + - haovp-network + + redis-sentinel: + image: redis:7.0-alpine + container_name: haovp-redis-sentinel + restart: unless-stopped + volumes: + - redis_sentinel_data:/data + - ./config/redis/sentinel-single.conf:/usr/local/etc/redis/sentinel.conf:ro + command: sh -c "sed \"s/__REDIS_PASSWORD__/${REDIS_PASSWORD}/g\" /usr/local/etc/redis/sentinel.conf > /data/sentinel.conf && redis-sentinel /data/sentinel.conf" + depends_on: + redis: + condition: service_healthy + networks: + - haovp-network + + nacos: + image: nacos/nacos-server:v2.3.2 + container_name: haovp-nacos + restart: unless-stopped + environment: + <<: *common-env + MODE: standalone + SPRING_DATASOURCE_PLATFORM: mysql + MYSQL_SERVICE_HOST: mysql + MYSQL_SERVICE_PORT: 3306 + MYSQL_SERVICE_DB_NAME: nacos_config + MYSQL_SERVICE_USER: root + MYSQL_SERVICE_PASSWORD: ${MYSQL_ROOT_PASSWORD} + MYSQL_SERVICE_DB_PARAM: characterEncoding=utf8&connectTimeout=10000&socketTimeout=30000&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true + JVM_XMS: ${NACOS_JVM_XMS:-512m} + JVM_XMX: ${NACOS_JVM_XMX:-512m} + NACOS_AUTH_ENABLE: "true" + NACOS_AUTH_TOKEN: ${NACOS_AUTH_TOKEN} + NACOS_AUTH_IDENTITY_KEY: serverIdentity + NACOS_AUTH_IDENTITY_VALUE: security + PREFER_HOST_MODE: hostname + ports: + - "${LOCAL_BIND_ADDR:-127.0.0.1}:${NACOS_HTTP_PORT:-8848}:8848" + depends_on: + mysql: + condition: service_healthy + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8848/nacos/v1/console/health/liveness"] + interval: 10s + timeout: 5s + retries: 15 + networks: + - haovp-network + + rmqnamesrv: + image: apache/rocketmq:5.1.4 + container_name: haovp-rmqnamesrv + restart: unless-stopped + command: sh mqnamesrv + healthcheck: + test: ["CMD-SHELL", "pgrep -f 'NamesrvStartup' || exit 1"] + interval: 10s + timeout: 5s + retries: 15 + start_period: 30s + networks: + - haovp-network + + rmqbroker: + image: apache/rocketmq:5.1.4 + container_name: haovp-rmqbroker + user: root + restart: unless-stopped + environment: + NAMESRV_ADDR: rmqnamesrv:9876 + JAVA_OPTS: -Duser.home=/opt + volumes: + - ./config/rocketmq/broker-1panel.conf:/home/rocketmq/rocketmq-5.1.4/conf/broker.conf:ro + - rmqbroker_logs:/home/rocketmq/logs + - rmqbroker_store:/home/rocketmq/store + command: sh mqbroker -c /home/rocketmq/rocketmq-5.1.4/conf/broker.conf + depends_on: + rmqnamesrv: + condition: service_healthy + healthcheck: + test: ["CMD-SHELL", "pgrep -f 'BrokerStartup' || exit 1"] + interval: 10s + timeout: 5s + retries: 15 + start_period: 30s + networks: + - haovp-network + + minio: + image: quay.io/minio/minio + container_name: haovp-minio + restart: unless-stopped + environment: + <<: *common-env + MINIO_ROOT_USER: ${MINIO_ACCESS_KEY} + MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY} + volumes: + - minio_data:/data + command: server /data --console-address ":9001" + ports: + - "${LOCAL_BIND_ADDR:-127.0.0.1}:${MINIO_API_PORT:-9100}:9000" + - "${LOCAL_BIND_ADDR:-127.0.0.1}:${MINIO_CONSOLE_PORT:-9101}:9001" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + interval: 10s + timeout: 5s + retries: 10 + networks: + - haovp-network + + minio-init: + image: minio/mc + container_name: haovp-minio-init + restart: "no" + depends_on: + minio: + condition: service_healthy + entrypoint: > + /bin/sh -c " + mc alias set local http://minio:9000 '${MINIO_ACCESS_KEY}' '${MINIO_SECRET_KEY}' && + mc mb --ignore-existing local/${MINIO_BUCKET:-video-platform} && + mc anonymous set download local/${MINIO_BUCKET:-video-platform} + " + networks: + - haovp-network + + sentinel: + build: + context: ./sentinel-dashboard + dockerfile: Dockerfile + image: haovp/sentinel-dashboard:1.8.6 + container_name: haovp-sentinel + restart: unless-stopped + environment: + <<: *common-env + SERVER_PORT: 8080 + ports: + - "${LOCAL_BIND_ADDR:-127.0.0.1}:${SENTINEL_HTTP_PORT:-8880}:8080" + networks: + - haovp-network + + video-gateway: + build: + <<: *backend-build + args: + MODULE: video-gateway + JAR_PREFIX: video-gateway + image: haovp/video-gateway:1panel + container_name: haovp-video-gateway + restart: unless-stopped + environment: + <<: *service-env + JWT_SECRET: ${USER_JWT_SECRET} + USER_JWT_SECRET: ${USER_JWT_SECRET} + GATEWAY_IGNORE_URLS: /**/auth/login,/**/auth/register,/**/auth/captcha,/**/auth/refresh,/auth/username/**,/content/video/public/**,/content/category/tree,/content/category/list,/content/tag/list,/content/tag/page,/content/danmaku/all/**,/content/danmaku/time,/content/stat/**,/user/profile/public/**,/user/profile/search,/user/follow/following/**,/user/follow/followers/**,/comment/reply/public/**,/comment/public/**,/recommend/home,/recommend/hot/**,/recommend/similar/**,/recommend/tag/**,/admin/auth/captcha,/admin/auth/login + JAVA_OPTS: ${GATEWAY_JAVA_OPTS:--Xms128m -Xmx256m} + ports: + - "${LOCAL_BIND_ADDR:-127.0.0.1}:${GATEWAY_HTTP_PORT:-9000}:9000" + depends_on: + nacos: + condition: service_healthy + redis-sentinel: + condition: service_started + networks: + - haovp-network + + video-auth: + build: + <<: *backend-build + args: + MODULE: video-auth + JAR_PREFIX: video-auth + image: haovp/video-auth:1panel + container_name: haovp-video-auth + restart: unless-stopped + environment: + <<: *service-env + JWT_SECRET: ${USER_JWT_SECRET} + USER_JWT_SECRET: ${USER_JWT_SECRET} + JAVA_OPTS: ${AUTH_JAVA_OPTS:--Xms128m -Xmx256m} + depends_on: + nacos: + condition: service_healthy + mysql: + condition: service_healthy + redis-sentinel: + condition: service_started + networks: + - haovp-network + + video-user: + build: + <<: *backend-build + args: + MODULE: video-user + JAR_PREFIX: video-user + image: haovp/video-user:1panel + container_name: haovp-video-user + restart: unless-stopped + environment: + <<: *service-env + MINIO_HOST: minio + MINIO_PORT: 9000 + MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} + MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} + MINIO_BUCKET: ${MINIO_BUCKET:-video-platform} + JWT_SECRET: ${USER_JWT_SECRET} + USER_JWT_SECRET: ${USER_JWT_SECRET} + JAVA_OPTS: ${USER_JAVA_OPTS:--Xms128m -Xmx256m} + depends_on: + nacos: + condition: service_healthy + mysql: + condition: service_healthy + redis-sentinel: + condition: service_started + minio: + condition: service_healthy + networks: + - haovp-network + + video-content: + build: + <<: *backend-build + args: + MODULE: video-content + JAR_PREFIX: video-content + INSTALL_FFMPEG: "true" + image: haovp/video-content:1panel + container_name: haovp-video-content + restart: unless-stopped + environment: + <<: *service-env + NAMESRV_ADDR: rmqnamesrv:9876 + ROCKETMQ_HOST: rmqnamesrv + ROCKETMQ_PORT: 9876 + MINIO_HOST: minio + MINIO_PORT: 9000 + MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} + MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} + MINIO_BUCKET: ${MINIO_BUCKET:-video-platform} + JWT_SECRET: ${USER_JWT_SECRET} + USER_JWT_SECRET: ${USER_JWT_SECRET} + JAVA_OPTS: ${CONTENT_JAVA_OPTS:--Xms256m -Xmx512m} + depends_on: + nacos: + condition: service_healthy + mysql: + condition: service_healthy + redis-sentinel: + condition: service_started + rmqbroker: + condition: service_healthy + minio: + condition: service_healthy + networks: + - haovp-network + + video-comment: + build: + <<: *backend-build + args: + MODULE: video-comment + JAR_PREFIX: video-comment + image: haovp/video-comment:1panel + container_name: haovp-video-comment + restart: unless-stopped + environment: + <<: *service-env + JWT_SECRET: ${USER_JWT_SECRET} + USER_JWT_SECRET: ${USER_JWT_SECRET} + JAVA_OPTS: ${COMMENT_JAVA_OPTS:--Xms128m -Xmx256m} + depends_on: + nacos: + condition: service_healthy + mysql: + condition: service_healthy + redis-sentinel: + condition: service_started + networks: + - haovp-network + + video-recommend: + build: + <<: *backend-build + args: + MODULE: video-recommend + JAR_PREFIX: video-recommend + image: haovp/video-recommend:1panel + container_name: haovp-video-recommend + restart: unless-stopped + environment: + <<: *service-env + JWT_SECRET: ${USER_JWT_SECRET} + USER_JWT_SECRET: ${USER_JWT_SECRET} + JAVA_OPTS: ${RECOMMEND_JAVA_OPTS:--Xms128m -Xmx256m} + depends_on: + nacos: + condition: service_healthy + mysql: + condition: service_healthy + redis-sentinel: + condition: service_started + networks: + - haovp-network + + video-admin: + build: + <<: *backend-build + args: + MODULE: video-admin + JAR_PREFIX: video-admin + image: haovp/video-admin:1panel + container_name: haovp-video-admin + restart: unless-stopped + environment: + <<: *service-env + JWT_SECRET: ${ADMIN_JWT_SECRET} + ADMIN_JWT_SECRET: ${ADMIN_JWT_SECRET} + ADMIN_INIT_PASSWORD: ${ADMIN_INIT_PASSWORD} + APP_INIT_ADMIN_PASSWORD: ${ADMIN_INIT_PASSWORD} + JAVA_OPTS: ${ADMIN_JAVA_OPTS:--Xms128m -Xmx256m} + depends_on: + nacos: + condition: service_healthy + mysql: + condition: service_healthy + redis-sentinel: + condition: service_started + networks: + - haovp-network + + frontend-web: + build: + context: ../frontend/video-frontend-web + dockerfile: Dockerfile.1panel + args: + VITE_API_BASE_URL: /api + VITE_MEDIA_BASE_URL: /media/video-platform + image: haovp/frontend-web:1panel + container_name: haovp-frontend-web + restart: unless-stopped + ports: + - "${FRONTEND_BIND_ADDR:-127.0.0.1}:${WEB_HTTP_PORT:-18080}:80" + depends_on: + - video-gateway + - minio + networks: + - haovp-network + + frontend-admin: + build: + context: ../frontend/video-frontend-admin + dockerfile: Dockerfile.1panel + args: + VITE_API_BASE_URL: /api/admin + VITE_MEDIA_BASE_URL: /media/video-platform + image: haovp/frontend-admin:1panel + container_name: haovp-frontend-admin + restart: unless-stopped + ports: + - "${FRONTEND_BIND_ADDR:-127.0.0.1}:${ADMIN_HTTP_PORT:-18081}:80" + depends_on: + - video-gateway + - minio + networks: + - haovp-network + + prometheus: + image: prom/prometheus:v2.54.1 + container_name: haovp-prometheus + restart: unless-stopped + profiles: + - monitoring + ports: + - "${LOCAL_BIND_ADDR:-127.0.0.1}:${PROMETHEUS_HTTP_PORT:-9090}:9090" + volumes: + - ./monitoring/prometheus/prometheus.local.yml:/etc/prometheus/prometheus.yml:ro + - prometheus_data:/prometheus + command: + - --config.file=/etc/prometheus/prometheus.yml + - --storage.tsdb.path=/prometheus + - --storage.tsdb.retention.time=15d + networks: + - haovp-network + + grafana: + image: grafana/grafana:11.2.0 + container_name: haovp-grafana + restart: unless-stopped + profiles: + - monitoring + ports: + - "${LOCAL_BIND_ADDR:-127.0.0.1}:${GRAFANA_HTTP_PORT:-3000}:3000" + environment: + <<: *common-env + GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER:-admin} + GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD} + GF_USERS_ALLOW_SIGN_UP: "false" + volumes: + - grafana_data:/var/lib/grafana + - ./monitoring/grafana/provisioning:/etc/grafana/provisioning:ro + - ./monitoring/grafana/dashboards:/var/lib/grafana/dashboards:ro + depends_on: + - prometheus + networks: + - haovp-network + + mysqld-exporter: + image: prom/mysqld-exporter:v0.16.0 + container_name: haovp-mysqld-exporter + restart: unless-stopped + profiles: + - monitoring + environment: + MYSQLD_EXPORTER_PASSWORD: ${MYSQL_ROOT_PASSWORD} + command: + - --mysqld.address=mysql:3306 + - --mysqld.username=root + depends_on: + mysql: + condition: service_healthy + networks: + - haovp-network + + redis-exporter: + image: oliver006/redis_exporter:v1.62.0 + container_name: haovp-redis-exporter + restart: unless-stopped + profiles: + - monitoring + environment: + REDIS_ADDR: redis://redis:6379 + REDIS_PASSWORD: ${REDIS_PASSWORD} + depends_on: + redis: + condition: service_healthy + networks: + - haovp-network + + node-exporter: + image: prom/node-exporter:v1.8.2 + container_name: haovp-node-exporter + restart: unless-stopped + profiles: + - monitoring + command: + - --path.procfs=/host/proc + - --path.sysfs=/host/sys + - --path.rootfs=/rootfs + - --collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/) + volumes: + - /proc:/host/proc:ro + - /sys:/host/sys:ro + - /:/rootfs:ro + networks: + - haovp-network + +networks: + haovp-network: + driver: bridge + +volumes: + mysql_data: + redis_data: + redis_sentinel_data: + minio_data: + rmqbroker_logs: + rmqbroker_store: + prometheus_data: + grafana_data: diff --git a/frontend/video-frontend-admin/Dockerfile.1panel b/frontend/video-frontend-admin/Dockerfile.1panel new file mode 100644 index 0000000..169bd31 --- /dev/null +++ b/frontend/video-frontend-admin/Dockerfile.1panel @@ -0,0 +1,22 @@ +FROM node:20-alpine AS build + +WORKDIR /app + +COPY package*.json ./ +RUN npm ci --prefer-offline --no-audit + +COPY . . + +ARG VITE_API_BASE_URL=/api/admin +ARG VITE_MEDIA_BASE_URL=/media/video-platform +ENV VITE_API_BASE_URL=${VITE_API_BASE_URL} +ENV VITE_MEDIA_BASE_URL=${VITE_MEDIA_BASE_URL} + +RUN npm run build + +FROM nginx:1.27-alpine + +COPY deploy/nginx.1panel.conf /etc/nginx/conf.d/default.conf +COPY --from=build /app/dist /usr/share/nginx/html + +EXPOSE 80 diff --git a/frontend/video-frontend-admin/deploy/nginx.1panel.conf b/frontend/video-frontend-admin/deploy/nginx.1panel.conf new file mode 100644 index 0000000..578728d --- /dev/null +++ b/frontend/video-frontend-admin/deploy/nginx.1panel.conf @@ -0,0 +1,44 @@ +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + client_max_body_size 1024m; + + gzip on; + gzip_min_length 1024; + gzip_types text/plain text/css application/json application/javascript application/xml; + + location / { + try_files $uri $uri/ /index.html; + } + + location /api/admin/ { + proxy_pass http://video-gateway:9000/admin/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + proxy_send_timeout 300s; + proxy_request_buffering off; + } + + location /media/ { + proxy_pass http://minio:9000/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_buffering off; + } + + location = /health { + access_log off; + return 200 "OK\n"; + } +} diff --git a/frontend/video-frontend-web/Dockerfile.1panel b/frontend/video-frontend-web/Dockerfile.1panel new file mode 100644 index 0000000..4f4b62d --- /dev/null +++ b/frontend/video-frontend-web/Dockerfile.1panel @@ -0,0 +1,22 @@ +FROM node:20-alpine AS build + +WORKDIR /app + +COPY package*.json ./ +RUN npm ci --prefer-offline --no-audit + +COPY . . + +ARG VITE_API_BASE_URL=/api +ARG VITE_MEDIA_BASE_URL=/media/video-platform +ENV VITE_API_BASE_URL=${VITE_API_BASE_URL} +ENV VITE_MEDIA_BASE_URL=${VITE_MEDIA_BASE_URL} + +RUN npm run build + +FROM nginx:1.27-alpine + +COPY deploy/nginx.1panel.conf /etc/nginx/conf.d/default.conf +COPY --from=build /app/dist /usr/share/nginx/html + +EXPOSE 80 diff --git a/frontend/video-frontend-web/deploy/nginx.1panel.conf b/frontend/video-frontend-web/deploy/nginx.1panel.conf new file mode 100644 index 0000000..5b74561 --- /dev/null +++ b/frontend/video-frontend-web/deploy/nginx.1panel.conf @@ -0,0 +1,44 @@ +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + client_max_body_size 1024m; + + gzip on; + gzip_min_length 1024; + gzip_types text/plain text/css application/json application/javascript application/xml; + + location / { + try_files $uri $uri/ /index.html; + } + + location /api/ { + proxy_pass http://video-gateway:9000/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + proxy_send_timeout 300s; + proxy_request_buffering off; + } + + location /media/ { + proxy_pass http://minio:9000/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_buffering off; + } + + location = /health { + access_log off; + return 200 "OK\n"; + } +}