OneUptime Proxmox Agent:基于 OpenTelemetry Collector 的 Proxmox VE 集群监控安装与排障实战

📅 发布时间:2026/9/18 4:24:44
OneUptime Proxmox Agent:基于 OpenTelemetry Collector 的 Proxmox VE 集群监控安装与排障实战
OneUptime Proxmox Agent:基于 OpenTelemetry Collector 的 Proxmox VE 集群监控安装与排障实战【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime本文以 OneUptime 仓库中ProxmoxAgent/目录的安装文档为主线,完整讲解如何用一套「预配置 OpenTelemetry Collector prometheus-pve-exporter」的 Agent 方案监控 Proxmox VE 集群(节点、QEMU 虚机、LXC 容器、存储与 HA 状态):从 API Token 创建、Docker Compose 部署、全量环境变量说明,到指标采集范围、id标签派生属性的源码原理、可选服务日志管道、systemd 托管,以及一个能给出「最终裁决」的官方诊断脚本。读完本文,你可以独立完成 Agent 的安装、升级、卸载与故障定位,并理解每一处配置背后的实现依据。Agent 总体架构与数据流OneUptime Proxmox Agent 本质上是一个纯配置型的 Collector 容器:标准的otel/opentelemetry-collector-contrib镜像,搭配一份经过调优的 otel-collector-config.yaml,其工作链路为:Proxmox VE API (8006) │ 每次 scrape 都是一次真实 API 往返 ▼ prometheus-pve-exporter (可选内置, :9221, /pve 端点) │ collector 每 30s 拉取 ▼ OpenTelemetry Collector └─ processors: memory_limiter → transform/pve-identity → resource → batch └─ resource processor 为每条指标打上 proxmox.cluster.name │ OTLP/HTTP, x-oneuptime-token 头 ▼ OneUptime 实例 (ONEUPTIME_URL/otlp)关键实现事实(来自 otel-collector-config.yaml):Prometheus 接收器(L7-L29):metrics_path: /pve,通过target参数把每次 scrape 代理到${env:PVE_HOST}指定的 PVE API 节点;cluster: [1]与node: [1]同时启用集群级与节点级采集器;scrape_interval: 30s—— 因为 pve-exporter 每次应答都是一次活的 PVE API 往返,30 秒间隔使 pveproxy 压力可忽略。OTLP 导出器(L126-L130):endpoint: ${env:ONEUPTIME_URL}/otlp,请求头x-oneuptime-token携带遥测摄入令牌。批处理与内存保护(L118-L124):batch处理器timeout: 10s、send_batch_size: 1024;memory_limiter限制 256 MiB(尖峰余量 64 MiB,每 5s 检查),防止采集积压拖垮容器。集群身份注入(L101-L117):resource处理器把proxmox.cluster.nameupsert 到每条指标的资源属性上 —— 这是 OneUptime自动注册 Proxmox 集群的唯一依据,集群名称取自环境变量PROXMOX_CLUSTER_NAME。同一个resource处理器还主动删除service.name与service.instance.id两个属性,源码注释解释了原因:prometheus receiver 按 Prometheus→OTLP 兼容规范会为每批数据合成这两个属性,而 OneUptime 优先按service.name路由数据批 —— 若保留,会注册出一个名为oneuptime-proxmox的「幽灵服务」,数据就无法落到按proxmox.cluster.name发现的 Proxmox 集群上(还会破坏按集群的保留期设置)。这也是官方标注「不要删除」的两行配置。前置条件一台能访问 Proxmox VE API(端口 8006)的机器,装有Docker Engine 20.10与Docker Compose v2插件;一个具有PVEAuditor角色(只读)的 Proxmox VE API Token;一个OneUptime Telemetry 摄入令牌—— 在Project Settings → Telemetry APM → Ingestion Keys中创建并复制其值。创建 Proxmox API Token最快路径 —— 在任一 PVE 节点上以 root 执行:pveum user token add monitoringpam oneuptime --privsep 1 pveum acl modify / --roles PVEAuditor --tokens monitoringpam!oneuptime如果monitoringpam用户尚不存在,先执行pveum user add monitoringpam创建 —— API Token 自带独立密钥,用户无需密码或系统账户。ACL 必须挂在根路径/上,因为 PVEAuditor 需要读取 exporter 遍历的每一个节点、虚机与存储对象;授权在更窄的路径上会隐藏集群其余部分,并产生401/403 Permission check failed (/, Sys.Audit)错误。第一条命令会只打印一次Token 密钥,在你的.env中对应:PVE_API_TOKEN_IDmonitoringpam!oneuptime PVE_API_TOKEN_SECRET打印出的密钥或者通过 Proxmox Web UI:进入Datacenter → Permissions → API Tokens,点击Add;选择(或新建)一个用户,Token ID 命名为oneuptime之类,取消勾选 Privilege Separation(或在下一步为 Token 单独授权);在Datacenter → Permissions中,为路径/上的该 Token 添加PVEAuditor角色;复制 Token ID(格式userrealm!tokenname)与密钥 —— 密钥只显示一次。部署位置建议Agent 通过网络查询 PVE API,因此不必须、也最好不要放在集群节点上:把它运行在一台能扛住节点故障的机器上(独立硬件上的小型监控 VM、管理主机),或者把PVE_HOST指向 VIP / 轮询 DNS 名称而非某个节点的固定地址 —— 否则当 Agent 的 API 目标恰好是刚挂掉的那个节点时,你的监控会随之一起失效。唯一例外是可选的 journald 日志管道,它必须在 PVE 节点上运行(见下文服务日志)。快速安装(安装脚本)仓库为 Agent 提供了交互式安装脚本 install.sh。在本仓库的ProxmoxAgent/目录中执行:bash install.sh脚本会依次提示输入:OneUptime URL、遥测摄入令牌、集群名称、Proxmox API 主机地址,然后:检查 Docker 与 Compose v2 是否可用(不可用则直接退出并提示);询问是否运行内置的 prometheus-pve-exporter(是,则要求提供 Token ID/密钥并启用pve-exporterprofile;否,则要求提供已有 exporter 的host:port地址 —— 脚本会特别提示:Agent 运行在容器里,localhost永远指不到宿主机上的 exporter,必须用 LAN IP 或 DNS 名);安装到/opt/oneuptime-proxmox-agent(可通过环境变量INSTALL_DIR覆盖),下载docker-compose.yml与otel-collector-config.yaml;生成.env文件并chmod 600收紧权限,最后docker compose up -d启动。手动安装 — Docker Compose把 ProxmoxAgent/docker-compose.yml 和 ProxmoxAgent/otel-collector-config.yaml 两个文件复制到任意目录,然后在旁边创建.env文件:ONEUPTIME_URLYOUR_ONEUPTIME_URL ONEUPTIME_TELEMETRY_INGESTION_KEYYOUR_TELEMETRY_INGESTION_TOKEN PROXMOX_CLUSTER_NAMEmy-proxmox-cluster PVE_HOST192.168.1.10 PVE_API_TOKEN_IDoneuptimepve!exporter PVE_API_TOKEN_SECRETyour-token-secret COMPOSE_PROFILESpve-exporter启动(pve-exporterprofile 会同时启动内置的 exporter 容器):docker compose up -d就这么多。Agent 连上之后,集群会自动出现在 OneUptime 仪表盘的Proxmox区域。compose 文件中的 Token 拆分细节:内置 exporter 服务(docker-compose.yml)要求把 Token ID 拆成PVE_USER(用户部分)和PVE_TOKEN_NAME(令牌名部分)。因此 compose 文件用一段自定义 entrypoint 完成拆分:entrypoint: [/bin/sh, -c] command: - export PVE_USER$${PVE_API_TOKEN_ID%%!*} PVE_TOKEN_NAME$${PVE_API_TOKEN_ID##*!} exec /usr/bin/pve_exporter$$用于屏蔽 docker compose 的插值,保证拆分在容器内完成 —— 这样.env里就可以原样粘贴 Web UI 中显示的完整userrealm!tokenname字符串,无需手工拆开。已有 pve-exporter 时如果你已经在别处运行 prometheus-pve-exporter,去掉.env中的COMPOSE_PROFILES、PVE_API_TOKEN_ID和PVE_API_TOKEN_SECRET,改为指向它:PVE_EXPORTER_URLyour-exporter-host:9221环境变量全量说明变量是否必需说明ONEUPTIME_URL是你的 OneUptime 实例 URL(如https://oneuptime.com或自托管地址)ONEUPTIME_TELEMETRY_INGESTION_KEY是来自Project Settings → Telemetry APM → Ingestion Keys的遥测摄入令牌PROXMOX_CLUSTER_NAME是在 OneUptime 中显示的集群标识,会被打上每条指标的proxmox.cluster.name资源属性。保持稳定—— 事后修改会注册出第二个集群。默认proxmox-clusterPVE_HOST是exporter 所查询的 Proxmox VE API 主机(集群任一节点),例如192.168.1.10PVE_EXPORTER_URL否prometheus-pve-exporter 地址(host:port,不带协议)。默认指向内置 exporter(pve-exporter:9221)PVE_API_TOKEN_ID仅内置 exporter完整 Proxmox API Token ID,例如oneuptimepve!exporterPVE_API_TOKEN_SECRET仅内置 exporterProxmox API Token 密钥PVE_VERIFY_SSL否是否校验 Proxmox API 的 TLS 证书。默认false,因为 Proxmox 出厂自签证书COMPOSE_PROFILES否设为pve-exporter以启动内置 exporter 容器默认值行为在 compose 文件中可见:PROXMOX_CLUSTER_NAME缺省回落到proxmox-cluster(docker-compose.yml),PVE_EXPORTER_URL缺省回落到pve-exporter:9221,PVE_HOST缺省回落到localhost(仅当 exporter 直接跑在 PVE 节点上时才有效)。验证安装确认 Agent 在运行:docker compose ps查看 Collector 日志:docker logs -f oneuptime-proxmox-agent寻找这行:Everything is ready. Begin running and processing data.大约一分钟后,集群应当出现在 OneUptime 仪表盘并开始有指标流入。采集了什么:指标全集Agent 每 30 秒 scrape 一次 exporter,同时启用 cluster 与 node 两类采集器 —— 这也覆盖了 exporter 默认开启的backup-info(集群级)与replication(节点级)采集器。每条序列都带有id标签用于标识资源:node/name、qemu/vmid、lxc/vmid或storage/node/storage:类别指标可用性pve_up、pve_uptime_seconds节点pve_node_info、pve_cpu_usage_ratio、pve_cpu_usage_limit、pve_memory_usage_bytes、pve_memory_size_bytes虚机 / LXCpve_guest_info,以及qemu/*与lxc/*上的 CPU / 内存 / 网络序列(pve_network_receive_bytes、pve_network_transmit_bytes)存储pve_disk_usage_bytes、pve_disk_size_bytes、pve_storage_infoHApve_ha_state备份覆盖pve_not_backed_up_total(未被任何备份作业覆盖的虚机数量;集群级单序列,无id标签)、pve_not_backed_up_info(每个未覆盖虚机一条序列,带其id标签)。注意诚实边界:「被备份作业覆盖」指虚机被至少一个作业选中 —— pve-exporter 并不暴露备份是否近期运行或成功复制pve_replication_failed_syncs、pve_replication_duration_seconds、pve_replication_last_sync_timestamp_seconds、pve_replication_last_try_timestamp_seconds、pve_replication_next_sync_timestamp_seconds、pve_replication_info—— 按存储复制作业划分,其id标签携带的是复制作业ID(如100-0),不是资源 ID派生身份属性:pve.scope/pve.type/pve.idOneUptime 的监控条件与属性过滤是等值匹配而非前缀匹配,因此随附的 Collector 配置包含一个transform/pve-identity处理器(otel-collector-config.yaml),把id标签拆成三个额外的数据点属性 —— 内置 Proxmox 告警模板正是基于它们过滤的,所以请勿删除该处理器:属性取值qemu/100示例pve.scopenode、guest、storage、cluster(qemu与lxc均映射到guest)guestpve.typenode、qemu、lxc、storage(cluster/*序列上不设值)qemupve.idid中第一个/之后的部分(pve1、100、pve1/local)100实现上就是一组基于正则的 OTel transform 语句,例如:- set(attributes[pve.scope], guest) where attributes[id] ! nil and IsMatch(attributes[id], ^qemu/) - set(attributes[pve.type], qemu) where attributes[id] ! nil and IsMatch(attributes[id], ^qemu/) - set(attributes[pve.id], attributes[id]) where attributes[id] ! nil and IsMatch(attributes[id], /) - replace_pattern(attributes[pve.id], ^[^/]/, ) where attributes[pve.id] ! nil处理器以error_mode: ignore运行(单点失败不阻断批次),且原始id标签保持不动—— 按组页面与拆分视图仍然使用它。可选:向 OneUptime 发送 Proxmox 服务日志默认 Agent只发送指标,Proxmox 仪表盘的 Logs 页签保持空白。PVE 控制面把日志写入 systemd journal 下的 8 个单元:pveproxy、pvedaemon、pve-firewall、pve-ha-crm、pve-ha-lrm、pvescheduler、pvestatd与qmeventd。随附的 otel-collector-config.yaml 中已包含一个注释掉的journald接收器,精确指向这 8 个单元(start_at: end避免重启重发历史,priority: info),并接到一段同样被注释的logs管道上 —— 该管道复用resource处理器打上proxmox.cluster.name,使日志落到你的集群名下。启用步骤:把 Agent 运行在 PVE 节点上。journal 是逐主机的,远程 Agent 读不到。这是唯一与前面「部署位置建议」冲突的设置;如果你希望指标 Agent 继续留在集群外,就在节点上另跑一个仅日志Collector(复制配置,删掉prometheus接收器与metrics管道)。取消注释otel-collector-config.yaml中的journald接收器与logs管道。取消注释docker-compose.yml中的 journal 卷挂载(docker-compose.yml 中已备好):- /var/log/journal:/var/log/journal:ro - /etc/machine-id:/etc/machine-id:ro更换 Collector 镜像。标准的otel/opentelemetry-collector-contrib镜像是FROM scratch构建的:既没有 journald 接收器需要 shell 调用的journalctl二进制,又以非 root 用户运行、无权读 journal。构建一个薄包装镜像并把 compose 中的image:指过去:FROM otel/opentelemetry-collector-contrib:latest AS otelcol FROM debian:stable-slim RUN apt-get update \ apt-get install -y --no-install-recommends systemd \ rm -rf /var/lib/apt/lists/* COPY --fromotelcol /otelcol-contrib /otelcol-contrib ENTRYPOINT [/otelcol-contrib] CMD [--config, /etc/otelcol-contrib/config.yaml]systemd包仅为获取journalctl二进制;该镜像以 root 运行,这正是读 journal 所必需的。另一种做法:日志路径完全跳过 Docker,直接在节点上运行otelcol-contrib发行.deb—— 系统里本来就有journalctl。日志是逐节点的:journald 接收器只发送 Agent 所在节点自己的 journal。要采集所有节点的服务日志,需在每个节点上分别运行第 1 步所述的仅日志 Collector。不换镜像的兜底:filelog 读 /var/log/syslog如果你希望保留标准镜像,可以改读 syslog:在节点上安装 rsyslog(apt install rsyslog—— Debian 12 / PVE 8 起默认不再附带),把/var/log目录挂进容器(挂目录而非文件,避免日志轮转后钉住旧 inode),并用filelog接收器替换 journald:receivers: filelog: include: - /var/log/syslog start_at: end代价:失去按单元过滤(syslog 是「大杂烩」,不止 8 个 PVE 服务),且标准镜像的非 root 用户必须能读该文件;收益:无需换镜像。把它接进同一段被注释的logs管道即可(receivers: [filelog])。零安装替代方案 — Proxmox VE 9 原生 OTel 推送Proxmox VE 9.0 及以后版本内置OpenTelemetry 指标服务器,可把节点、虚机、存储指标直接推送到任意 OTLP/HTTP 端点 —— 无需安装任何 Agent 或 exporter。在Datacenter → Metric Server → Add → OpenTelemetry中配置:字段取值Server你的 OneUptime 主机,如oneuptime.com(或自托管主机)Port443ProtocolhttpsPath/otlp/v1/metricsHeaders{x-oneuptime-token: YOUR_TELEMETRY_INGESTION_TOKEN}两个需要知晓的取舍:集群发现。集群自动注册由 Agent 路径驱动,因为它是为每条指标打上proxmox.cluster.name资源属性的那条链路。使用原生推送时,请把 Metric Server 的Resource Attributes选项设为proxmox.cluster.namemy-proxmox-cluster,集群才会自我注册 —— 否则指标会进入项目,但不会出现任何 Proxmox 集群。指标名不同。原生推送产出proxmox_node_*/proxmox_vm_*/proxmox_storage_*序列,而 Agent 产出 pve-exporter 的pve_*序列。OneUptime 内置的 Proxmox 指标目录与告警模板针对的是pve_*命名,因此推荐 Agent 路径;原生推送适合作为零安装方式,把原始指标送入 Metrics Explorer 与自定义仪表盘。两者也可以并存:原生推送提供低延迟原始指标,Agent 负责发现、Proxmox 仪表盘页面与告警模板。进阶:用 Project Labels 自动打标签ProxmoxAgent/README.md 还提供了一个扩展技巧:任何以oneuptime.label.开头的资源属性都会被提升为项目 Label 并附加到集群上(模式:oneuptime.label.维度值→ 标签维度:值)。只需在resource处理器中追加:- key: oneuptime.label.team value: platform action: upsert - key: oneuptime.label.env value: production action: upsert集群即会带上team:platform与env:production标签;标签匹配不区分大小写,已有的同名标签会被复用而非重复创建,手动添加的标签也绝不会被 Agent 删除。以 systemd 服务运行为让 Agent 在重启后存活而不只依赖 Docker 的 restart 策略,安装仓库自带的 oneuptime-proxmox-agent.service:sudo cp systemd/oneuptime-proxmox-agent.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now oneuptime-proxmox-agent该 unit 假设 Agent 位于/opt/oneuptime-proxmox-agent(安装脚本默认值)。从 unit 内容看,它Requiresdocker.service、Afternetwork-online.target,并在WorkingDirectory/opt/oneuptime-proxmox-agent下以docker compose pull(ExecStartPre)→docker compose up --remove-orphans(启动)/docker compose down(停止)管理生命周期,Restarton-failure且RestartSec30—— 也就是说开机自启时会自动拉取新镜像,等效于每次重启都执行一次升级流程。升级、卸载与自托管升级 Agent:cd /opt/oneuptime-proxmox-agent docker compose pull docker compose up -d卸载 Agent:cd /opt/oneuptime-proxmox-agent docker compose down自托管 OneUptime:把ONEUPTIME_URL指向你自己的实例即可:ONEUPTIME_URLhttps://your-oneuptime-host.example.com若实例仅支持 HTTP,改用http://加相应端口。故障排查第一步:先跑诊断脚本Agent 附带一个「doctor」脚本 troubleshoot.sh,从安装 Agent 的机器上运行,它覆盖整条链路:容器运行时状态、exporter scrape、集群名注入、摄入令牌形态、Collector 自监控指标,以及一个确定性的服务端令牌校验。令牌校验是重点 —— OneUptime 的 OTLP 端点对非法摄入令牌故意返回静默的200(这样配置错误的 Collector 不会重试洪泛服务端),意味着 Collector 日志看起来一切正常,而每个数据点其实都在被丢弃。诊断脚本的解法:从 Agent 容器内部的网络命名空间发起GET url/otlp/v1/validate,换取真正的200(有效)/401(无效)裁决;老版本服务端没有该端点时,回退到POST /fluentd/v1/logs(走同一套鉴权但不是/otlp路径,坏令牌会返回400 Invalid service token)。bash troubleshoot.sh # 若未装在 /opt/oneuptime-proxmox-agent,加 -d dir脚本以 8 个分节推进,最后输出 VERDICT 小节,直接点名最可能的根因。从源码看,其关键探测手段包括:网络命名空间级探测:Collector 镜像是 distroless(无 shell、无 curl),脚本用docker run --rm --network container:oneuptime-proxmox-agent curlimages/curl ...起一个共享 Agent 网络命名空间的 curl 兄弟容器,精确复刻 Collector 自己的出网路径(compose 网络、DNS、代理、防火墙、TLS);exporter 抓取验证(L209-L239):从 Collector 命名空间内请求http://PVE_EXPORTER_URL/pve?targetPVE_HOSTcluster1node1,统计pve_*序列数并检查pve_up是否存在;返回 0 条序列时,直接给出「API Token 错误或权限不足」的结论,并自动从内置 exporter 日志中抓取 401/595/auth 相关行作为佐证;它还专门捕获一个隐蔽陷阱 ——PVE_EXPORTER_URLlocalhost:*在容器内指向的是 Agent 自己,永远不会是宿主机上的 exporter;集群名注入检查(L249-L268):确认PROXMOX_CLUSTER_NAME非空,且配置文件里确实存在proxmox.cluster.name资源处理器;令牌形态检查(L273-L300):校验 UUID 形态,并专门检测夹带的空白字符(Collector 会原样发送带空格的令牌,导致服务端永远匹配不上);Collector 自监控(L303-L329):从命名空间内 scrape127.0.0.1:8888/metrics,汇总otelcol_receiver_accepted_metric_points、otelcol_exporter_sent_metric_points与otelcol_exporter_send_failed_*三组计数器 ——send_failed 0说明出网/URL/TLS 有问题;VERDICT(L437-L484):按优先级裁决 —— 容器未运行 → 令牌被拒(经典陷阱)→ 出网失败 → exporter 无指标 → 集群名缺失 → 令牌含空白/形态错误 → 令牌有效且健康(此时若仪表盘仍显示 Disconnected,提示等待 2–5 分钟的状态翻转周期,并检查是否因改名出现了一个新集群条目)。OneUptime 中不出现集群查 Collector 日志:docker logs oneuptime-proxmox-agent—— 导出时的401意味着摄入令牌有误,connection refused 意味着ONEUPTIME_URL不对;验证 exporter 抓取本身。内置 exporter 不向宿主机发布端口,需进入其网络命名空间测试:docker run --rm --network container:oneuptime-pve-exporter curlimages/curl -s http://localhost:9221/pve?targetYOUR_PVE_HOST | head,应当打印出pve_*指标行(外置 exporter 则直接curl其host:9221);确认PROXMOX_CLUSTER_NAME已设置 —— 发现机制就是围绕proxmox.cluster.name资源属性建立的。exporter 日志出现 401 / 认证错误API Token 错误或权限不足。重新核对 Token ID 格式(userrealm!tokenname)、密钥,以及该 Token 是否对路径/持有PVEAuditor角色(privilege separation 需关闭,或权限直接授给 Token 本身)。只有节点指标,没有虚机指标虚机序列(qemu/*、lxc/*)来自 exporter 的 cluster 采集器。随附配置已启用它(cluster1scrape 参数)—— 如果你改过otel-collector-config.yaml,请恢复cluster: [1]参数。指标落到了错误的集群下OneUptime 按proxmox.cluster.name(取自PROXMOX_CLUSTER_NAME环境变量)自动注册 Proxmox 集群。首批发遥测之后再改这个值,只会新增一行集群,而不是给旧行改名。延伸阅读基于 Agent 采集的数据配置Proxmox Monitor,对节点、虚机、存储、HA、备份覆盖与复制状态设置告警,参见 Proxmox Monitor;如果你的集群用 Ceph 作为存储后端,可参考本仓库的 CephAgent 与该 Agent 配套部署;完整的安装文档源文件位于 App/FeatureSet/Docs/Content/en/telemetry/proxmox.md,Agent 目录说明见 ProxmoxAgent/README.md。【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考