From 01ccd44e84a77472f5647adeaa3cb6bdaf9c7175 Mon Sep 17 00:00:00 2001 From: shanshanzhong Date: Tue, 13 Jan 2026 18:17:12 -0800 Subject: [PATCH] feat: optimize docker-compose, add observability stack (Grafana/Loki/Prometheus), and host nginx config --- apis/admin/user.api | 2 + configs/ppanel.yaml | 91 ++++++ docker-compose.cloud.yml | 309 ++++++++++++++++++ grafana/provisioning/dashboards/dashboard.yml | 11 + .../provisioning/datasources/datasource.yml | 27 ++ .../admin/user/updateUserBasicInfoLogic.go | 2 + internal/model/user/user.go | 2 + internal/types/types.go | 2 + nginx_host_config.conf | 37 +++ prometheus/prometheus.yml | 46 +++ 10 files changed, 529 insertions(+) create mode 100644 configs/ppanel.yaml create mode 100644 docker-compose.cloud.yml create mode 100644 grafana/provisioning/dashboards/dashboard.yml create mode 100644 grafana/provisioning/datasources/datasource.yml create mode 100644 nginx_host_config.conf create mode 100644 prometheus/prometheus.yml diff --git a/apis/admin/user.api b/apis/admin/user.api index cb4b3c7..8b7a5ba 100644 --- a/apis/admin/user.api +++ b/apis/admin/user.api @@ -46,6 +46,8 @@ type ( RefererId int64 `json:"referer_id"` Enable bool `json:"enable"` IsAdmin bool `json:"is_admin"` + MemberStatus string `json:"member_status"` + Remark string `json:"remark"` } UpdateUserNotifySettingRequest { UserId int64 `json:"user_id" validate:"required"` diff --git a/configs/ppanel.yaml b/configs/ppanel.yaml new file mode 100644 index 0000000..a24f8e0 --- /dev/null +++ b/configs/ppanel.yaml @@ -0,0 +1,91 @@ +# PPanel Server Configuration +# 完整配置示例 + +# 运行模式: debug, release, test +Model: release +# 监听地址 +Host: 0.0.0.0 +# 监听端口 +Port: 8080 +# 是否开启调试模式 +Debug: false + +# JWT 认证配置 +JwtAuth: + AccessSecret: "ppanel-secret-key-change-me" # 请务必修改此密钥 + AccessExpire: 604800 # Token 过期时间 (秒), 默认 7 天 + MaxSessionsPerUser: 3 # 每个用户最大并发登录数 + +# 日志配置 +Logger: + ServiceName: "PPanel" + Mode: "file" # console, file, volume + Encoding: "json" # json, plain + Path: "logs" # 日志文件路径 + Level: "info" # debug, info, warn, error + Compress: true + KeepDays: 7 + Rotation: "daily" # daily, size + +# MySQL 数据库配置 +MySQL: + Addr: "mysql:3306" # Docker 服务名:端口 + Username: "root" + Password: "ppanel_password" # 与 docker-compose 中的 MYSQL_ROOT_PASSWORD 保持一致 + Dbname: "ppanel_db" + Config: "charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai" + MaxIdleConns: 10 + MaxOpenConns: 100 + SlowThreshold: 1000 # 慢查询阈值 (ms) + +# Redis 配置 +Redis: + Host: "redis:6379" # Docker 服务名:端口 + Pass: "" + DB: 0 + +# 管理员初始化配置 (仅在首次初始化有效,后续请在数据库管理) +Administrator: + Email: "admin@ppanel.dev" + Password: "password" + +# 站点配置 +Site: + Title: "PPanel" + Dec: "PPanel Panel" + Url: "https://your-domain.com" + SubUrl: "https://sub.your-domain.com" + +# 邮件服务配置 +Email: + Enable: false + # platform: "smtp" + # platform_config: "..." + +# 验证配置 +Verify: + TurnstileSiteKey: "" + TurnstileSecret: "" + LoginVerify: false + RegisterVerify: false + ResetPasswordVerify: false + +# 注册配置 +Register: + StopRegister: false + EnableTrial: false + TrialSubscribe: 0 + TrialTime: 0 + TrialTimeUnit: "hour" + EnableIpRegisterLimit: false + IpRegisterLimit: 0 + IpRegisterLimitDuration: 0 + +# 订阅配置 +Subscribe: + SingleModel: false + SubscribePath: "/v1/subscribe/config" + SubscribeDomain: "" + PanDomain: false + UserAgentLimit: false + UserAgentList: "" diff --git a/docker-compose.cloud.yml b/docker-compose.cloud.yml new file mode 100644 index 0000000..d6f98b3 --- /dev/null +++ b/docker-compose.cloud.yml @@ -0,0 +1,309 @@ +# PPanel 服务部署 (云端/无源码版) +# 使用方法: +# 1. 确保已将 docker-compose.cloud.yml, configs/, loki/ 目录上传到服务器同一目录 +# 2. 确保 configs/ 目录下有 ppanel.yaml 配置文件 +# 3. 确保 logs/ 目录存在 (mkdir logs) +# 4. 运行: docker-compose -f docker-compose.cloud.yml up -d + +services: + # ---------------------------------------------------- + # 1. 业务后端 (PPanel Server) + # ---------------------------------------------------- + ppanel-server: + image: registry.kxsw.us/ario-server:latest + container_name: ppanel-server + restart: always + ports: + - "8080:8080" # 暴露端口供宿主机 Nginx 反代 + volumes: + # 挂载配置文件和日志 + - ./configs:/app/etc + - ./logs:/app/logs + environment: + - TZ=Asia/Shanghai + networks: + - ppanel_net + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + depends_on: + - mysql + - redis + + # ---------------------------------------------------- + # 2. MySQL Database + # ---------------------------------------------------- + mysql: + image: mysql:8.0 + container_name: ppanel-mysql + restart: always + ports: + - "3306:3306" # 临时开放外部访问,用完记得关闭! + environment: + MYSQL_ROOT_PASSWORD: "ppanel_password" # 请修改为强密码 + MYSQL_DATABASE: "ppanel_db" + TZ: Asia/Shanghai + command: --default-authentication-plugin=mysql_native_password + volumes: + - mysql_data:/var/lib/mysql + - ./mysql/init:/docker-entrypoint-initdb.d # 初始化脚本 + networks: + - ppanel_net + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # ---------------------------------------------------- + # 3. Redis + # ---------------------------------------------------- + redis: + image: redis:7.0 + container_name: ppanel-redis + restart: always + volumes: + - redis_data:/data + networks: + - ppanel_net + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # ---------------------------------------------------- + # 4. Loki (日志存储) + # ---------------------------------------------------- + loki: + image: grafana/loki:3.0.0 + container_name: ppanel-loki + restart: always + volumes: + # 必须上传 loki 目录到服务器 + - ./loki/loki-config.yaml:/etc/loki/local-config.yaml + - loki_data:/loki + command: -config.file=/etc/loki/local-config.yaml + networks: + - ppanel_net + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # ---------------------------------------------------- + # 5. Promtail (日志采集) + # ---------------------------------------------------- + promtail: + image: grafana/promtail:3.0.0 + container_name: ppanel-promtail + restart: always + volumes: + - ./loki/promtail-config.yaml:/etc/promtail/config.yaml + - /var/lib/docker/containers:/var/lib/docker/containers:ro + - /var/run/docker.sock:/var/run/docker.sock + # 采集当前目录下的 logs 文件夹 + - ./logs:/var/log/ppanel-server:ro + command: -config.file=/etc/promtail/config.yaml + networks: + - ppanel_net + depends_on: + - loki + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # ---------------------------------------------------- + # 6. Grafana (日志界面) + # ---------------------------------------------------- + grafana: + image: grafana/grafana:latest + container_name: ppanel-grafana + restart: always + ports: + - "3000:3000" + environment: + - GF_SECURITY_ADMIN_PASSWORD=admin + - GF_USERS_ALLOW_SIGN_UP=false + volumes: + - grafana_data:/var/lib/grafana + # 自动加载数据源和仪表盘配置 + - ./grafana/provisioning:/etc/grafana/provisioning + # 挂载本地仪表盘 JSON 文件目录 + - ./grafana/dashboards:/var/lib/grafana/dashboards + networks: + - ppanel_net + depends_on: + - loki + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # ---------------------------------------------------- + # 7. Prometheus (指标采集) + # ---------------------------------------------------- + prometheus: + image: prom/prometheus:latest + container_name: ppanel-prometheus + restart: always + ports: + - "9090:9090" # 暴露端口便于调试 + volumes: + - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml + - prometheus_data:/prometheus + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + - '--web.enable-lifecycle' + networks: + - ppanel_net + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # ---------------------------------------------------- + # 8. Redis Exporter (Redis指标导出) + # ---------------------------------------------------- + redis-exporter: + image: oliver006/redis_exporter:latest + container_name: ppanel-redis-exporter + restart: always + environment: + - REDIS_ADDR=redis://redis:6379 + networks: + - ppanel_net + depends_on: + - redis + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # ---------------------------------------------------- + # 9. Nginx Exporter (监控宿主机 Nginx) + # ---------------------------------------------------- + nginx-exporter: + image: nginx/nginx-prometheus-exporter:latest + container_name: ppanel-nginx-exporter + restart: always + # 使用 host.docker.internal 访问宿主机 + command: + - -nginx.scrape-uri=http://host.docker.internal:80/nginx_status + extra_hosts: + - "host.docker.internal:host-gateway" + networks: + - ppanel_net + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # ---------------------------------------------------- + # 10. MySQL Exporter (MySQL指标导出) + # ---------------------------------------------------- + mysql-exporter: + image: prom/mysqld-exporter:latest + container_name: ppanel-mysql-exporter + restart: always + command: + - --config.my-cnf=/etc/.my.cnf + volumes: + - ./mysql/.my.cnf:/etc/.my.cnf:ro + networks: + - ppanel_net + depends_on: + - mysql + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # ---------------------------------------------------- + # 11. Jaeger (链路追踪) + # ---------------------------------------------------- + jaeger: + image: jaegertracing/all-in-one:latest + container_name: ppanel-jaeger + restart: always + ports: + - "16686:16686" # Jaeger UI + - "4317:4317" # OTLP gRPC + - "4318:4318" # OTLP HTTP + environment: + - LOG_LEVEL=debug + - COLLECTOR_OTLP_ENABLED=true + networks: + - ppanel_net + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # ---------------------------------------------------- + # 12. Node Exporter (宿主机监控) + # ---------------------------------------------------- + node-exporter: + image: prom/node-exporter:latest + container_name: ppanel-node-exporter + restart: always + volumes: + - /proc:/host/proc:ro + - /sys:/host/sys:ro + - /:/rootfs:ro + command: + - '--path.procfs=/host/proc' + - '--path.sysfs=/host/sys' + - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)' + networks: + - ppanel_net + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # ---------------------------------------------------- + # 13. cAdvisor (容器监控) + # ---------------------------------------------------- + cadvisor: + image: gcr.io/cadvisor/cadvisor:latest + container_name: ppanel-cadvisor + restart: always + volumes: + - /:/rootfs:ro + - /var/run:/var/run:ro + - /sys:/sys:ro + - /var/lib/docker/:/var/lib/docker:ro + - /dev/disk/:/dev/disk:ro + networks: + - ppanel_net + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + +volumes: + mysql_data: + redis_data: + loki_data: + grafana_data: + prometheus_data: + +networks: + ppanel_net: + name: ppanel_net + driver: bridge diff --git a/grafana/provisioning/dashboards/dashboard.yml b/grafana/provisioning/dashboards/dashboard.yml new file mode 100644 index 0000000..f5dee2d --- /dev/null +++ b/grafana/provisioning/dashboards/dashboard.yml @@ -0,0 +1,11 @@ +apiVersion: 1 + +providers: + - name: 'Default' + orgId: 1 + folder: '' + type: file + disableDeletion: false + updateIntervalSeconds: 10 + options: + path: /var/lib/grafana/dashboards diff --git a/grafana/provisioning/datasources/datasource.yml b/grafana/provisioning/datasources/datasource.yml new file mode 100644 index 0000000..e5aaac2 --- /dev/null +++ b/grafana/provisioning/datasources/datasource.yml @@ -0,0 +1,27 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + orgId: 1 + url: http://prometheus:9090 + isDefault: true + version: 1 + editable: true + + - name: Loki + type: loki + access: proxy + orgId: 1 + url: http://loki:3100 + version: 1 + editable: true + + - name: Jaeger + type: jaeger + access: proxy + orgId: 1 + url: http://jaeger:16686 + version: 1 + editable: true diff --git a/internal/logic/admin/user/updateUserBasicInfoLogic.go b/internal/logic/admin/user/updateUserBasicInfoLogic.go index faa7930..1cb3345 100644 --- a/internal/logic/admin/user/updateUserBasicInfoLogic.go +++ b/internal/logic/admin/user/updateUserBasicInfoLogic.go @@ -121,6 +121,8 @@ func (l *UpdateUserBasicInfoLogic) UpdateUserBasicInfo(req *types.UpdateUserBasi userInfo.Commission = req.Commission } tool.DeepCopy(userInfo, req) + userInfo.Remark = req.Remark + userInfo.MemberStatus = req.MemberStatus userInfo.OnlyFirstPurchase = &req.OnlyFirstPurchase userInfo.ReferralPercentage = req.ReferralPercentage diff --git a/internal/model/user/user.go b/internal/model/user/user.go index 9318aaf..44302d9 100644 --- a/internal/model/user/user.go +++ b/internal/model/user/user.go @@ -24,6 +24,8 @@ type User struct { EnableSubscribeNotify *bool `gorm:"default:false;not null;comment:Enable Subscription Notifications"` EnableTradeNotify *bool `gorm:"default:false;not null;comment:Enable Trade Notifications"` LastLoginTime *time.Time `gorm:"comment:Last Login Time"` + MemberStatus string `gorm:"type:varchar(20);default:'';comment:Member Status"` // Member Status + Remark string `gorm:"type:varchar(255);default:'';comment:Remark"` // Remark AuthMethods []AuthMethods `gorm:"foreignKey:UserId;references:Id"` UserDevices []Device `gorm:"foreignKey:UserId;references:Id"` CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` diff --git a/internal/types/types.go b/internal/types/types.go index 870b6ff..8c3ae56 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -2548,6 +2548,8 @@ type UpdateUserBasiceInfoRequest struct { RefererId int64 `json:"referer_id"` Enable bool `json:"enable"` IsAdmin bool `json:"is_admin"` + MemberStatus string `json:"member_status"` + Remark string `json:"remark"` } type UpdateUserNotifyRequest struct { diff --git a/nginx_host_config.conf b/nginx_host_config.conf new file mode 100644 index 0000000..10b07ae --- /dev/null +++ b/nginx_host_config.conf @@ -0,0 +1,37 @@ +server { + listen 80; + server_name localhost; # 请修改为您实际的域名,如 ppanel.example.com + + # ---------------------------------------------------- + # 1. Nginx Status (探针/监控端点) + # ---------------------------------------------------- + # 用于 nginx-exporter 采集 Nginx 自身指标 (连接数、请求数等) + location /nginx_status { + stub_status on; + access_log off; + + # 允许 Docker 容器和本地访问 + allow 127.0.0.1; + allow 172.16.0.0/12; # Docker bridge 默认网段 + allow 192.168.0.0/16; # Docker Desktop for Mac/Windows 网段 + allow 10.0.0.0/8; # 其他常见私有网段 + deny all; + } + + # ---------------------------------------------------- + # 2. PPanel Server (后端 API) + # ---------------------------------------------------- + # 将请求转发到宿主机 8080 端口 (docker-compose 中暴露的端口) + location / { + proxy_pass http://127.0.0.1:8080; + 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; + + # WebSocket 支持 (如果需要) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} diff --git a/prometheus/prometheus.yml b/prometheus/prometheus.yml new file mode 100644 index 0000000..5316922 --- /dev/null +++ b/prometheus/prometheus.yml @@ -0,0 +1,46 @@ +# Prometheus 配置文件 +global: + scrape_interval: 15s # 默认抓取频率 + evaluation_interval: 15s + +scrape_configs: + # ---------------------------------------- + # 1. Prometheus 自身监控 + # ---------------------------------------- + - job_name: "prometheus" + static_configs: + - targets: ["localhost:9090"] + + # ---------------------------------------- + # 2. 业务后端 (PPanel Server) + # ---------------------------------------- + # 如果您的后端代码暴露了 /metrics 接口,可启用此项 + # - job_name: "ppanel-server" + # static_configs: + # - targets: ["ppanel-server:8080"] + + # ---------------------------------------- + # 3. 基础设施监控 (Redis, MySQL, Nginx) + # ---------------------------------------- + - job_name: "redis" + static_configs: + - targets: ["redis-exporter:9121"] + + - job_name: "mysql" + static_configs: + - targets: ["mysql-exporter:9104"] + + - job_name: "nginx" + static_configs: + - targets: ["nginx-exporter:9113"] + + # ---------------------------------------- + # 4. 宿主机与容器资源监控 + # ---------------------------------------- + - job_name: "node-exporter" # 宿主机硬件资源 + static_configs: + - targets: ["node-exporter:9100"] + + - job_name: "cadvisor" # 容器资源 + static_configs: + - targets: ["cadvisor:8080"]