From ab1515dffba1505fee2895d5fc69cbb482eba1e5 Mon Sep 17 00:00:00 2001 From: jack Date: Sat, 28 Feb 2026 22:05:43 -0500 Subject: [PATCH] =?UTF-8?q?refactor:=20config/apps=20=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E9=87=8D=E7=BB=84=E3=80=81=E6=96=87=E6=A1=A3=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E3=80=81=E6=9E=B6=E6=9E=84=E5=9B=BE=E6=94=B6=E7=AA=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 中央:config/(prometheus,alertmanager,grafana)、apps/(tile-cache,topology-editor) - 边缘:config/(vmagent,blackbox,targets)、apps/(onvif-exporter) - env: TRAEFIK_PROVIDER、prometheus/env.example 详细说明 - 文档:README/doc 重构,EDGE_CACHE 合并到 EDGE_AGENT_CONFIG - targets.csv 更新流程说明,ARCHITECTURE 图收窄 Made-with: Cursor --- .gitignore | 1 - README.md | 94 +- central-server/CONFIGURATION.md | 44 +- .../apps/tile-cache}/Dockerfile | 2 +- central-server/apps/tile-cache/package.json | 1 + .../apps/tile-cache}/server.js | 0 .../apps/topology-editor/.dockerignore | 3 + .../apps/topology-editor/Dockerfile | 16 + .../apps/topology-editor/package-lock.json | 827 ++++++++++++++++++ .../apps/topology-editor/package.json | 13 + .../apps/topology-editor/public/index.html | 509 +++++++++++ central-server/apps/topology-editor/server.js | 267 ++++++ .../alertmanager/alertmanager.yml | 0 .../grafana/dashboards/onvif-monitoring.json | 0 .../provisioning/dashboards/dashboard.yml | 0 .../datasources/prometheus-admin.yml | 0 .../provisioning/datasources/prometheus.yml | 0 .../datasources/victoriametrics.yml | 0 .../{ => config}/grafana/setup-users.sh | 0 .../{ => config/prometheus}/alert_rules.yml | 0 .../{ => config/prometheus}/prometheus.yml | 23 +- .../prometheus}/prometheus.yml.template | 23 +- central-server/deploy.sh | 83 +- central-server/docker-compose.yml | 56 +- central-server/env.example | 118 ++- doc/ALERTING.md | 8 +- doc/ARCHITECTURE.md | 124 +-- doc/BEST_PRACTICES.md | 7 +- doc/CENTRAL_SERVER_CONFIG.md | 23 +- doc/DEPLOYMENT_GUIDE.md | 34 +- doc/EDGE_AGENT_CONFIG.md | 18 +- doc/EDGE_CACHE.md | 34 - doc/ONVIF_ALTERNATIVES.md | 8 +- doc/README.md | 117 +-- doc/TARGETS_AND_MONITORING.md | 2 + doc/TROUBLESHOOTING.md | 8 +- .../{ => apps}/onvif-exporter/Dockerfile | 4 +- .../{ => apps}/onvif-exporter/README.md | 0 edge-agent/{ => apps}/onvif-exporter/go.mod | 0 edge-agent/{ => apps}/onvif-exporter/main.go | 0 edge-agent/{ => config}/blackbox/config.yml | 0 .../vmagent}/vmagent-scrape.yml.template | 0 edge-agent/deploy.sh | 6 +- edge-agent/docker-compose.yml | 8 +- edge-agent/env.example | 3 +- edge-agent/prometheus-edge/prometheus.yml | 45 - .../prometheus-edge/prometheus.yml.template | 45 - tile-cache/package.json | 6 - 48 files changed, 2071 insertions(+), 509 deletions(-) rename {tile-cache => central-server/apps/tile-cache}/Dockerfile (63%) create mode 100644 central-server/apps/tile-cache/package.json rename {tile-cache => central-server/apps/tile-cache}/server.js (100%) create mode 100644 central-server/apps/topology-editor/.dockerignore create mode 100644 central-server/apps/topology-editor/Dockerfile create mode 100644 central-server/apps/topology-editor/package-lock.json create mode 100644 central-server/apps/topology-editor/package.json create mode 100644 central-server/apps/topology-editor/public/index.html create mode 100644 central-server/apps/topology-editor/server.js rename central-server/{ => config}/alertmanager/alertmanager.yml (100%) rename central-server/{ => config}/grafana/dashboards/onvif-monitoring.json (100%) rename central-server/{ => config}/grafana/provisioning/dashboards/dashboard.yml (100%) rename central-server/{ => config}/grafana/provisioning/datasources/prometheus-admin.yml (100%) rename central-server/{ => config}/grafana/provisioning/datasources/prometheus.yml (100%) rename central-server/{ => config}/grafana/provisioning/datasources/victoriametrics.yml (100%) rename central-server/{ => config}/grafana/setup-users.sh (100%) rename central-server/{ => config/prometheus}/alert_rules.yml (100%) rename central-server/{ => config/prometheus}/prometheus.yml (50%) rename central-server/{ => config/prometheus}/prometheus.yml.template (56%) delete mode 100644 doc/EDGE_CACHE.md rename edge-agent/{ => apps}/onvif-exporter/Dockerfile (82%) rename edge-agent/{ => apps}/onvif-exporter/README.md (100%) rename edge-agent/{ => apps}/onvif-exporter/go.mod (100%) rename edge-agent/{ => apps}/onvif-exporter/main.go (100%) rename edge-agent/{ => config}/blackbox/config.yml (100%) rename edge-agent/{prometheus-edge => config/vmagent}/vmagent-scrape.yml.template (100%) delete mode 100644 edge-agent/prometheus-edge/prometheus.yml delete mode 100644 edge-agent/prometheus-edge/prometheus.yml.template delete mode 100644 tile-cache/package.json diff --git a/.gitignore b/.gitignore index 19663d6..1e6aea4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ central-server/data/ central-server/.env edge-agent/.env -edge-agent/prometheus-edge/data/ # 生成文件(由 update-configs.sh 从 targets.csv 生成) edge-agent/config/*.json diff --git a/README.md b/README.md index aa7a9ef..b925e32 100644 --- a/README.md +++ b/README.md @@ -1,67 +1,91 @@ # Distributed-Prometheus -分布式 Prometheus 监控系统,支持多用户、多设备监控。 +分布式 Prometheus 监控系统:中央收集、边缘上报、多用户多设备。 --- -## 部署顺序 +## 架构概览 -**先中央,后边缘**(边缘向中央上报,中央必须先就绪)。 +``` +边缘 targets.csv → update-configs.sh → target-onvif / target-ping / target-topology +边缘 vmagent 抓取 → remote_write → 中央 VictoriaMetrics +中央 Prometheus 抓取本地 + 查 VictoriaMetrics → 告警 + Grafana +``` -| 步骤 | 做什么 | 命令摘要 | -|------|--------|----------| -| **第一步** | 部署中央服务器 | `cd central-server && bash deploy.sh` | -| **第二步** | 部署边缘节点(可选,可多台) | 本机同机:`cd edge-agent && bash deploy.sh --local`;远程:配 `.env` 后 `bash deploy.sh` | -| **第三步** | 多用户 / 告警(可选) | Grafana:`central-server/grafana/setup-users.sh`;告警:编辑 `alertmanager/alertmanager.yml` | - -**完整说明、验证方式与文档入口**:**[doc/README.md](doc/README.md)**(建议先看其中的「部署顺序」)。 +边缘将指标推送到中央 VictoriaMetrics(8428);Grafana 查询边缘数据选 **VictoriaMetrics**,中央自抓选 **Prometheus**。 --- ## 项目结构 -- **central-server/** — 中央:Prometheus、Grafana、VictoriaMetrics、Alertmanager -- **edge-agent/** — 边缘:vmagent、ONVIF Exporter、Blackbox Exporter +``` +Distributed-Prometheus/ +├── central-server/ # 中央节点 +│ ├── config/ # 配置(prometheus、alertmanager、grafana) +│ ├── apps/ # 自建应用(tile-cache、topology-editor) +│ └── data/ # 运行时数据(gitignore) +│ +├── edge-agent/ # 边缘节点(可多台) +│ ├── config/ # 配置(vmagent、blackbox、targets.csv) +│ └── apps/ # 自建应用(onvif-exporter) +│ +└── doc/ # 文档 +``` --- -## 快速开始(对应第一步 + 第二步) +## 快速开始 -1. **第一步:部署中央** - ```bash - cd central-server - cp env.example .env # 可选 - bash deploy.sh - ``` - 访问 Grafana:http://localhost:3000(admin / admin123)。 - 2. **第二步:部署边缘**(可选) - - 本机同机:`cd edge-agent && bash deploy.sh --local` - - 边缘在别台机器:在 `edge-agent` 里配 `.env` 后 `bash deploy.sh` +**顺序**:中央 → 边缘(边缘上报中央,中央须先就绪) - 边缘数据在 Grafana 中需选择数据源 **「VictoriaMetrics」** 才能看到;中央自身指标在数据源「Prometheus」。 +```bash +# 1. 中央 +cd central-server && cp env.example .env && bash deploy.sh -3. **第三步(可选)**:多用户见 `doc/USER_MANAGEMENT.md`,告警见 `doc/ALERTING.md`。 +# 2. 边缘(本机同机) +cd edge-agent && bash deploy.sh --local + +# 2. 边缘(跨机) +cd edge-agent && cp env.example .env +# 编辑 .env 中 CENTRAL_SERVER_HOST=中央IP +bash deploy.sh +``` --- ## 访问地址(默认) -- Grafana: http://localhost:3000 -- Prometheus: http://localhost:9091 -- VictoriaMetrics: http://localhost:8428 -- Alertmanager: http://localhost:9093 -- 边缘 Prometheus(端口 9092):http://localhost:9092 +| 服务 | 端口 | URL | +|------|------|-----| +| Grafana | 3000 | http://localhost:3000 | +| Prometheus | 9091 | http://localhost:9091 | +| VictoriaMetrics | 8428 | http://localhost:8428 | +| Alertmanager | 9093 | http://localhost:9093 | +| GPS 标注助手 | 4080 | http://localhost:4080 | +| 边缘 vmagent | 9092 | http://localhost:9092 | + +Grafana 默认 admin/admin123;查边缘数据选数据源 **VictoriaMetrics**。 --- -## 多用户与数据隔离 +## 监控目标(targets.csv) -Grafana 支持多组织、多用户;通过 Prometheus 标签做数据隔离(如 `user_group`)。管理员可查看全部数据。详见 **doc/USER_MANAGEMENT.md**。 +边缘监控目标在 `edge-agent/config/targets.csv`,部署时自动生成 `target-onvif.json`、`target-ping.json`。 + +**修改 targets.csv 后**:手动执行 `cd edge-agent/config && ./update-configs.sh`(或重新 `deploy.sh`),vmagent 每 5 分钟自动重载,无需重启。 + +详见 [doc/TARGETS_AND_MONITORING.md](doc/TARGETS_AND_MONITORING.md)。 --- ## 文档 -**入口与部署顺序**:**[doc/README.md](doc/README.md)** - -其他文档均在 `doc/` 下:架构(ARCHITECTURE)、中央/边缘配置、告警、部署指南、故障排查等,见 [doc/README.md#文档列表](doc/README.md)。 +| 类别 | 文档 | +|------|------| +| **部署与配置** | [doc/README.md](doc/README.md) 部署步骤、[DEPLOYMENT_GUIDE](doc/DEPLOYMENT_GUIDE.md) | +| **架构** | [ARCHITECTURE](doc/ARCHITECTURE.md) 容器关系、数据流 | +| **中央** | [CENTRAL_SERVER_CONFIG](doc/CENTRAL_SERVER_CONFIG.md)、[central-server/CONFIGURATION.md](central-server/CONFIGURATION.md) | +| **边缘** | [EDGE_AGENT_CONFIG](doc/EDGE_AGENT_CONFIG.md)、[TARGETS_AND_MONITORING](doc/TARGETS_AND_MONITORING.md) | +| **告警** | [ALERTING](doc/ALERTING.md) 规则与 Alertmanager | +| **扩展** | [ONVIF_ALTERNATIVES](doc/ONVIF_ALTERNATIVES.md)、[TIANDITU_CONFIG](doc/TIANDITU_CONFIG.md)、[USER_MANAGEMENT](doc/USER_MANAGEMENT.md) | +| **运维** | [TROUBLESHOOTING](doc/TROUBLESHOOTING.md)、[BEST_PRACTICES](doc/BEST_PRACTICES.md) | diff --git a/central-server/CONFIGURATION.md b/central-server/CONFIGURATION.md index 603e80e..29aa6bb 100644 --- a/central-server/CONFIGURATION.md +++ b/central-server/CONFIGURATION.md @@ -8,10 +8,13 @@ - **`.env`** - 环境变量配置文件(从 `env.example` 复制并修改) - **`docker-compose.yml`** - Docker Compose 服务定义(使用环境变量) -- **`prometheus.yml.template`** - Prometheus 配置模板(部署时自动生成 `prometheus.yml`) -- **`prometheus.yml`** - Prometheus 实际配置文件(由模板自动生成,不要手动编辑) -- **`alert_rules.yml`** - Prometheus 告警规则配置 -- **`alertmanager/alertmanager.yml`** - Alertmanager 告警管理配置 +- **`config/`** - 配置目录 + - `prometheus/` - Prometheus 配置(prometheus.yml.template, prometheus.yml, alert_rules.yml) + - `alertmanager/` - Alertmanager 配置(alertmanager.yml) + - `grafana/` - Grafana 配置(provisioning, dashboards) +- **`apps/`** - 自建应用源码 + - `tile-cache/` - 天地图瓦片缓存 + - `topology-editor/` - GPS 标注助手 ## 快速开始 @@ -30,7 +33,7 @@ 部署脚本会自动: - 加载 `.env` 文件中的环境变量 -- 从 `prometheus.yml.template` 生成 `prometheus.yml` +- 从 `config/prometheus/prometheus.yml.template` 生成 `config/prometheus/prometheus.yml` - 创建数据目录并设置权限 - 启动所有服务 @@ -108,7 +111,7 @@ | 参数 | 默认值 | 说明 | |------|--------|------| -| `TIANDITU_TK` | (空) | **天地图密钥**,配置到 `.env` 中。启用后 tile-cache、拓扑助手「使用服务器缓存」及 Grafana Geomap 使用天地图底图时均使用此密钥,无需在浏览器或 Grafana 中填写。在 [天地图开放平台](https://console.tianditu.gov.cn/) 申请。 | +| `TIANDITU_TK` | (空) | **天地图密钥**,配置到 `.env` 中。启用后 tile-cache 与 Grafana Geomap 使用天地图底图时均使用此密钥,无需在 Grafana 中填写。在 [天地图开放平台](https://console.tianditu.gov.cn/) 申请。 | | `TILE_CACHE_PORT` | 4090 | 瓦片缓存服务端口 | | `TILE_CACHE_DATA_DIR` | ./data/tile-cache | 瓦片缓存数据目录 | | `TILE_CACHE_TTL_DAYS` | 7 | 缓存老化时间(天),超过后该瓦片下次请求时重新向天地图拉取;可改为 15 等 | @@ -135,7 +138,8 @@ | 参数 | 默认值 | 说明 | |------|--------|------| | `TRAEFIK_ENABLED` | true | 是否启用 Traefik 反向代理 | -| `TRAEFIK_NETWORK` | traefik | Traefik 网络名称 | +| `TRAEFIK_PROVIDER` | external | Traefik 来源:**internal**=本编排启动 Traefik;**external**=使用已有外部 Traefik | +| `TRAEFIK_NETWORK` | traefik | Traefik 网络名称(external 时通常为 traefik;internal 时 deploy.sh 设为 central_default) | | `GRAFANA_DOMAIN` | grafana.example.com | Grafana 域名 | | `PROMETHEUS_DOMAIN` | prometheus.example.com | Prometheus 域名 | | `ALERTMANAGER_DOMAIN` | alertmanager.example.com | Alertmanager 域名 | @@ -145,11 +149,11 @@ **Traefik 配置说明**: - 启用 Traefik 后,服务将通过域名访问,不再直接暴露端口 -- 需要确保 Traefik 网络已创建:`docker network create traefik`(如果不存在) -- 需要配置 DNS 解析,将域名指向 Traefik 服务器 +- **TRAEFIK_PROVIDER=internal**:本编排内启动 Traefik,监听 80/443,自动创建网络,无需外部 Traefik +- **TRAEFIK_PROVIDER=external**:接入已有 Traefik,需 `docker network create traefik`(若不存在) +- 需要配置 DNS 解析,将域名指向本机 - VictoriaMetrics 通常不通过 Traefik 访问(边缘节点直接连接) - 如果使用 HTTPS,需要配置 Traefik 的 TLS 证书 -- `NETWORK_NAME` 必须与 Traefik 实际网络一致,否则 Traefik 无法转发 ### Docker 网络配置 @@ -290,9 +294,9 @@ Docker Compose 配置文件,定义了所有服务的: **注意**:此文件已配置为使用环境变量,一般不需要手动修改。 -### prometheus.yml.template +### config/prometheus/prometheus.yml.template -Prometheus 配置模板文件,包含: +Prometheus 配置模板文件(位于 `config/prometheus/`),包含: - 全局配置(抓取间隔、评估间隔、集群名称) - 远程写入配置(接收边缘节点数据) - 抓取配置(抓取本地服务指标) @@ -301,18 +305,18 @@ Prometheus 配置模板文件,包含: **注意**: - 此文件是模板,不要直接使用 -- 部署脚本会自动从此模板生成 `prometheus.yml` +- 部署脚本会自动从此模板生成 `prometheus/prometheus.yml` - 修改配置应通过 `.env` 文件,而不是直接修改模板 -### prometheus.yml +### config/prometheus/prometheus.yml Prometheus 实际配置文件,由 `prometheus.yml.template` 自动生成。 **注意**: - 此文件由部署脚本自动生成,**不要手动编辑** -- 如果需要修改,应修改 `prometheus.yml.template` 和 `.env` 文件 +- 如果需要修改,应修改 `config/prometheus/prometheus.yml.template` 和 `.env` 文件 -### alert_rules.yml +### config/prometheus/alert_rules.yml Prometheus 告警规则配置文件,定义了: - ONVIF 设备告警规则(设备离线、高温、存储不足) @@ -320,7 +324,7 @@ Prometheus 告警规则配置文件,定义了: **注意**:此文件需要手动编辑,修改后需要重启 Prometheus 服务。 -### alertmanager/alertmanager.yml +### config/alertmanager/alertmanager.yml Alertmanager 告警管理配置文件,定义了: - 告警路由规则 @@ -343,7 +347,7 @@ Alertmanager 告警管理配置文件,定义了: **A**: - 查看环境变量:`cat .env` -- 查看生成的 Prometheus 配置:`cat prometheus.yml` +- 查看生成的 Prometheus 配置:`cat config/prometheus/prometheus.yml` - 查看 Docker Compose 配置:`cat docker-compose.yml` ### Q3: 配置错误导致服务无法启动? @@ -361,9 +365,7 @@ Alertmanager 告警管理配置文件,定义了: # 备份所有配置文件 tar -czf central-server-config-backup-$(date +%Y%m%d).tar.gz \ .env \ - prometheus.yml.template \ - alert_rules.yml \ - alertmanager/alertmanager.yml \ + config/ \ docker-compose.yml ``` diff --git a/tile-cache/Dockerfile b/central-server/apps/tile-cache/Dockerfile similarity index 63% rename from tile-cache/Dockerfile rename to central-server/apps/tile-cache/Dockerfile index 08e3a6f..85c030b 100644 --- a/tile-cache/Dockerfile +++ b/central-server/apps/tile-cache/Dockerfile @@ -1,6 +1,6 @@ FROM node:20-alpine WORKDIR /app -COPY tile-cache/package.json tile-cache/server.js ./ +COPY apps/tile-cache/package.json apps/tile-cache/server.js ./ RUN mkdir -p /app/cache ENV PORT=4090 EXPOSE 4090 diff --git a/central-server/apps/tile-cache/package.json b/central-server/apps/tile-cache/package.json new file mode 100644 index 0000000..dc477d9 --- /dev/null +++ b/central-server/apps/tile-cache/package.json @@ -0,0 +1 @@ +{"name":"tianditu-tile-cache","version":"1.0.0","description":"Cache Tianditu WMTS tiles to reduce API key usage","main":"server.js"} diff --git a/tile-cache/server.js b/central-server/apps/tile-cache/server.js similarity index 100% rename from tile-cache/server.js rename to central-server/apps/tile-cache/server.js diff --git a/central-server/apps/topology-editor/.dockerignore b/central-server/apps/topology-editor/.dockerignore new file mode 100644 index 0000000..54e38e4 --- /dev/null +++ b/central-server/apps/topology-editor/.dockerignore @@ -0,0 +1,3 @@ +node_modules +*.log +.env* diff --git a/central-server/apps/topology-editor/Dockerfile b/central-server/apps/topology-editor/Dockerfile new file mode 100644 index 0000000..f379dcb --- /dev/null +++ b/central-server/apps/topology-editor/Dockerfile @@ -0,0 +1,16 @@ +# GPS 标注助手:H5 采集 GPS + 编辑 targets.csv(构建上下文为 central-server) +FROM node:20-alpine + +WORKDIR /app + +COPY apps/topology-editor/package.json ./ +RUN npm install --production + +COPY apps/topology-editor/server.js ./ +COPY apps/topology-editor/public ./public + +ENV PORT=4080 +EXPOSE 4080 + +# 运行时由 docker-compose 挂载 edge-agent/config 到 /config,并设置 CONFIG_DIR=/config +CMD ["node", "server.js"] diff --git a/central-server/apps/topology-editor/package-lock.json b/central-server/apps/topology-editor/package-lock.json new file mode 100644 index 0000000..d76e74b --- /dev/null +++ b/central-server/apps/topology-editor/package-lock.json @@ -0,0 +1,827 @@ +{ + "name": "topology-editor", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "topology-editor", + "version": "0.1.0", + "dependencies": { + "express": "^4.19.2" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + } + } +} diff --git a/central-server/apps/topology-editor/package.json b/central-server/apps/topology-editor/package.json new file mode 100644 index 0000000..c8308c9 --- /dev/null +++ b/central-server/apps/topology-editor/package.json @@ -0,0 +1,13 @@ +{ + "name": "topology-editor", + "version": "0.1.0", + "description": "拓扑标注助手:上传/下载 targets.csv,H5 采集 GPS 与地图校验。可与 central-server 或 edge-agent 同机运行。", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "express": "^4.19.2", + "multer": "^1.4.5-lts.1" + } +} diff --git a/central-server/apps/topology-editor/public/index.html b/central-server/apps/topology-editor/public/index.html new file mode 100644 index 0000000..4dcb1cb --- /dev/null +++ b/central-server/apps/topology-editor/public/index.html @@ -0,0 +1,509 @@ + + + + + 拓扑标注助手(GPS → targets.csv) + + + + +

拓扑标注助手

+

+ 与 central 同机运行时:先上传本机 targets.csv,在页面上选设备、补 GPS 或新建后下载 CSV 部署到边缘。与 edge-agent 同机挂载 config 时可直接读写 config/targets.csv。 +

+ +
+ +
+ + + 下载 targets.csv +
+

+
+ +
+ + +
+ +

+ 若是新建设备:先选上面的「(新建设备)」,再填写下列字段。 +

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + + +
+ +
+

地图校验

+
+ + +
+
+ + +
+
+

点击地图可修正坐标;有经纬度后会自动打点并居中。

+
+ + diff --git a/central-server/apps/topology-editor/server.js b/central-server/apps/topology-editor/server.js new file mode 100644 index 0000000..bc9a473 --- /dev/null +++ b/central-server/apps/topology-editor/server.js @@ -0,0 +1,267 @@ +const express = require('express'); +const fs = require('fs'); +const path = require('path'); +const http = require('http'); +const { exec } = require('child_process'); +const multer = require('multer'); + +const app = express(); +const PORT = process.env.PORT || 4080; +const TILE_CACHE_URL = (process.env.TILE_CACHE_URL || '').trim(); + +const ROOT_DIR = path.join(__dirname, '..'); +const CONFIG_DIR = process.env.CONFIG_DIR || null; +const TARGETS_CSV = CONFIG_DIR ? path.join(CONFIG_DIR, 'targets.csv') : null; + +const upload = multer({ storage: multer.memoryStorage() }); + +// 内存模式(与 central-server 一起跑、无挂载时):存一份 targets 的解析结果 +const DEFAULT_HEADER = ['type', 'ip', 'name', 'role', 'parent', 'uplink_type', 'network', 'device_type', 'model', 'location', 'username', 'password', 'onvif_port', 'lat', 'lon']; +let memoryStore = { + comments: ['# 统一监控 + 拓扑目标配置文件\n', '# 格式: type,ip,name,role,parent,uplink_type,...\n'], + header: DEFAULT_HEADER, + rows: [], +}; + +function isFileMode() { + return CONFIG_DIR && TARGETS_CSV && fs.existsSync(TARGETS_CSV); +} + +app.use(express.json()); +app.use(express.static(path.join(__dirname, 'public'))); + +function parseCsv(text) { + const lines = text.split(/\r?\n/); + const comments = []; + let headerLineIndex = -1; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i].trim(); + if (!line || line.startsWith('#')) { + comments.push(lines[i]); + continue; + } + headerLineIndex = i; + break; + } + + if (headerLineIndex === -1) { + return { comments: lines, header: DEFAULT_HEADER, rows: [] }; + } + + const header = lines[headerLineIndex].split(',').map(s => s.trim()); + const rows = []; + + for (let i = headerLineIndex + 1; i < lines.length; i++) { + const raw = lines[i]; + if (!raw || raw.trim().startsWith('#')) continue; + const parts = raw.split(','); + const obj = {}; + header.forEach((h, idx) => { + obj[h] = (parts[idx] || '').trim(); + }); + if (Object.values(obj).every(v => v === '')) continue; + rows.push(obj); + } + + return { comments, header, rows }; +} + +function stringifyCsv(comments, header, rows) { + const lines = []; + if (comments && comments.length) { + lines.push(...comments); + } + if (header && header.length) { + lines.push(header.join(',')); + } + for (const row of rows) { + const line = header.map(h => (row[h] || '').replace(/,/g, ' ')).join(','); + lines.push(line); + } + return lines.join('\n') + '\n'; +} + +function loadTargets() { + if (isFileMode()) { + const text = fs.readFileSync(TARGETS_CSV, 'utf8'); + return parseCsv(text); + } + return { ...memoryStore, rows: [...memoryStore.rows] }; +} + +function saveTargets(parsed) { + if (isFileMode()) { + const text = stringifyCsv(parsed.comments, parsed.header, parsed.rows); + fs.writeFileSync(TARGETS_CSV, text, 'utf8'); + return; + } + memoryStore = { + comments: parsed.comments || memoryStore.comments, + header: parsed.header || memoryStore.header, + rows: parsed.rows || memoryStore.rows, + }; +} + +function rebuildConfigs() { + if (!CONFIG_DIR) return; + const cmd = `cd "${CONFIG_DIR}" && ./update-configs.sh`; + exec(cmd, (err, stdout, stderr) => { + if (err) { + console.error('重建配置失败:', err.message); + if (stderr) console.error(stderr); + return; + } + if (stdout) console.log(stdout); + }); +} + +app.get('/api/targets', (req, res) => { + try { + const parsed = loadTargets(); + res.json(parsed.rows); + } catch (e) { + console.error(e); + res.status(500).json({ error: '读取 targets 失败' }); + } +}); + +app.get('/api/mode', (req, res) => { + res.json({ mode: isFileMode() ? 'file' : 'memory' }); +}); + +app.get('/api/map-config', (req, res) => { + res.json({ cacheBaseUrl: TILE_CACHE_URL ? '/tiles' : '' }); +}); + +function proxyToTileCache(pathname, res) { + const url = TILE_CACHE_URL + pathname; + const u = new URL(url); + const client = u.protocol === 'https:' ? require('https') : require('http'); + client.get(url, (proxyRes) => { + res.status(proxyRes.statusCode || 200); + if (proxyRes.headers['content-type']) res.setHeader('Content-Type', proxyRes.headers['content-type']); + if (proxyRes.headers['cache-control']) res.setHeader('Cache-Control', proxyRes.headers['cache-control']); + proxyRes.pipe(res); + }).on('error', (err) => { + res.status(502).json({ error: 'Tile cache unreachable: ' + err.message }); + }); +} + +app.get('/tiles/vec/:z/:x/:y', (req, res) => { + if (!TILE_CACHE_URL) return res.status(503).send('Tile cache not configured'); + proxyToTileCache(`/vec/${req.params.z}/${req.params.x}/${req.params.y}`, res); +}); + +app.get('/tiles/cva/:z/:x/:y', (req, res) => { + if (!TILE_CACHE_URL) return res.status(503).send('Tile cache not configured'); + proxyToTileCache(`/cva/${req.params.z}/${req.params.x}/${req.params.y}`, res); +}); + +app.get('/api/download', (req, res) => { + try { + const parsed = loadTargets(); + const text = stringifyCsv(parsed.comments, parsed.header, parsed.rows); + res.setHeader('Content-Type', 'text/csv; charset=utf-8'); + res.setHeader('Content-Disposition', 'attachment; filename=targets.csv'); + res.send(text); + } catch (e) { + console.error(e); + res.status(500).json({ error: '生成下载失败' }); + } +}); + +app.post('/api/upload', upload.single('file'), (req, res) => { + try { + if (!req.file || !req.file.buffer) { + return res.status(400).json({ error: '请选择 CSV 文件上传' }); + } + const text = req.file.buffer.toString('utf8'); + const parsed = parseCsv(text); + if (!isFileMode()) { + memoryStore = parsed; + } else { + saveTargets(parsed); + } + res.json({ ok: true, rows: parsed.rows.length }); + } catch (e) { + console.error(e); + res.status(500).json({ error: '解析 CSV 失败' }); + } +}); + +app.post('/api/targets', (req, res) => { + try { + const { + type = '', + ip = '', + name = '', + role = '', + parent = '', + uplink_type = '', + network = '', + device_type = '', + model = '', + location = '', + username = '', + password = '', + onvif_port = '', + lat = '', + lon = '', + } = req.body || {}; + + if (!type || !name) { + return res.status(400).json({ error: 'type 与 name 为必填字段' }); + } + + const parsed = loadTargets(); + const { header, rows } = parsed; + + const idx = rows.findIndex((r) => r.name === name); + const row = {}; + header.forEach((h) => { + row[h] = ''; + }); + + Object.assign(row, { + type, + ip, + name, + role, + parent, + uplink_type, + network, + device_type, + model, + location, + username, + password, + onvif_port, + lat, + lon, + }); + + if (idx >= 0) { + rows[idx] = row; + } else { + rows.push(row); + } + + saveTargets({ ...parsed, rows }); + rebuildConfigs(); + + res.json({ ok: true, row }); + } catch (e) { + console.error(e); + res.status(500).json({ error: '写入失败' }); + } +}); + +app.listen(PORT, '0.0.0.0', () => { + console.log(`Topology editor listening on http://0.0.0.0:${PORT}`); + if (CONFIG_DIR) { + console.log(`CONFIG_DIR=${CONFIG_DIR} (file mode)`); + } else { + console.log('Running in memory mode: use Upload CSV / Download CSV'); + } +}); diff --git a/central-server/alertmanager/alertmanager.yml b/central-server/config/alertmanager/alertmanager.yml similarity index 100% rename from central-server/alertmanager/alertmanager.yml rename to central-server/config/alertmanager/alertmanager.yml diff --git a/central-server/grafana/dashboards/onvif-monitoring.json b/central-server/config/grafana/dashboards/onvif-monitoring.json similarity index 100% rename from central-server/grafana/dashboards/onvif-monitoring.json rename to central-server/config/grafana/dashboards/onvif-monitoring.json diff --git a/central-server/grafana/provisioning/dashboards/dashboard.yml b/central-server/config/grafana/provisioning/dashboards/dashboard.yml similarity index 100% rename from central-server/grafana/provisioning/dashboards/dashboard.yml rename to central-server/config/grafana/provisioning/dashboards/dashboard.yml diff --git a/central-server/grafana/provisioning/datasources/prometheus-admin.yml b/central-server/config/grafana/provisioning/datasources/prometheus-admin.yml similarity index 100% rename from central-server/grafana/provisioning/datasources/prometheus-admin.yml rename to central-server/config/grafana/provisioning/datasources/prometheus-admin.yml diff --git a/central-server/grafana/provisioning/datasources/prometheus.yml b/central-server/config/grafana/provisioning/datasources/prometheus.yml similarity index 100% rename from central-server/grafana/provisioning/datasources/prometheus.yml rename to central-server/config/grafana/provisioning/datasources/prometheus.yml diff --git a/central-server/grafana/provisioning/datasources/victoriametrics.yml b/central-server/config/grafana/provisioning/datasources/victoriametrics.yml similarity index 100% rename from central-server/grafana/provisioning/datasources/victoriametrics.yml rename to central-server/config/grafana/provisioning/datasources/victoriametrics.yml diff --git a/central-server/grafana/setup-users.sh b/central-server/config/grafana/setup-users.sh similarity index 100% rename from central-server/grafana/setup-users.sh rename to central-server/config/grafana/setup-users.sh diff --git a/central-server/alert_rules.yml b/central-server/config/prometheus/alert_rules.yml similarity index 100% rename from central-server/alert_rules.yml rename to central-server/config/prometheus/alert_rules.yml diff --git a/central-server/prometheus.yml b/central-server/config/prometheus/prometheus.yml similarity index 50% rename from central-server/prometheus.yml rename to central-server/config/prometheus/prometheus.yml index 8387282..10e54d5 100644 --- a/central-server/prometheus.yml +++ b/central-server/config/prometheus/prometheus.yml @@ -1,10 +1,25 @@ +# Prometheus 中央服务器配置模板 +# ============================================ +# 说明: +# - 本文件为配置模板,包含 ${变量名} 占位符 +# - 部署时由 deploy.sh 从 .env 读取变量,用 envsubst 生成 prometheus.yml +# - 请勿直接编辑 prometheus.yml,修改应在此模板或 .env 中进行 +# +# 变量来源:central-server/.env(参考 env.example);本文件位于 config/prometheus/ +# 涉及变量:PROMETHEUS_SCRAPE_INTERVAL, PROMETHEUS_EVALUATION_INTERVAL, +# PROMETHEUS_CLUSTER_NAME, VICTORIAMETRICS_PORT, +# PROMETHEUS_REMOTE_WRITE_MAX_SAMPLES, PROMETHEUS_REMOTE_WRITE_CAPACITY, +# PROMETHEUS_REMOTE_WRITE_MAX_SHARDS +# ============================================ + global: scrape_interval: 15s evaluation_interval: 15s external_labels: cluster: 'central-monitoring' -# 远程写入配置 - 接收来自边缘节点的数据 +# 远程写入:将中央 Prometheus 抓取到的本地服务指标推送到 VictoriaMetrics +# (边缘节点由 vmagent 直接 remote_write 到 VictoriaMetrics) remote_write: - url: http://victoria-metrics:8428/api/v1/write queue_config: @@ -12,7 +27,7 @@ remote_write: capacity: 20000 max_shards: 10 -# 抓取配置 - 主要抓取本地服务 +# 抓取配置:仅抓取中央本机 Docker 容器(Prometheus/VM/Alertmanager/Grafana) scrape_configs: # 抓取中央Prometheus自身 - job_name: 'prometheus-central' @@ -40,11 +55,11 @@ scrape_configs: static_configs: - targets: ['grafana:3000'] -# 告警规则配置 +# 告警规则:alert_rules.yml 与 prometheus.yml 同目录 rule_files: - "alert_rules.yml" -# Alertmanager配置 +# Alertmanager:告警路由与静默 alerting: alertmanagers: - static_configs: diff --git a/central-server/prometheus.yml.template b/central-server/config/prometheus/prometheus.yml.template similarity index 56% rename from central-server/prometheus.yml.template rename to central-server/config/prometheus/prometheus.yml.template index ce98e5a..4873590 100644 --- a/central-server/prometheus.yml.template +++ b/central-server/config/prometheus/prometheus.yml.template @@ -1,10 +1,25 @@ +# Prometheus 中央服务器配置模板 +# ============================================ +# 说明: +# - 本文件为配置模板,包含 ${变量名} 占位符 +# - 部署时由 deploy.sh 从 .env 读取变量,用 envsubst 生成 prometheus.yml +# - 请勿直接编辑 prometheus.yml,修改应在此模板或 .env 中进行 +# +# 变量来源:central-server/.env(参考 env.example);本文件位于 config/prometheus/ +# 涉及变量:PROMETHEUS_SCRAPE_INTERVAL, PROMETHEUS_EVALUATION_INTERVAL, +# PROMETHEUS_CLUSTER_NAME, VICTORIAMETRICS_PORT, +# PROMETHEUS_REMOTE_WRITE_MAX_SAMPLES, PROMETHEUS_REMOTE_WRITE_CAPACITY, +# PROMETHEUS_REMOTE_WRITE_MAX_SHARDS +# ============================================ + global: scrape_interval: ${PROMETHEUS_SCRAPE_INTERVAL}s evaluation_interval: ${PROMETHEUS_EVALUATION_INTERVAL}s external_labels: cluster: '${PROMETHEUS_CLUSTER_NAME}' -# 远程写入配置 - 接收来自边缘节点的数据 +# 远程写入:将中央 Prometheus 抓取到的本地服务指标推送到 VictoriaMetrics +# (边缘节点由 vmagent 直接 remote_write 到 VictoriaMetrics) remote_write: - url: http://victoria-metrics:${VICTORIAMETRICS_PORT}/api/v1/write queue_config: @@ -12,7 +27,7 @@ remote_write: capacity: ${PROMETHEUS_REMOTE_WRITE_CAPACITY} max_shards: ${PROMETHEUS_REMOTE_WRITE_MAX_SHARDS} -# 抓取配置 - 主要抓取本地服务 +# 抓取配置:仅抓取中央本机 Docker 容器(Prometheus/VM/Alertmanager/Grafana) scrape_configs: # 抓取中央Prometheus自身 - job_name: 'prometheus-central' @@ -40,11 +55,11 @@ scrape_configs: static_configs: - targets: ['grafana:3000'] -# 告警规则配置 +# 告警规则:alert_rules.yml 与 prometheus.yml 同目录 rule_files: - "alert_rules.yml" -# Alertmanager配置 +# Alertmanager:告警路由与静默 alerting: alertmanagers: - static_configs: diff --git a/central-server/deploy.sh b/central-server/deploy.sh index e98dabd..2414363 100644 --- a/central-server/deploy.sh +++ b/central-server/deploy.sh @@ -45,6 +45,36 @@ PROMETHEUS_REMOTE_WRITE_CAPACITY=${PROMETHEUS_REMOTE_WRITE_CAPACITY:-20000} PROMETHEUS_REMOTE_WRITE_MAX_SHARDS=${PROMETHEUS_REMOTE_WRITE_MAX_SHARDS:-10} GRAFANA_DEFAULT_LANGUAGE=${GRAFANA_DEFAULT_LANGUAGE:-zh-Hans} GRAFANA_DEFAULT_THEME=${GRAFANA_DEFAULT_THEME:-light} +TRAEFIK_PROVIDER=${TRAEFIK_PROVIDER:-external} + +# 根据 TRAEFIK_ENABLED 与 TRAEFIK_PROVIDER 设置网络 +if [ "${TRAEFIK_ENABLED:-false}" = "true" ]; then + case "${TRAEFIK_PROVIDER}" in + internal) + export NETWORK_NAME=${NETWORK_NAME:-central_default} + export EXTERNAL_NETWORK=${EXTERNAL_NETWORK:-false} + export TRAEFIK_NETWORK=${TRAEFIK_NETWORK:-central_default} + export COMPOSE_PROFILES="${COMPOSE_PROFILES:-},traefik-internal" + export COMPOSE_PROFILES="${COMPOSE_PROFILES#,}" + ;; + external) + export NETWORK_NAME=${NETWORK_NAME:-traefik} + export EXTERNAL_NETWORK=${EXTERNAL_NETWORK:-true} + export TRAEFIK_NETWORK=${TRAEFIK_NETWORK:-traefik} + ;; + *) + echo "⚠️ TRAEFIK_PROVIDER 应为 internal 或 external,当前为 ${TRAEFIK_PROVIDER}" + export NETWORK_NAME=${NETWORK_NAME:-traefik} + export EXTERNAL_NETWORK=${EXTERNAL_NETWORK:-true} + export TRAEFIK_NETWORK=${TRAEFIK_NETWORK:-traefik} + ;; + esac +else + # 不使用 Traefik:使用 compose 默认网络,直连端口访问 + export NETWORK_NAME=${NETWORK_NAME:-central_default} + export EXTERNAL_NETWORK=${EXTERNAL_NETWORK:-false} + export TRAEFIK_NETWORK=${TRAEFIK_NETWORK:-central_default} +fi # 将相对路径转换为绝对路径(Docker 需要绝对路径) # 获取脚本所在目录的绝对路径 @@ -140,12 +170,12 @@ fi echo "" # 从模板生成 prometheus.yml -if [ -f "prometheus.yml.template" ]; then - echo "📝 从模板生成 prometheus.yml..." +if [ -f "config/prometheus/prometheus.yml.template" ]; then + echo "📝 从模板生成 config/prometheus/prometheus.yml..." # 检查是否有 envsubst 命令 if command -v envsubst &> /dev/null; then - envsubst < prometheus.yml.template > prometheus.yml - echo "✅ prometheus.yml 已生成" + envsubst < config/prometheus/prometheus.yml.template > config/prometheus/prometheus.yml + echo "✅ config/prometheus/prometheus.yml 已生成" else echo "⚠️ envsubst 命令未找到,尝试使用 sed 替换..." # 使用 sed 进行简单的变量替换 @@ -156,22 +186,22 @@ if [ -f "prometheus.yml.template" ]; then -e "s/\${PROMETHEUS_REMOTE_WRITE_MAX_SAMPLES}/${PROMETHEUS_REMOTE_WRITE_MAX_SAMPLES}/g" \ -e "s/\${PROMETHEUS_REMOTE_WRITE_CAPACITY}/${PROMETHEUS_REMOTE_WRITE_CAPACITY}/g" \ -e "s/\${PROMETHEUS_REMOTE_WRITE_MAX_SHARDS}/${PROMETHEUS_REMOTE_WRITE_MAX_SHARDS}/g" \ - prometheus.yml.template > prometheus.yml - echo "✅ prometheus.yml 已生成(使用 sed)" + config/prometheus/prometheus.yml.template > config/prometheus/prometheus.yml + echo "✅ config/prometheus/prometheus.yml 已生成(使用 sed)" fi -elif [ ! -f "prometheus.yml" ]; then - echo "❌ 配置文件 prometheus.yml 不存在,且未找到模板文件" +elif [ ! -f "config/prometheus/prometheus.yml" ]; then + echo "❌ 配置文件 config/prometheus/prometheus.yml 不存在,且未找到模板文件" exit 1 fi # 检查配置文件 -if [ ! -f "alert_rules.yml" ]; then - echo "❌ 配置文件 alert_rules.yml 不存在" +if [ ! -f "config/prometheus/alert_rules.yml" ]; then + echo "❌ 配置文件 config/prometheus/alert_rules.yml 不存在" exit 1 fi -if [ ! -f "alertmanager/alertmanager.yml" ]; then - echo "❌ 配置文件 alertmanager/alertmanager.yml 不存在" +if [ ! -f "config/alertmanager/alertmanager.yml" ]; then + echo "❌ 配置文件 config/alertmanager/alertmanager.yml 不存在" exit 1 fi @@ -199,18 +229,23 @@ export GRAFANA_DOMAIN export PROMETHEUS_DOMAIN export ALERTMANAGER_DOMAIN -# 检查 Traefik 网络(docker-compose.yml 中总是会引用此网络,无论是否启用) +# 检查 Traefik 网络(仅 TRAEFIK_PROVIDER=external 时需已存在) echo "🔍 检查 Traefik 网络..." TRAEFIK_NET=${TRAEFIK_NETWORK:-traefik} -if ! docker network inspect "$TRAEFIK_NET" &> /dev/null; then +if [ "${TRAEFIK_ENABLED:-false}" != "true" ]; then + echo "✅ 未启用 Traefik,使用 compose 默认网络" +elif [ "${TRAEFIK_PROVIDER}" = "internal" ]; then + echo "✅ 本编排启动 Traefik,将自动创建网络 $TRAEFIK_NET" +elif ! docker network inspect "$TRAEFIK_NET" &> /dev/null; then echo "⚠️ Traefik 网络 '$TRAEFIK_NET' 不存在,正在创建..." if docker network create "$TRAEFIK_NET" 2>/dev/null; then echo "✅ Traefik 网络 '$TRAEFIK_NET' 已创建" else echo "❌ 无法创建 Traefik 网络 '$TRAEFIK_NET'" echo " 请确保:" - echo " 1. Traefik 已运行并创建了网络" - echo " 2. 或手动创建网络: docker network create $TRAEFIK_NET" + echo " 1. 外部 Traefik 已运行并创建了网络" + echo " 2. 或改为 TRAEFIK_PROVIDER=internal 由本编排启动 Traefik" + echo " 3. 或手动创建网络: docker network create $TRAEFIK_NET" echo "" read -p "是否继续部署?(y/N): " -n 1 -r echo @@ -220,7 +255,7 @@ if ! docker network inspect "$TRAEFIK_NET" &> /dev/null; then fi fi else - echo "✅ Traefik 网络 '$TRAEFIK_NET' 已存在" + echo "✅ Traefik 网络 '$TRAEFIK_NET' 已存在(外部 Traefik)" fi echo "" @@ -229,9 +264,9 @@ echo "📁 创建数据目录..." mkdir -p "${PROMETHEUS_DATA_DIR}" mkdir -p "${GRAFANA_DATA_DIR}" mkdir -p "${VICTORIAMETRICS_DATA_DIR}" -mkdir -p grafana/dashboards -mkdir -p grafana/provisioning/datasources -mkdir -p grafana/provisioning/dashboards +mkdir -p config/grafana/dashboards +mkdir -p config/grafana/provisioning/datasources +mkdir -p config/grafana/provisioning/dashboards # 设置目录权限 # Prometheus 需要写权限 @@ -293,15 +328,17 @@ echo "" # 检查是否启用 Traefik if [ "${TRAEFIK_ENABLED:-false}" = "true" ]; then echo "🔗 访问地址(通过 Traefik 反向代理):" + if [ "${TRAEFIK_PROVIDER}" = "internal" ]; then + echo " - Traefik 由本编排启动,监听 80/443 端口" + fi echo " - Grafana仪表板: http://${GRAFANA_DOMAIN:-grafana.example.com} (admin/${GRAFANA_ADMIN_PASSWORD}) [${GRAFANA_DEFAULT_LANGUAGE}界面]" echo " - Prometheus: http://${PROMETHEUS_DOMAIN:-prometheus.example.com} [英文界面]" echo " - Alertmanager: http://${ALERTMANAGER_DOMAIN:-alertmanager.example.com} [英文界面]" echo " - VictoriaMetrics: http://localhost:${VICTORIAMETRICS_PORT} [英文界面,边缘节点直接连接]" echo "" echo "⚠️ 请确保:" - echo " 1. DNS 已正确解析域名到 Traefik 服务器" - echo " 2. Traefik 网络 (${TRAEFIK_NETWORK:-traefik_default}) 已创建" - echo " 3. 边缘节点可以访问此服务器的${VICTORIAMETRICS_PORT}端口(VictoriaMetrics 不通过 Traefik)" + echo " 1. DNS 已正确解析域名到本机" + echo " 2. 边缘节点可以访问此服务器的${VICTORIAMETRICS_PORT}端口(VictoriaMetrics 不通过 Traefik)" else echo "🔗 访问地址:" echo " - Grafana仪表板: http://localhost:${GRAFANA_PORT} (admin/${GRAFANA_ADMIN_PASSWORD}) [${GRAFANA_DEFAULT_LANGUAGE}界面]" diff --git a/central-server/docker-compose.yml b/central-server/docker-compose.yml index 6f2950f..e7a60fc 100644 --- a/central-server/docker-compose.yml +++ b/central-server/docker-compose.yml @@ -4,12 +4,13 @@ services: image: prom/prometheus:latest container_name: prometheus-central restart: unless-stopped + mem_limit: "128m" ports: - "${PROMETHEUS_PORT:-9091}:9090" volumes: - ${PROMETHEUS_DATA_DIR:-./data/prometheus-data}:/prometheus - - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro - - ./alert_rules.yml:/etc/prometheus/alert_rules.yml:ro + - ./config/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - ./config/prometheus/alert_rules.yml:/etc/prometheus/alert_rules.yml:ro command: - '--config.file=/etc/prometheus/prometheus.yml' - "--storage.tsdb.retention.time=${PROMETHEUS_RETENTION_TIME:-30d}" @@ -29,6 +30,7 @@ services: image: grafana/grafana:latest container_name: grafana restart: unless-stopped + mem_limit: "128m" ports: - "${GRAFANA_PORT:-3000}:3000" environment: @@ -41,8 +43,8 @@ services: - GF_SERVER_ROOT_URL=${GRAFANA_ROOT_URL:-http://localhost:3000} volumes: - ${GRAFANA_DATA_DIR:-./data/grafana-data}:/var/lib/grafana - - ./grafana/provisioning:/etc/grafana/provisioning - - ./grafana/dashboards:/var/lib/grafana/dashboards + - ./config/grafana/provisioning:/etc/grafana/provisioning + - ./config/grafana/dashboards:/var/lib/grafana/dashboards labels: - "traefik.enable=${TRAEFIK_ENABLED:-true}" - "traefik.http.routers.grafana.rule=Host(`${GRAFANA_DOMAIN:-grafana.example.com}`)" @@ -56,10 +58,11 @@ services: image: prom/alertmanager:latest container_name: alertmanager restart: unless-stopped + mem_limit: "32m" ports: - "${ALERTMANAGER_PORT:-9093}:9093" volumes: - - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro + - ./config/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro labels: - "traefik.enable=${TRAEFIK_ENABLED:-true}" - "traefik.http.routers.alertmanager.rule=Host(`${ALERTMANAGER_DOMAIN:-alertmanager.example.com}`)" @@ -73,6 +76,7 @@ services: image: victoriametrics/victoria-metrics:latest container_name: victoria-metrics restart: unless-stopped + mem_limit: "64m" ports: - "${VICTORIAMETRICS_PORT:-8428}:8428" volumes: @@ -82,11 +86,47 @@ services: - "--retentionPeriod=${VICTORIAMETRICS_RETENTION_PERIOD:-30d}" - "--httpListenAddr=:${VICTORIAMETRICS_PORT:-8428}" + # GPS 标注助手(上传/下载 targets.csv,H5 采集 GPS + 天地图校验) + topology-editor: + build: + context: . + dockerfile: apps/topology-editor/Dockerfile + image: topology-editor:local + container_name: topology-editor + restart: unless-stopped + environment: + - PORT=4080 + - TILE_CACHE_URL=http://tile-cache:4090 + ports: + - "${TOPOLOGY_EDITOR_PORT:-4080}:4080" + mem_limit: "128m" + + # Traefik 反向代理(仅 TRAEFIK_PROVIDER=internal 时启动) + traefik: + image: traefik:v2.10 + container_name: traefik-central + restart: unless-stopped + profiles: + - traefik-internal + command: + - "--api.insecure=true" + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--providers.docker.network=${TRAEFIK_NETWORK:-central_default}" + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" + ports: + - "${TRAEFIK_HTTP_PORT:-80}:80" + - "${TRAEFIK_HTTPS_PORT:-443}:443" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + mem_limit: "64m" + # 天地图瓦片缓存(节省 key 免费量;可手动清空缓存后重新拉取) tile-cache: build: - context: .. - dockerfile: tile-cache/Dockerfile + context: . + dockerfile: apps/tile-cache/Dockerfile image: tile-cache:local container_name: tile-cache restart: unless-stopped @@ -100,7 +140,7 @@ services: - ${TILE_CACHE_DATA_DIR:-./data/tile-cache}:/cache ports: - "${TILE_CACHE_PORT:-4090}:4090" - mem_limit: "128m" + mem_limit: "32m" # 定义网络配置(默认使用已存在的 traefik 网络) diff --git a/central-server/env.example b/central-server/env.example index b2b394d..4b4acb0 100644 --- a/central-server/env.example +++ b/central-server/env.example @@ -1,55 +1,85 @@ -# 中央服务器环境变量配置 -# 复制此文件为 .env 并根据实际情况修改 +# ============================================================================= +# 中央服务器环境变量配置模板 +# ============================================================================= +# +# 【用途】 +# 本文件为 central-server 所有可配置参数的模板,供 deploy.sh 和 docker-compose 使用。 +# 部署脚本 deploy.sh 会读取 .env,并将部分变量代入 prometheus.yml.template 生成 prometheus.yml。 +# +# 【使用方式】 +# 1. 复制为 .env: cp env.example .env +# 2. 编辑 .env,按实际环境修改参数 +# 3. 运行部署脚本: ./deploy.sh +# +# 若不存在 .env,deploy.sh 会自动从 env.example 创建,并提示修改后重试。 +# +# 【变量去向】 +# - deploy.sh:加载 .env,生成 prometheus.yml,创建数据目录,启动 docker-compose +# - docker-compose:端口、数据目录、容器环境变量、Traefik 标签等 +# - prometheus.yml.template:PROMETHEUS_*、VICTORIAMETRICS_PORT 等(见模板头部) +# +# 【修改生效】 +# 修改 .env 后需重新运行 ./deploy.sh。不要直接编辑 prometheus.yml,其由模板生成。 +# +# ============================================================================= # ============================================ # 端口配置 # ============================================ +# 宿主机映射端口,对应各服务容器内端口。端口冲突时修改此处。 -# Prometheus 端口(避免与 cockpit 冲突) +# Prometheus Web UI 端口(避免与 cockpit 9090 冲突,故默认 9091) +# 访问:http://localhost:${PROMETHEUS_PORT} PROMETHEUS_PORT=9091 -# Grafana 端口 +# Grafana Web UI 端口 +# 访问:http://localhost:${GRAFANA_PORT} GRAFANA_PORT=3000 -# Alertmanager 端口 +# Alertmanager Web UI 端口 ALERTMANAGER_PORT=9093 -# VictoriaMetrics 端口(边缘节点推送数据到此端口) +# VictoriaMetrics 端口(边缘 vmagent 通过 remote_write 推送到此端口) +# 必须与边缘侧 CENTRAL_VM_URL 中的端口一致;通常不通过 Traefik,边缘直连 VICTORIAMETRICS_PORT=8428 # ============================================ # Grafana 配置 # ============================================ -# Grafana 管理员密码 +# Grafana 管理员密码(生产环境必须修改,建议 12 位以上强密码) GRAFANA_ADMIN_PASSWORD=admin123 -# Grafana 默认语言 +# Grafana 默认语言:zh-Hans 简体中文,en 英文 GRAFANA_DEFAULT_LANGUAGE=zh-Hans -# Grafana 默认主题 +# Grafana 默认主题:light 浅色,dark 深色 GRAFANA_DEFAULT_THEME=light -# Grafana 根 URL(用于 Traefik 反向代理,如果使用 Traefik,设置为 https://grafana.example.com) +# Grafana 根 URL(使用 Traefik 时设为对外访问地址,如 https://grafana.example.com) +# 影响登录跳转、OAuth 回调等 GRAFANA_ROOT_URL=http://localhost:3000 # ============================================ # Prometheus 配置 # ============================================ +# 部分变量会代入 prometheus.yml.template 生成 prometheus.yml -# Prometheus 数据保留时间 +# Prometheus 本地 TSDB 数据保留时间(如 30d、7d、1y) PROMETHEUS_RETENTION_TIME=30d -# Prometheus 抓取间隔(秒) +# 抓取间隔(秒),影响中央 Prometheus 抓取本机服务的频率 +# 建议 15–60;越小越实时,负载越高 PROMETHEUS_SCRAPE_INTERVAL=15 -# Prometheus 告警评估间隔(秒) +# 告警规则评估间隔(秒) PROMETHEUS_EVALUATION_INTERVAL=15 -# Prometheus 集群标识 +# 集群标识,作为 external_labels 中的 cluster 标签,用于区分多集群 PROMETHEUS_CLUSTER_NAME=central-monitoring -# 远程写入队列配置 +# remote_write 到 VictoriaMetrics 的队列参数(中央 Prometheus 将抓取数据推送到 VM) +# 边缘写入量大时可适当调大;一般保持默认即可 PROMETHEUS_REMOTE_WRITE_MAX_SAMPLES=10000 PROMETHEUS_REMOTE_WRITE_CAPACITY=20000 PROMETHEUS_REMOTE_WRITE_MAX_SHARDS=10 @@ -57,81 +87,83 @@ PROMETHEUS_REMOTE_WRITE_MAX_SHARDS=10 # ============================================ # VictoriaMetrics 配置 # ============================================ +# VM 接收边缘 remote_write 并存储;Grafana 数据源通常指向 VM -# VictoriaMetrics 数据保留时间 +# VM 数据保留时间(如 30d、90d) VICTORIAMETRICS_RETENTION_PERIOD=30d # ============================================ # 数据存储路径 # ============================================ +# 相对于 central-server 目录;deploy.sh 会转换为绝对路径供 Docker 使用 -# 数据存储根目录(所有数据存储在此目录下,相对于 central-server 目录) -# 使用相对路径,数据将存储在 central-server 目录下的 data 子目录中 +# 数据存储根目录(可选,部分脚本可能引用) DATA_STORAGE_ROOT=./data -# Prometheus 数据目录 +# Prometheus 本地 TSDB 数据目录 PROMETHEUS_DATA_DIR=./data/prometheus-data -# Grafana 数据目录 +# Grafana 数据库与插件数据目录 GRAFANA_DATA_DIR=./data/grafana-data -# VictoriaMetrics 数据目录 +# VictoriaMetrics 时序数据目录 VICTORIAMETRICS_DATA_DIR=./data/victoria-metrics-data -# 天地图瓦片缓存(密钥与缓存参数均在 .env 中配置) -# 在 .env 中设置 TIANDITU_TK 后,tile-cache 与拓扑助手「使用服务器缓存」、Grafana Geomap 方可使用天地图 +# 天地图瓦片缓存(供 topology-editor、Grafana Geomap 使用) +# 在 .env 中设置 TIANDITU_TK 后,tile-cache 才可正常工作 # TIANDITU_TK=您的天地图密钥 # TILE_CACHE_PORT=4090 # TILE_CACHE_DATA_DIR=./data/tile-cache -# 缓存老化时间(天),超过后该瓦片下次请求时会重新向天地图拉取;默认 7,可改为 15 等 # TILE_CACHE_TTL_DAYS=7 -# 向天地图请求单瓦片超时(毫秒),默认 15000;网络或上游慢时可适当调大 # TILE_CACHE_UPSTREAM_TIMEOUT_MS=15000 # ============================================ # Traefik 反向代理配置 # ============================================ +# 启用后,docker-compose 会为各服务添加 Traefik 标签,通过域名访问 -# 是否启用 Traefik 反向代理(true/false) -# 如果启用,服务将通过 Traefik 访问,不再直接暴露端口 +# 是否启用 Traefik(true/false)。为 false 时通过宿主机端口直接访问 TRAEFIK_ENABLED=true -# Traefik 网络名称(通常为 traefik) +# Traefik 来源:internal=本编排启动 Traefik(包含 traefik 服务);external=使用已有外部 Traefik +# internal:本 compose 内启动 Traefik,自动创建网络,无需外部 Traefik +# external:接入已有 Traefik,需 traefik 网络已存在(如单独部署的 Traefik) +TRAEFIK_PROVIDER=external + +# Traefik 所在 Docker 网络名称 +# external 时通常为 traefik;internal 时为 central_default(compose 自动创建) TRAEFIK_NETWORK=traefik -# 域名配置(需要配置 DNS 解析到 Traefik 服务器) -# Grafana 域名 +# 域名(需 DNS 解析到 Traefik 所在机器) GRAFANA_DOMAIN=grafana.example.com - -# Prometheus 域名 PROMETHEUS_DOMAIN=prometheus.example.com - -# Alertmanager 域名 ALERTMANAGER_DOMAIN=alertmanager.example.com - -# VictoriaMetrics 域名(通常不需要通过 Traefik 访问,边缘节点直接连接) VICTORIAMETRICS_DOMAIN=vm.example.com -# Traefik EntryPoint(通常为 web 或 websecure) +# Traefik EntryPoint(web=80, websecure=443) TRAEFIK_ENTRYPOINT=web -# 是否启用 HTTPS(需要配置 Traefik 的 TLS) +# 是否启用 HTTPS(需 Traefik 配置 TLS) TRAEFIK_HTTPS_ENABLED=false +# TRAEFIK_PROVIDER=internal 时,Traefik 监听的宿主机端口 +# TRAEFIK_HTTP_PORT=80 +# TRAEFIK_HTTPS_PORT=443 + # ============================================ # Docker 网络配置 # ============================================ +# 由 TRAEFIK_PROVIDER 决定;一般无需手动改,deploy.sh 会自动设置 -# Compose 项目名称(用于区分同一目录下的多套部署,避免与旧状态冲突) +# Compose 项目名称,用于区分同一目录多套部署 COMPOSE_PROJECT_NAME=central -# 使用已存在的 traefik 网络(由 Traefik 创建,不在此项目中创建) -# 保持以下两项即可接入现有 Traefik +# TRAEFIK_PROVIDER=external 时: NETWORK_NAME=traefik EXTERNAL_NETWORK=true -# 仅在不使用 Traefik、仅本地直连时改为: -# NETWORK_NAME=central-server_default +# TRAEFIK_PROVIDER=internal 时(deploy.sh 会自动改为): +# NETWORK_NAME=central_default # EXTERNAL_NETWORK=false # 是否启用 IPv6(true/false) diff --git a/doc/ALERTING.md b/doc/ALERTING.md index 452c000..e926985 100644 --- a/doc/ALERTING.md +++ b/doc/ALERTING.md @@ -6,7 +6,7 @@ ## 告警规则(alert_rules.yml) -中央已内置 `central-server/alert_rules.yml`,主要包含: +中央已内置 `central-server/config/prometheus/alert_rules.yml`,主要包含: | 规则 | 条件 | 说明 | |------|------|------| @@ -16,13 +16,13 @@ **为何显示 Inactive**:规则依赖边缘推送的指标。需先部署边缘、配置 Ping/ONVIF 目标,数据经 remote_write 到 VictoriaMetrics 后,规则才会评估;无数据时保持 inactive。 -**激活步骤**:完成 [README.md#第二步](README.md) 边缘部署 → 在 Grafana 选 VictoriaMetrics 数据源确认有 `probe_success{job="network-ping"}` 等 → Prometheus 会从 VictoriaMetrics 取数并评估规则。 +**激活步骤**:完成边缘部署(见 [README](README.md)、[DEPLOYMENT_GUIDE](DEPLOYMENT_GUIDE.md))→ 在 Grafana 选 VictoriaMetrics 数据源确认有 `probe_success{job="network-ping"}` 等 → Prometheus 会从 VictoriaMetrics 取数并评估规则。 --- ## Alertmanager 配置(alertmanager.yml) -路径:`central-server/alertmanager/alertmanager.yml`。 +路径:`central-server/config/alertmanager/alertmanager.yml`。 - **route**:分组(group_by)、等待时间(group_wait)、重复间隔(repeat_interval)、默认接收器(receiver)。 - **receivers**:当前示例为 webhook `http://127.0.0.1:5001/`。 @@ -37,7 +37,7 @@ ## 自定义告警规则 -在 `alert_rules.yml` 中追加或修改规则,例如: +在 `config/prometheus/alert_rules.yml` 中追加或修改规则,例如: ```yaml - alert: ExampleAlert diff --git a/doc/ARCHITECTURE.md b/doc/ARCHITECTURE.md index bc4de82..2e03677 100644 --- a/doc/ARCHITECTURE.md +++ b/doc/ARCHITECTURE.md @@ -3,78 +3,22 @@ ## 容器关系图 ``` -┌─────────────────────────────────────────────────────────────────┐ -│ 边缘节点 (Edge Agents) │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ │ Edge Node 1 │ │ Edge Node 2 │ │ Edge Node N │ │ -│ │ │ │ │ │ │ │ -│ │ Prometheus │ │ Prometheus │ │ Prometheus │ │ -│ │ Edge │ │ Edge │ │ Edge │ │ -│ │ │ │ │ │ │ │ -│ │ ONVIF │ │ ONVIF │ │ ONVIF │ │ -│ │ Exporter │ │ Exporter │ │ Exporter │ │ -│ │ │ │ │ │ │ │ -│ │ Blackbox │ │ Blackbox │ │ Blackbox │ │ -│ │ Exporter │ │ Exporter │ │ Exporter │ │ -│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ -│ │ │ │ │ -│ └──────────────────┼──────────────────┘ │ -│ │ │ -│ remote_write │ -│ (HTTP POST) │ -└────────────────────────────┼────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────┐ -│ 中央服务器 (Central Server) │ -│ │ -│ ┌──────────────────────────────────────────────────────────┐ │ -│ │ VictoriaMetrics (8428) │ │ -│ │ ┌────────────────────────────────────────────────────┐ │ │ -│ │ │ 远程写入接收器 │ │ │ -│ │ │ - 接收边缘节点推送的指标数据 │ │ │ -│ │ │ - 存储时序数据 │ │ │ -│ │ │ - 提供查询接口 │ │ │ -│ │ └────────────────────────────────────────────────────┘ │ │ -│ └────────────────────┬───────────────────────────────────────┘ │ -│ │ │ -│ │ 数据查询 │ -│ │ │ -│ ┌────────────────────▼───────────────────────────────────────┐ │ -│ │ Prometheus Central (9091) │ │ -│ │ ┌────────────────────────────────────────────────────┐ │ │ -│ │ │ 指标收集和查询引擎 │ │ │ -│ │ │ - 从 VictoriaMetrics 读取数据 │ │ │ -│ │ │ - 抓取本地服务指标 (自身、Grafana、Alertmanager) │ │ │ -│ │ │ - 评估告警规则 │ │ │ -│ │ │ - 提供 PromQL 查询接口 │ │ │ -│ │ └────────────────────────────────────────────────────┘ │ │ -│ └────────────┬───────────────────────────┬───────────────────┘ │ -│ │ │ │ -│ │ 告警触发 │ 数据查询 │ -│ │ │ │ -│ ┌────────────▼──────────┐ ┌─────────────▼──────────────┐ │ -│ │ Alertmanager (9093) │ │ Grafana (3000) │ │ -│ │ ┌──────────────────┐ │ │ ┌──────────────────────┐ │ │ -│ │ │ 告警管理 │ │ │ │ 可视化仪表板 │ │ │ -│ │ │ - 接收告警 │ │ │ │ - 从 Prometheus 查询 │ │ │ -│ │ │ - 告警分组 │ │ │ │ - 创建图表和仪表板 │ │ │ -│ │ │ - 发送通知 │ │ │ │ - 多用户管理 │ │ │ -│ │ │ - 告警抑制 │ │ │ │ - 中文界面 │ │ │ -│ │ └──────────────────┘ │ │ └──────────────────────┘ │ │ -│ └───────────────────────┘ │ └──────────────────────────┘ │ -│ │ │ -└──────────────────────────────┼──────────────────────────────────┘ - │ - │ HTTP 访问 - │ - ┌───────────────┼───────────────┐ - │ │ │ - ▼ ▼ ▼ - ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ - │ 管理员 │ │ 用户组A │ │ 用户组B │ - │ (Admin) │ │ (Org A) │ │ (Org B) │ - └─────────────┘ └─────────────┘ └─────────────┘ +┌─ 边缘节点 (Edge Node 1/2/…/N) ─────────────────┐ +│ vmagent | ONVIF Exporter | Blackbox Exporter │ +└──────────────────┬────────────────────────────┘ + │ remote_write (HTTP POST) + ▼ +┌─ 中央服务器 ───────────────────────────────────┐ +│ VictoriaMetrics (8428) 接收边缘推送、存储 │ +│ │ 数据查询 │ +│ ▼ │ +│ Prometheus (9091) 抓取本地、告警评估 │ +│ ├── 告警 ──> Alertmanager (9093) │ +│ └── 查询 ──> Grafana (3000) │ +└──────────────────┬─────────────────────────────┘ + │ HTTP 访问 + ▼ + 管理员 / 用户组A / 用户组B ``` ## 数据流向 @@ -173,19 +117,11 @@ Alertmanager 处理告警 ## 网络关系 ``` -monitoring_net (Docker Bridge Network) -│ -├─ prometheus-central:9090 (内部) -│ └─> 映射到宿主机:9091 -│ -├─ grafana:3000 (内部) -│ └─> 映射到宿主机:3000 -│ -├─ alertmanager:9093 (内部) -│ └─> 映射到宿主机:9093 -│ -└─ victoria-metrics:8428 (内部) - └─> 映射到宿主机:8428 +monitoring_net (Docker Bridge) +├─ prometheus-central:9090 -> 宿主机 9091 +├─ grafana:3000 -> 宿主机 3000 +├─ alertmanager:9093 -> 宿主机 9093 +└─ victoria-metrics:8428 -> 宿主机 8428 ``` ## 端口映射 @@ -199,25 +135,19 @@ monitoring_net (Docker Bridge Network) ## 数据存储 -所有数据存储在 `/storage` 分区: - ``` -/storage/ +central-server/data/ ├── prometheus-data/ # Prometheus 时序数据 -├── grafana-data/ # Grafana 配置和仪表板 -├── victoria-metrics-data/ # VictoriaMetrics 时序数据 -└── docker/ # Docker 数据 +├── grafana-data/ # Grafana 配置与仪表板 +└── victoria-metrics-data/ # VictoriaMetrics 时序数据 ``` ## 依赖关系 ``` -VictoriaMetrics - ↑ (数据查询) - │ -Prometheus - ├─> (告警触发) ──> Alertmanager - └─> (数据查询) ──> Grafana +VictoriaMetrics <── Prometheus + ├─ 告警 ──> Alertmanager + └─ 查询 ──> Grafana ``` **启动顺序**: diff --git a/doc/BEST_PRACTICES.md b/doc/BEST_PRACTICES.md index 6f51e45..98cd9d2 100644 --- a/doc/BEST_PRACTICES.md +++ b/doc/BEST_PRACTICES.md @@ -164,11 +164,8 @@ firewall-cmd --reload ```bash # 备份所有配置文件 tar -czf config-backup-$(date +%Y%m%d).tar.gz \ - central-server/*.yml \ - central-server/alertmanager/*.yml \ - central-server/grafana/provisioning/ \ - edge-agent/*.yml \ - edge-agent/prometheus-edge/*.yml + central-server/config/ \ + edge-agent/config/ ``` #### 数据备份 diff --git a/doc/CENTRAL_SERVER_CONFIG.md b/doc/CENTRAL_SERVER_CONFIG.md index b919f94..57eefd3 100644 --- a/doc/CENTRAL_SERVER_CONFIG.md +++ b/doc/CENTRAL_SERVER_CONFIG.md @@ -6,13 +6,14 @@ central-server/ ├── docker-compose.yml # 服务编排 ├── deploy.sh # 部署脚本 -├── prometheus.yml # Prometheus 主配置 -├── alert_rules.yml # 告警规则 -├── alertmanager/alertmanager.yml -└── grafana/ - ├── setup-users.sh - ├── provisioning/datasources/ # prometheus.yml, victoriametrics.yml - └── dashboards/ +├── config/ # 配置目录 +│ ├── prometheus/ # Prometheus 配置(prometheus.yml、alert_rules.yml) +│ ├── alertmanager/ # Alertmanager 配置 +│ └── grafana/ # Grafana 配置(provisioning、dashboards) +├── apps/ # 自建应用源码 +│ ├── tile-cache/ # 天地图瓦片缓存 +│ └── topology-editor/ # GPS 标注助手 +└── data/ # 运行时数据(gitignore) ``` ## 主要服务与端口 @@ -26,16 +27,16 @@ central-server/ ## 关键配置摘要 -- **prometheus.yml**:`remote_write` 指向 VictoriaMetrics;`rule_files: alert_rules.yml`;抓取自身、VM、Alertmanager、Grafana。 +- **config/prometheus/prometheus.yml**:`remote_write` 指向 VictoriaMetrics;`rule_files: alert_rules.yml`;抓取自身、VM、Alertmanager、Grafana。 - **告警规则与通知**:见 [ALERTING.md](ALERTING.md)。 - **Grafana 数据源**:Provisioning 下配置 Prometheus、VictoriaMetrics;查边缘指标请选 **VictoriaMetrics**。 - **Grafana Geomap 使用天地图缓存**:在 Geomap 面板中将 Base layer 选为 **XYZ Tile layer**,底图 URL 填 `http://:4090/tiles/vec/{z}/{x}/{y}`,再添加一层 XYZ 填 `http://:4090/tiles/cva/{z}/{x}/{y}`(中文注记)。key 仅需在 central 配置 `TIANDITU_TK`,无需在 Grafana 中填写。详见 [TIANDITU_CONFIG.md](TIANDITU_CONFIG.md)。 -- **多用户**:`grafana/setup-users.sh`,见 [USER_MANAGEMENT.md](USER_MANAGEMENT.md)。 +- **多用户**:`config/grafana/setup-users.sh`,见 [USER_MANAGEMENT.md](USER_MANAGEMENT.md)。 ## 修改与重载 -- Prometheus:改 `prometheus.yml` 或 `alert_rules.yml` 后 `docker compose restart prometheus-central`,或 `curl -X POST http://localhost:9091/-/reload`(若启用 lifecycle)。 -- Alertmanager:改 `alertmanager/alertmanager.yml` 后 `docker compose restart alertmanager`。 +- Prometheus:改 `config/prometheus/prometheus.yml` 或 `config/prometheus/alert_rules.yml` 后 `docker compose restart prometheus-central`,或 `curl -X POST http://localhost:9091/-/reload`(若启用 lifecycle)。 +- Alertmanager:改 `config/alertmanager/alertmanager.yml` 后 `docker compose restart alertmanager`。 - Grafana:改 provisioning 后重启;或通过 Web UI 修改(持久化到库)。 ## 相关文档 diff --git a/doc/DEPLOYMENT_GUIDE.md b/doc/DEPLOYMENT_GUIDE.md index a70210b..77a258a 100644 --- a/doc/DEPLOYMENT_GUIDE.md +++ b/doc/DEPLOYMENT_GUIDE.md @@ -1,21 +1,23 @@ # 部署指南 -部署顺序见 **[doc/README.md](README.md)#部署顺序**:中央 → 边缘 → 多用户/告警(可选)。本文为各步操作与验证要点。 +部署顺序:中央 → 边缘 → 多用户/告警(可选)。详见 [README](README.md)。 --- ## 第一步:部署中央服务器 -**前置**:Docker、Docker Compose;端口 3000、9091、8428、9093、4090 未被占用;磁盘充足。 +**前置**:Docker、Docker Compose;端口 3000、9091、8428、9093 未被占用;磁盘充足。 ```bash cd central-server -cp env.example .env # 可选 +cp env.example .env # 可选,按需改端口、Traefik 等 bash deploy.sh ``` **验证**:Grafana http://localhost:3000(admin/admin123)、Prometheus http://localhost:9091、VictoriaMetrics http://localhost:8428。 +**详细**:[CENTRAL_SERVER_CONFIG](CENTRAL_SERVER_CONFIG.md)、[central-server/CONFIGURATION.md](../central-server/CONFIGURATION.md)。 + --- ## 第二步:部署边缘节点 @@ -23,29 +25,31 @@ bash deploy.sh **前提**:中央已运行,VictoriaMetrics 8428 可访问。 - **本机同机**:`cd edge-agent && bash deploy.sh --local`(中央地址设为 host.docker.internal:8428)。 -- **边缘在另一台机器**: - - 在 edge-agent 下 `cp env.example .env`,编辑 `CENTRAL_SERVER_HOST`、`CENTRAL_SERVER_PORT=8428`。 - - `bash deploy.sh`(会自动调用 update-configs)。 +- **边缘跨机**:`cd edge-agent` → 编辑 `.env` 中 `CENTRAL_SERVER_HOST=中央IP` → `bash deploy.sh`。 -**验证**:边缘 Prometheus http://localhost:9092(或边缘机 IP:9092);中央 Grafana 选数据源 **VictoriaMetrics**,查询 `probe_success{job="network-ping"}` 可见边缘数据。 +**验证**:边缘 http://localhost:9092;中央 Grafana 选数据源 **VictoriaMetrics**,查询 `probe_success{job="network-ping"}` 可见边缘数据。 + +**targets.csv**:部署时自动生成 target-*.json;修改 targets.csv 后需手动 `cd config && ./update-configs.sh`,vmagent 每 5 分钟自动重载。 **常见问题**: -- 看不到边缘数据:确认 `.env` 中为中央 IP(非 host.docker.internal,除非本机同机);从边缘 `curl -s -o /dev/null -w "%{http_code}" http://<中央IP>:8428/health` 应为 200。 -- 端口冲突:边缘 Prometheus 已映射 9092,避免与中央 9091 冲突。 +- 看不到边缘数据:确认 `.env` 中为中央 IP(跨机不能用 host.docker.internal);`curl -s -o /dev/null -w "%{http_code}" http://<中央IP>:8428/health` 应为 200。 +- 端口冲突:边缘已映射 9092,与中央 9091 区分。 + +**详细**:[EDGE_AGENT_CONFIG](EDGE_AGENT_CONFIG.md)、[TARGETS_AND_MONITORING](TARGETS_AND_MONITORING.md)。 --- ## 第三步(可选):多用户与告警 -- **Grafana 多用户**:`cd central-server/grafana && bash setup-users.sh`,详见 [USER_MANAGEMENT.md](USER_MANAGEMENT.md)。 -- **告警**:规则见 [ALERTING.md](ALERTING.md);通知渠道编辑 `central-server/alertmanager/alertmanager.yml`。 +- **Grafana 多用户**:`cd central-server/config/grafana && bash setup-users.sh`,见 [USER_MANAGEMENT](USER_MANAGEMENT.md)。 +- **告警**:规则见 [ALERTING](ALERTING.md);通知渠道编辑 `central-server/config/alertmanager/alertmanager.yml`。 --- ## 部署后检查清单 -- **中央**:`docker compose ps` 中相关服务 Up;Grafana 中 Prometheus 数据源可查 `up`。 -- **边缘**:prometheus-edge、blackbox-exporter Up;Grafana 选 VictoriaMetrics 可查 `probe_success{job="network-ping"}` 等。 -- **磁盘/端口**:端口冲突用 `ss -tulpn` 排查;空间不足时清理或扩容数据目录。 +- **中央**:`docker compose ps` 中相关服务 Up;Grafana Prometheus 数据源可查 `up`。 +- **边缘**:prometheus-edge、blackbox-exporter Up;Grafana 选 VictoriaMetrics 可查 `probe_success{job="network-ping"}`。 +- **磁盘/端口**:`ss -tulpn` 查端口;空间不足时清理或扩容。 -详见 [TROUBLESHOOTING.md](TROUBLESHOOTING.md)、[README.md](README.md)。 +详见 [TROUBLESHOOTING](TROUBLESHOOTING.md)。 diff --git a/doc/EDGE_AGENT_CONFIG.md b/doc/EDGE_AGENT_CONFIG.md index 5cdd104..6faa2df 100644 --- a/doc/EDGE_AGENT_CONFIG.md +++ b/doc/EDGE_AGENT_CONFIG.md @@ -26,25 +26,27 @@ - **config/targets.csv**:统一监控目标(ping/onvif/topology),格式与脚本见 [TARGETS_AND_MONITORING.md](TARGETS_AND_MONITORING.md)。 - **config/update-configs.sh**:从 targets.csv 生成 `target-onvif.json`、`target-ping.json`、`target-topology.geojson`。 -- **prometheus-edge (vmagent)**:使用 `vmagent-scrape.yml.template` 抓取;`CENTRAL_SERVER_HOST`/`PORT` 来自 `.env`;磁盘缓存卷 `vmagent-cache-data`。 +- **prometheus-edge (vmagent)**:使用 `config/vmagent/vmagent-scrape.yml.template` 抓取;`CENTRAL_SERVER_HOST`/`PORT` 来自 `.env`;磁盘缓存卷 `vmagent-cache-data`。 - **.env**:`CENTRAL_SERVER_HOST`、`CENTRAL_SERVER_PORT=8428`、`EDGE_NODE_ID`。本机同机用 `./deploy.sh --local`;跨机配 `.env` 后 `./deploy.sh`。 ## 常用操作 -- 改监控目标:编辑 `config/targets.csv` → `cd config && ./update-configs.sh`,必要时重启 prometheus-edge。 +- 改监控目标:编辑 `config/targets.csv` → `cd config && ./update-configs.sh`;vmagent 每 5 分钟自动重载 JSON,无需重启。 - 改中央地址:编辑 `.env` → `docker compose restart prometheus-edge`。 ## 中心宕机 / 断网时的缓存 -`docker-compose.yaml` 使用 vmagent 统一实现: +`docker-compose.yaml` 使用 vmagent 实现: -- **短时内存缓存**:中心短暂不可达时在内存中缓冲 -- **长时磁盘缓存**:长时间离线时写入磁盘队列(默认 512MB),恢复后自动补传 -- **冗余重试**:失败自动重试,边缘重启后从磁盘恢复未上传数据 +| 层级 | 机制 | 说明 | +|------|------|------| +| **短时内存缓存** | 内存队列 | 中心短暂不可达时在内存中缓冲(约 30 分钟量级) | +| **长时磁盘缓存** | 持久化队列 | 长时间离线写入磁盘(默认 512MB),恢复后自动补传 | +| **冗余重试** | 失败重试 | 边缘重启后从磁盘恢复未上传数据 | -详见 [EDGE_CACHE.md](EDGE_CACHE.md)。 +**参数**(修改 prometheus-edge 的 `command` 可调):`-remoteWrite.maxDiskUsagePerURL=512MB`、`-remoteWrite.tmpDataPath=/cache/remotewrite`、`-memory.allowedPercent=80`。监控指标:`vmagent_remotewrite_pending_bytes`、`vmagent_remotewrite_packets_dropped_total`。 ## 相关文档 -- [EDGE_CACHE.md](EDGE_CACHE.md) | [DEPLOYMENT_GUIDE.md](DEPLOYMENT_GUIDE.md) | [TARGETS_AND_MONITORING.md](TARGETS_AND_MONITORING.md) | [ONVIF_ALTERNATIVES.md](ONVIF_ALTERNATIVES.md) | [ARCHITECTURE.md](ARCHITECTURE.md) +- [DEPLOYMENT_GUIDE](DEPLOYMENT_GUIDE.md) | [TARGETS_AND_MONITORING](TARGETS_AND_MONITORING.md) | [ONVIF_ALTERNATIVES](ONVIF_ALTERNATIVES.md) | [ARCHITECTURE](ARCHITECTURE.md) diff --git a/doc/EDGE_CACHE.md b/doc/EDGE_CACHE.md deleted file mode 100644 index ac59da4..0000000 --- a/doc/EDGE_CACHE.md +++ /dev/null @@ -1,34 +0,0 @@ -# 边缘节点缓存 - -## 架构 - -`docker-compose.yaml` 使用 **vmagent** 统一实现: - -| 层级 | 机制 | 说明 | -|------|------|------| -| **短时内存缓存** | 内存队列 | 中心短暂不可达时在内存中缓冲(~30 分钟量级) | -| **长时磁盘缓存** | 持久化队列 | 长时间离线时写入磁盘(默认 512MB),恢复后自动补传 | -| **冗余重试** | 失败重试 | 自动重试,边缘重启后从磁盘恢复未上传数据 | - -## 部署 - -```bash -cd edge-agent -bash deploy.sh -# 本机同机: bash deploy.sh --local -``` - -## 配置 - -| 参数 | 默认值 | 说明 | -|------|--------|------| -| `-remoteWrite.maxDiskUsagePerURL` | 512MB | 每 URL 最大磁盘缓存 | -| `-remoteWrite.tmpDataPath` | /cache/remotewrite | 磁盘队列路径 | -| `-memory.allowedPercent` | 80 | 内存队列可用比例 | - -修改 `docker-compose.yaml` 中 `prometheus-edge` 的 `command` 可调整上述参数。 - -## 监控 - -- `vmagent_remotewrite_pending_bytes`:待发送字节数 -- `vmagent_remotewrite_packets_dropped_total`:丢包数 diff --git a/doc/ONVIF_ALTERNATIVES.md b/doc/ONVIF_ALTERNATIVES.md index d9877ca..6743a24 100644 --- a/doc/ONVIF_ALTERNATIVES.md +++ b/doc/ONVIF_ALTERNATIVES.md @@ -11,7 +11,7 @@ | **SNMP Exporter** | 摄像头/设备支持 SNMP | 用官方 `prom/snmp_exporter`,按设备 MIB 配置 OID,无 ONVIF 协议 | | **Frigate** | 已用或可部署 Frigate NVR | Frigate 暴露 `/api/metrics`,Prometheus 直接抓取或通过 frigate-exporter | | **UniFi Protect Exporter** | UniFi 摄像头/Protect | 使用专有 exporter,非 ONVIF 通用方案 | -| **ONVIF 自建** | 必须用 ONVIF 协议 | **本项目已提供**:见 **edge-agent/onvif-exporter/**,Go + use-go/onvif,读取 `onvif-targets.json`,GetDeviceInformation 探测,暴露 `onvif_device_up`、`onvif_probe_duration_seconds`。`docker compose --profile onvif up -d --build` 即可。 | +| **ONVIF 自建** | 必须用 ONVIF 协议 | **本项目已提供**:见 **edge-agent/apps/onvif-exporter/**,Go + use-go/onvif,读取 `target-onvif.json`,GetDeviceInformation 探测,暴露 `onvif_device_up`、`onvif_probe_duration_seconds`。`docker compose --profile onvif up -d --build` 即可。 | | **仅 Ping/HTTP 探测** | 只关心在线与可达性 | 用 Blackbox Exporter 对摄像头 IP 做 ICMP/HTTP 探测,不解析 ONVIF | --- @@ -63,19 +63,19 @@ ## 4. ONVIF 自建 Exporter(必须走 ONVIF 时) -**本项目已在 edge-agent/onvif-exporter/ 提供自建容器**,无需再找第三方镜像。 +**本项目已在 edge-agent/apps/onvif-exporter/ 提供自建容器**,无需再找第三方镜像。 - **实现**:Go + [use-go/onvif](https://github.com/use-go/onvif),读取 `config/target-onvif.json`(与 `targets.csv` 中 onvif 行一致),轮询 ONVIF `GetDeviceInformation`,暴露 Prometheus 指标 `onvif_device_up`、`onvif_probe_duration_seconds`。 - **启用**:在边缘节点执行 `docker compose --profile onvif up -d --build`,会构建并启动 ONVIF exporter,无需设置 `ONVIF_EXPORTER_IMAGE`。 - **配置**:在 `config/targets.csv` 中增加 onvif 行(ip、device_type、model、location、username、password、onvif_port),运行 `config/update-configs.sh` 生成 `target-onvif.json`。 -- 若需自行修改或扩展,见 **edge-agent/onvif-exporter/README.md**。 +- 若需自行修改或扩展,见 **edge-agent/apps/onvif-exporter/README.md**。 --- ## 在本项目中的建议 - **边缘默认部署**:不依赖不存在的 ONVIF 镜像;默认只跑 **prometheus-edge** + **blackbox-exporter**(Ping/探测),可选用 **snmp-exporter** 或 Frigate 抓取。 -- **若需要 ONVIF**:使用本项目自建的 **edge-agent/onvif-exporter**,执行 `docker compose --profile onvif up -d --build` 即可构建并启动;无需再设 `ONVIF_EXPORTER_IMAGE`。 +- **若需要 ONVIF**:使用本项目自建的 **edge-agent/apps/onvif-exporter**,执行 `docker compose --profile onvif up -d --build` 即可构建并启动;无需再设 `ONVIF_EXPORTER_IMAGE`。 - **摄像头支持 SNMP 时**:优先考虑 **SNMP Exporter** 作为“Prometheus 监控摄像头”的替代方案,再根据需要补充 Frigate 或 Blackbox。 具体边缘配置与 compose 变更见 **[EDGE_AGENT_CONFIG.md](EDGE_AGENT_CONFIG.md)** 及 `edge-agent/docker-compose.yaml`。 diff --git a/doc/README.md b/doc/README.md index 726211b..e365fd7 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,112 +1,63 @@ -# Distributed-Prometheus 文档 +# 文档索引 -本目录为项目文档入口。**先按部署顺序做完第一步、第二步,再按需查阅其他文档。** +本目录为项目文档入口。**首次部署**按「部署顺序」先中央、后边缘;**修改配置**按需查阅对应文档。 --- -## 部署顺序(必读) +## 部署顺序 -整体顺序:**先中央,后边缘**。边缘向中央主动上报数据,中央必须先就绪。 +| 步骤 | 操作 | 验证 | +|------|------|------| +| **1. 中央** | `cd central-server && cp env.example .env && bash deploy.sh` | Grafana http://localhost:3000、Prometheus http://localhost:9091 | +| **2. 边缘** | `cd edge-agent && bash deploy.sh`(本机同机加 `--local`) | 边缘 http://localhost:9092;Grafana 选 VictoriaMetrics 可见 `probe_success{job="network-ping"}` | +| **3. 可选** | 多用户、告警通知 | [USER_MANAGEMENT](USER_MANAGEMENT.md)、[ALERTING](ALERTING.md) | -| 步骤 | 部署 / 操作对象 | 做什么 | 验证 | -|------|------------------|--------|------| -| **第一步** | 中央服务器 | 部署 Prometheus、Grafana、VictoriaMetrics、Alertmanager | Grafana http://localhost:3000、Prometheus http://localhost:9091 | -| **第二步** | 边缘节点(可选,可多台) | 配置中央地址与监控目标,部署边缘 Prometheus + Exporter | 边缘 UI http://localhost:9092,Grafana 选 VictoriaMetrics 数据源可见边缘数据 | -| **第三步** | 多用户 / 告警(可选) | 配置 Grafana 组织与用户、Alertmanager 通知 | 按 [USER_MANAGEMENT.md](USER_MANAGEMENT.md)、[ALERTING.md](ALERTING.md) 验证 | +**边缘跨机**:编辑 `edge-agent/.env` 中 `CENTRAL_SERVER_HOST` 为中央 IP,再 `bash deploy.sh`。 + +**targets.csv**:部署时自动从 targets.csv 生成 target-onvif.json、target-ping.json;修改 targets.csv 后需手动 `cd config && ./update-configs.sh`,vmagent 每 5 分钟自动重载。 --- -### 第一步:部署中央服务器 - -**必须先做**。中央提供 VictoriaMetrics(接收边缘数据)、Prometheus、Grafana、Alertmanager。 - -```bash -cd central-server -cp env.example .env # 可选:按需改端口、Traefik、网络等 -bash deploy.sh -``` - -- **前置**:已安装 Docker、Docker Compose;端口 3000、9091、8428、9093 未被占用。 -- **验证**:访问 http://localhost:3000(Grafana,admin/admin123)、http://localhost:9091(Prometheus)。 -- **详细**:[DEPLOYMENT_GUIDE.md](DEPLOYMENT_GUIDE.md)、[CENTRAL_SERVER_CONFIG.md](CENTRAL_SERVER_CONFIG.md)、[central-server/CONFIGURATION.md](../central-server/CONFIGURATION.md)。 - ---- - -### 第二步:部署边缘节点 - -**在中央已运行后**进行。边缘将指标推送到中央 VictoriaMetrics(端口 8428)。 -边缘必选:**remote_write**(prometheus-edge)、**Blackbox** 容器;可选:ONVIF/SNMP 等容器(见 [EDGE_AGENT_CONFIG.md](EDGE_AGENT_CONFIG.md))。 - -- **本机同机**(中央与边缘在同一台机器): - ```bash - cd edge-agent - bash deploy.sh --local - ``` - 脚本会设置中央地址为 `host.docker.internal:8428` 并执行部署。 - -- **边缘在另一台机器**: - ```bash - cd edge-agent - cp env.example .env - # 编辑 .env:CENTRAL_SERVER_HOST=中央服务器IP,CENTRAL_SERVER_PORT=8428 - cd config && ./update-configs.sh && cd .. # 从 targets.csv 生成 JSON - bash deploy.sh - ``` - -- **验证**:边缘 Prometheus UI http://localhost:9092(端口 9092 避免与中央 9091 冲突)。在中央 Grafana 中**选择数据源「VictoriaMetrics」**,查询如 `up{job="network-ping"}` 可见边缘数据;中央自身指标在数据源「Prometheus」。 -- **摄像头/ONVIF**:默认不拉取 ONVIF 镜像(公共镜像不存在)。监控摄像头可选:**SNMP Exporter**、**Frigate**、**Blackbox 探测** 或自建 ONVIF 镜像,见 **[ONVIF_ALTERNATIVES.md](ONVIF_ALTERNATIVES.md)**。 -- **监控目标**:编辑 `edge-agent/config/targets.csv`(Ping / ONVIF / 拓扑),详见 [TARGETS_AND_MONITORING.md](TARGETS_AND_MONITORING.md)。 -- **详细**:[EDGE_AGENT_CONFIG.md](EDGE_AGENT_CONFIG.md)、[DEPLOYMENT_GUIDE.md](DEPLOYMENT_GUIDE.md)。 - ---- - -### 第三步(可选):多用户与告警 - -- **Grafana 多用户**:`cd central-server/grafana && bash setup-users.sh`,然后按 [USER_MANAGEMENT.md](USER_MANAGEMENT.md) 配置组织与数据源。 -- **告警通知**:编辑 `central-server/alertmanager/alertmanager.yml` 配置接收端;告警规则与说明见 [ALERTING.md](ALERTING.md)。 - ---- - -## 文档列表(按用途) +## 文档列表 ### 架构与数据流 | 文档 | 说明 | |------|------| -| [ARCHITECTURE.md](ARCHITECTURE.md) | 系统架构、容器关系、数据流向、端口与依赖 | +| [ARCHITECTURE](ARCHITECTURE.md) | 容器关系图、数据流向、端口与依赖 | -### 配置说明 +### 中央节点 | 文档 | 说明 | |------|------| -| [CENTRAL_SERVER_CONFIG.md](CENTRAL_SERVER_CONFIG.md) | 中央服务器配置文件说明 | -| [../central-server/CONFIGURATION.md](../central-server/CONFIGURATION.md) | 中央服务器环境变量(.env)说明 | -| [EDGE_AGENT_CONFIG.md](EDGE_AGENT_CONFIG.md) | 边缘节点配置文件说明 | -| [TARGETS_AND_MONITORING.md](TARGETS_AND_MONITORING.md) | 监控目标与 targets.csv(格式、脚本、数据流) | -| [TIANDITU_CONFIG.md](TIANDITU_CONFIG.md) | 天地图配置(底图 vec_w、标识图 cva_w、WMTS 地址) | -| [ONVIF_ALTERNATIVES.md](ONVIF_ALTERNATIVES.md) | **摄像头/ONVIF 监控替代方案**(SNMP、Frigate、Blackbox、自建) | +| [CENTRAL_SERVER_CONFIG](CENTRAL_SERVER_CONFIG.md) | 中央目录结构、服务端口、关键配置 | +| [../central-server/CONFIGURATION.md](../central-server/CONFIGURATION.md) | 中央环境变量(.env)说明 | -### 用户与告警 +### 边缘节点 | 文档 | 说明 | |------|------| -| [USER_MANAGEMENT.md](USER_MANAGEMENT.md) | Grafana 多用户、组织与数据隔离 | -| [ALERTING.md](ALERTING.md) | 告警规则、Alertmanager 配置与通知渠道 | +| [EDGE_AGENT_CONFIG](EDGE_AGENT_CONFIG.md) | 边缘目录结构、vmagent、blackbox、缓存机制 | +| [TARGETS_AND_MONITORING](TARGETS_AND_MONITORING.md) | targets.csv 格式、update-configs.sh、监控类型 | -### 部署与运维 +### 告警与多用户 | 文档 | 说明 | |------|------| -| [DEPLOYMENT_GUIDE.md](DEPLOYMENT_GUIDE.md) | 完整部署步骤、检查清单、验证与常见问题 | -| [TROUBLESHOOTING.md](TROUBLESHOOTING.md) | 故障排查 | -| [BEST_PRACTICES.md](BEST_PRACTICES.md) | 最佳实践与生产环境建议 | +| [ALERTING](ALERTING.md) | 告警规则、Alertmanager 配置、通知渠道 | +| [USER_MANAGEMENT](USER_MANAGEMENT.md) | Grafana 多用户、组织与数据隔离 | ---- +### 扩展功能 -## 快速导航 +| 文档 | 说明 | +|------|------| +| [ONVIF_ALTERNATIVES](ONVIF_ALTERNATIVES.md) | ONVIF 摄像头监控方案(SNMP、Frigate、Blackbox、自建) | +| [TIANDITU_CONFIG](TIANDITU_CONFIG.md) | 天地图底图、Grafana Geomap、tile-cache | -- **第一次部署**:按上面「部署顺序」先做第一步,再做第二步。 -- **只改中央配置**:看 [CENTRAL_SERVER_CONFIG.md](CENTRAL_SERVER_CONFIG.md)、[CONFIGURATION.md](../central-server/CONFIGURATION.md)。 -- **只改边缘 / 监控目标**:看 [EDGE_AGENT_CONFIG.md](EDGE_AGENT_CONFIG.md)、[TARGETS_AND_MONITORING.md](TARGETS_AND_MONITORING.md)。 -- **多用户 / 告警**:看 [USER_MANAGEMENT.md](USER_MANAGEMENT.md)、[ALERTING.md](ALERTING.md)。 -- **出问题**:看 [TROUBLESHOOTING.md](TROUBLESHOOTING.md)、[DEPLOYMENT_GUIDE.md](DEPLOYMENT_GUIDE.md)。 +### 运维 + +| 文档 | 说明 | +|------|------| +| [DEPLOYMENT_GUIDE](DEPLOYMENT_GUIDE.md) | 完整部署步骤、检查清单、常见问题 | +| [TROUBLESHOOTING](TROUBLESHOOTING.md) | 故障排查 | +| [BEST_PRACTICES](BEST_PRACTICES.md) | 最佳实践与生产建议 | diff --git a/doc/TARGETS_AND_MONITORING.md b/doc/TARGETS_AND_MONITORING.md index 91f18ec..1b8265a 100644 --- a/doc/TARGETS_AND_MONITORING.md +++ b/doc/TARGETS_AND_MONITORING.md @@ -2,6 +2,8 @@ 边缘监控目标统一由 `edge-agent/config/targets.csv` 配置,经 `update-configs.sh` 生成 `target-onvif.json`、`target-ping.json`、`target-topology.geojson`。 +**更新流程**:部署时 deploy.sh 自动从 targets.csv 生成 target-*.json;修改 targets.csv 后需手动执行 `cd edge-agent/config && ./update-configs.sh`,vmagent 每 5 分钟自动重载 JSON,无需重启。 + --- ## targets.csv 格式 diff --git a/doc/TROUBLESHOOTING.md b/doc/TROUBLESHOOTING.md index 8374a4c..987cbe6 100644 --- a/doc/TROUBLESHOOTING.md +++ b/doc/TROUBLESHOOTING.md @@ -116,10 +116,10 @@ docker compose logs prometheus-edge # 查询: probe_success{job="network-ping"} # 2. 检查告警规则文件 -cat central-server/alert_rules.yml +cat central-server/config/prometheus/alert_rules.yml # 3. 检查 Prometheus 配置 -cat central-server/prometheus.yml +cat central-server/config/prometheus/prometheus.yml ``` **常见原因**: @@ -130,7 +130,7 @@ cat central-server/prometheus.yml **解决方案**: - 部署边缘节点并配置监控目标 - 检查告警规则表达式 -- 确认 `prometheus.yml` 中引用了 `alert_rules.yml` +- 确认 `config/prometheus/prometheus.yml` 中引用了 `alert_rules.yml` - 重启 Prometheus 容器 --- @@ -374,7 +374,7 @@ ls -lh /storage/prometheus-data ls -lh /storage/victoria-metrics-data # 检查数据保留配置 -grep retention prometheus.yml +grep retention config/prometheus/prometheus.yml ``` **解决**: diff --git a/edge-agent/onvif-exporter/Dockerfile b/edge-agent/apps/onvif-exporter/Dockerfile similarity index 82% rename from edge-agent/onvif-exporter/Dockerfile rename to edge-agent/apps/onvif-exporter/Dockerfile index a215ac7..67b321b 100644 --- a/edge-agent/onvif-exporter/Dockerfile +++ b/edge-agent/apps/onvif-exporter/Dockerfile @@ -1,8 +1,8 @@ # 多阶段构建:在镜像内编译,无需本机安装 Go FROM golang:1.21-alpine AS builder WORKDIR /app -COPY go.mod ./ -COPY main.go ./ +COPY apps/onvif-exporter/go.mod ./ +COPY apps/onvif-exporter/main.go ./ RUN go mod tidy && CGO_ENABLED=0 GOOS=linux go build -o /onvif-exporter . FROM alpine:3.19 diff --git a/edge-agent/onvif-exporter/README.md b/edge-agent/apps/onvif-exporter/README.md similarity index 100% rename from edge-agent/onvif-exporter/README.md rename to edge-agent/apps/onvif-exporter/README.md diff --git a/edge-agent/onvif-exporter/go.mod b/edge-agent/apps/onvif-exporter/go.mod similarity index 100% rename from edge-agent/onvif-exporter/go.mod rename to edge-agent/apps/onvif-exporter/go.mod diff --git a/edge-agent/onvif-exporter/main.go b/edge-agent/apps/onvif-exporter/main.go similarity index 100% rename from edge-agent/onvif-exporter/main.go rename to edge-agent/apps/onvif-exporter/main.go diff --git a/edge-agent/blackbox/config.yml b/edge-agent/config/blackbox/config.yml similarity index 100% rename from edge-agent/blackbox/config.yml rename to edge-agent/config/blackbox/config.yml diff --git a/edge-agent/prometheus-edge/vmagent-scrape.yml.template b/edge-agent/config/vmagent/vmagent-scrape.yml.template similarity index 100% rename from edge-agent/prometheus-edge/vmagent-scrape.yml.template rename to edge-agent/config/vmagent/vmagent-scrape.yml.template diff --git a/edge-agent/deploy.sh b/edge-agent/deploy.sh index 8f7a4f0..586358f 100644 --- a/edge-agent/deploy.sh +++ b/edge-agent/deploy.sh @@ -1,6 +1,10 @@ #!/bin/bash # 边缘节点部署:vmagent + 内存/磁盘缓存 # 用法: ./deploy.sh [--local] --local = 本机同机(中央与边缘同机) +# +# targets.csv:部署时自动从 targets.csv 生成 target-onvif.json、target-ping.json; +# 修改 targets.csv 后需手动执行 config/update-configs.sh(或重新 deploy), +# vmagent 每 5 分钟自动重载 JSON,无需重启。 set -e cd "$(dirname "${BASH_SOURCE[0]}")" @@ -24,7 +28,7 @@ command -v jq &>/dev/null || { echo "❌ 需要 jq"; exit 1; } [ -f config/targets.csv ] && (cd config && ./update-configs.sh) || true [ ! -f config/target-onvif.json ] && echo '[]' > config/target-onvif.json [ ! -f config/target-ping.json ] && echo '[]' > config/target-ping.json -[ ! -f prometheus-edge/vmagent-scrape.yml.template ] && { echo "❌ 缺少 vmagent-scrape.yml.template"; exit 1; } +[ ! -f config/vmagent/vmagent-scrape.yml.template ] && { echo "❌ 缺少 config/vmagent/vmagent-scrape.yml.template"; exit 1; } # .env [ ! -f .env ] && cp env.example .env diff --git a/edge-agent/docker-compose.yml b/edge-agent/docker-compose.yml index 2803038..97c0c46 100644 --- a/edge-agent/docker-compose.yml +++ b/edge-agent/docker-compose.yml @@ -13,7 +13,7 @@ services: - CENTRAL_SERVER_PORT=${CENTRAL_SERVER_PORT:-8428} volumes: - vmagent-cache-data:/cache - - ./prometheus-edge/vmagent-scrape.yml.template:/etc/vmagent/scrape.yml:ro + - ./config/vmagent/vmagent-scrape.yml.template:/etc/vmagent/scrape.yml:ro - ./config/target-onvif.json:/etc/prometheus/target-onvif.json:ro - ./config/target-ping.json:/etc/prometheus/target-ping.json:ro mem_limit: "256m" @@ -38,8 +38,8 @@ services: - onvif image: onvif-exporter:local build: - context: ./onvif-exporter - dockerfile: Dockerfile + context: . + dockerfile: apps/onvif-exporter/Dockerfile container_name: onvif-exporter restart: unless-stopped environment: @@ -57,7 +57,7 @@ services: container_name: blackbox-exporter restart: unless-stopped volumes: - - ./blackbox/config.yml:/etc/blackbox_exporter/config.yml:ro + - ./config/blackbox/config.yml:/etc/blackbox_exporter/config.yml:ro mem_limit: "64m" cpus: "0.5" networks: diff --git a/edge-agent/env.example b/edge-agent/env.example index 8ee05f2..57fdf90 100644 --- a/edge-agent/env.example +++ b/edge-agent/env.example @@ -19,9 +19,10 @@ EDGE_NODE_ID=workernode_1 # 格式: http://域名或IP:端口/api/v1/write # 默认端口: 8428 (VictoriaMetrics) -# 边缘缓存:docker-compose.yaml 使用 vmagent,含内存+磁盘缓存,详见 doc/EDGE_CACHE.md +# 边缘缓存:docker-compose 使用 vmagent,含内存+磁盘缓存,详见 doc/EDGE_AGENT_CONFIG.md # 注意:ONVIF 设备在 config/targets.csv 中配置(每行 ip、username、password 等) +# 配置与自建应用结构:config/(vmagent、blackbox、targets); apps/(onvif-exporter) # ONVIF Exporter 镜像(仅在使用 --profile onvif 时需要) # 公共 registry 无现成镜像,需自建或使用第三方镜像,参见 doc/ONVIF_ALTERNATIVES.md diff --git a/edge-agent/prometheus-edge/prometheus.yml b/edge-agent/prometheus-edge/prometheus.yml deleted file mode 100644 index a76a715..0000000 --- a/edge-agent/prometheus-edge/prometheus.yml +++ /dev/null @@ -1,45 +0,0 @@ -global: - scrape_interval: 120s - evaluation_interval: 120s - external_labels: - region: workernode_1 # 设置一个唯一边缘节点名称 - -remote_write: - - url: http://192.168.2.106:8428/api/v1/write - queue_config: - max_samples_per_send: 5000 - capacity: 5000 - max_shards: 5 - -scrape_configs: - - job_name: 'onvif-devices' - scrape_interval: 120s - file_sd_configs: - - files: ['/etc/prometheus/onvif-targets.json'] - refresh_interval: 5m - metrics_path: /metrics - static_configs: - - targets: ['onvif-exporter:9600'] - - - job_name: 'network-ping' - scrape_interval: 300s - file_sd_configs: - - files: ['/etc/prometheus/ping-targets.json'] - refresh_interval: 5m - metrics_path: /probe - params: - module: [icmp] - static_configs: - - targets: ['blackbox-exporter:9115'] - relabel_configs: - - source_labels: [__address__] - target_label: __param_target - - source_labels: [__param_target] - target_label: instance - - target_label: __address__ - replacement: blackbox-exporter:9115 - - - job_name: 'prometheus-edge' - scrape_interval: 60s - static_configs: - - targets: ['localhost:9090'] diff --git a/edge-agent/prometheus-edge/prometheus.yml.template b/edge-agent/prometheus-edge/prometheus.yml.template deleted file mode 100644 index 49a33d4..0000000 --- a/edge-agent/prometheus-edge/prometheus.yml.template +++ /dev/null @@ -1,45 +0,0 @@ -global: - scrape_interval: 120s - evaluation_interval: 120s - external_labels: - region: workernode_1 # 设置一个唯一边缘节点名称 - -remote_write: - - url: http://${CENTRAL_SERVER_HOST}:${CENTRAL_SERVER_PORT}/api/v1/write - queue_config: - max_samples_per_send: 5000 - capacity: 10000 - max_shards: 8 - -scrape_configs: - - job_name: 'onvif-devices' - scrape_interval: 120s - file_sd_configs: - - files: ['/etc/prometheus/onvif-targets.json'] - refresh_interval: 5m - metrics_path: /metrics - static_configs: - - targets: ['onvif-exporter:9600'] - - - job_name: 'network-ping' - scrape_interval: 300s - file_sd_configs: - - files: ['/etc/prometheus/ping-targets.json'] - refresh_interval: 5m - metrics_path: /probe - params: - module: [icmp] - static_configs: - - targets: ['blackbox-exporter:9115'] - relabel_configs: - - source_labels: [__address__] - target_label: __param_target - - source_labels: [__param_target] - target_label: instance - - target_label: __address__ - replacement: blackbox-exporter:9115 - - - job_name: 'prometheus-edge' - scrape_interval: 60s - static_configs: - - targets: ['localhost:9090'] diff --git a/tile-cache/package.json b/tile-cache/package.json deleted file mode 100644 index 795278d..0000000 --- a/tile-cache/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "tianditu-tile-cache", - "version": "1.0.0", - "description": "Cache Tianditu WMTS tiles to reduce API key usage", - "main": "server.js" -}