这是一篇“日常排查记录”模板文章。我会尽量只写事实 + 证据链,避免凭感觉下结论。
TL;DR
- 问题现象:DNS 服务跑着跑着失去响应;整机出现明显顿卡;偶发(疑似)掉盘/IO 异常。
- 触发特征:随机出现,通常在连续运行 1 天+ 后发生。
- 恢复方式:关机断电并静置一段时间后恢复正常。
- 当前结论(概率表达):____(例如:高概率与散热/供电/存储控制器复位相关)。
影响范围
- 直接影响:____(例如:内网所有设备 DNS 解析超时/失败)。
- 间接影响:____(例如:依赖域名解析的服务/容器全部异常)。
- 影响时段:____(开始时间/持续多久/是否自动恢复)。
环境信息(可复现前提)
硬件
- CPU:Intel® N100(4C/4T,6MB Cache,最高 3.4GHz)
- GPU:Intel® UHD Graphics
- 内存:8GB LPDDR5(单通道,板载,4800MHz)
- 存储:UFS 2.1 256G
- 无线:Intel AX200/201(Wi‑Fi 6 / Bluetooth 5.2)
- 有线:2.5G RJ45 ×1(支持 PoE IEEE 802.3at)
- 接口:USB 3.2 Gen2 Type‑A ×2;USB 3.2 Gen2 Type‑C ×1(Alt DP/PD);HDMI ×1
- 电源:65W USB‑C Power Delivery 适配器
软件
- 实际运行系统:Linux(当前内核版本为
6.8.12-5-pve;出厂为 Windows 11 Home) - 内核版本(如 Linux):
6.8.12-5-pve - 引导加载器(GRUB):
grub2 2.06-13+pmx2 - DNS 软件:____(dnsmasq / unbound / AdGuard Home / Pi‑hole / 其它)
- 部署方式:____(systemd / Docker / 其它)
- 其它常驻服务:____
- 日志策略:____(落盘频率/轮转策略/是否写入同一磁盘)
问题描述(只写事实)
- 首次出现时间:____
- 复现频率:大约每 ____ 小时/天一次(随机)。
- 故障时可观测症状:
- DNS:____(超时/拒绝/解析慢)
- 系统:____(SSH/远程桌面是否可达?CPU/内存是否飙升?)
- 存储:____(挂载点消失/只读/IO error/设备重置/掉盘)
- 网络:____(ping 是否丢包?网卡是否 reset?)
- 故障后的恢复动作:____(关机静置 ____ 分钟后恢复;“重启”是否也能恢复:____)
- 与负载的关系:____(高 QPS/日志写入/其它任务是否更容易触发)
当场止血(按时间线)
目的:先恢复核心服务,避免数据损坏,再谈定位。
- T+0:____(例如:将上游 DNS 临时切换到路由器/公网 DNS)
- T+5m:____(例如:停止 DNS 服务/停止高 IO 服务)
- T+10m:____(例如:采集日志/抓取指标快照)
- 结果:____(是否恢复?持续多久?)
我关心的“数据结构”(证据链要对齐时间戳)
- 一个时间线:故障开始时间、温度峰值、IO 错误、服务超时,必须能对齐。
- 一个核心问题:是“DNS 服务死了”,还是“机器/存储子系统死了导致 DNS 表现为死”。
假设清单(按优先级)
- H1:散热/过热导致保护或降频,继而触发系统不稳定
- 证据:____(温度曲线/thermal throttle log)
- H2:供电不稳(PD/PoE/适配器)导致存储控制器或系统 reset
- 证据:____(kernel reset/电源事件/规律性)
- H3:存储介质或控制器问题(UFS/NVMe/SATA)导致 IO 卡死或设备消失
- 证据:____(I/O error、timeout、device reset、SMART/health)
- H4:软件层资源耗尽(FD/内存泄漏/日志写爆/IO 打满)
- 证据:____(ulimit、内存曲线、iowait、磁盘写入量)
- H5:驱动/内核 bug(省电策略/设备电源管理)
- 证据:____(特定模块报错、升级/降级内核后变化)
数据采集(故障发生时我必须抓到什么)
不要靠“感觉像过热/像掉盘”,用日志说话。
- 温度/风扇:____(例如 Linux:
sensors、/sys/class/thermal/;Windows:HWiNFO) - 系统日志:____(Linux:
journalctl;Windows:事件查看器) - 存储相关日志:____(I/O error、timeout、reset、file system remount read-only)
- 资源指标:____(CPU、load、iowait、内存、swap、磁盘吞吐)
- DNS 指标:____(QPS、缓存命中、上游延迟、失败率)
- 客户端验证:____(
dig/nslookup的失败表现)
关键证据(粘 3~5 段就够)
- 证据 1(定性):
text[time] ____
- 证据 2(支持链路):
text[time] ____
- 证据 3(排除项):
text[time] ____
排查过程(尝试 → 观察 → 结论)
尝试 A:____
- 改动:____
- 观察:____
- 结论:____(支持/否定哪条假设)
尝试 B:____
- 改动:____
- 观察:____
- 结论:____
尝试 C:____
- 改动:____
- 观察:____
- 结论:____
结论(概率表达,不装确定)
- 高概率主因:____
- 次要因素:____
- 我排除的方向:____(必须给证据)
解决方案(短期止血 vs 长期修复)
短期止血(马上能做)
- ____(例如:加强散热/开盖/外接风扇)
- ____(例如:限制功耗/关闭省电策略)
- ____(例如:降低日志落盘/开启轮转/把日志写到另一块盘)
长期修复(一次到位)
- ____(例如:更换电源/更换存储/更新 BIOS/固件)
- ____(例如:调整机箱风道/加导热垫/改善安装位置)
- ____(例如:升级/更换系统与内核版本)
验证标准
- 连续运行:____ 天无复现
- 温度上限:CPU ≤ ____°C;存储 ≤ ____°C
- 日志:无 I/O error / reset / remount read-only
复盘
- 这次最值钱的证据:____
- 下次更早做的事:____(例如:加监控、告警、故障自动抓日志)
- 仍未解决的问题:____
尝试方案:依赖 192.168.22.12(PVE 宿主)上的监控 LXC(192.168.22.19)持续监测 192.168.22.18(Minisforum)
目标:把“感觉像过热/像掉盘/像 DNS 挂了”变成一条可对齐时间戳的证据链:温度曲线 + IO/内核报错计数 + DNS 可用性探测 + 主机可达性。
注意:不要把账号密码写进任何配置文件/仓库。下面所有登录步骤都默认你手动输入密码或(更推荐)使用 SSH key。
额外坑:22 端口通,但 ssh 仍然卡住/断线(跨网段更常见)
这个坑很容易误导人:你看到 nc 显示 22/tcp open,就以为网络没问题;但 ssh 仍然会在握手阶段卡住,最后报超时或 Broken pipe。
场景(这次真实遇到的拓扑)
- 客户端网段:
192.168.11.0/24 - 目标主机:
192.168.22.12(PVE) - 同网段跳板/对照:
192.168.22.18(从这里ssh到.12通畅) - 同时发生的信号:DNS 服务(例如
192.168.22.53:53)出现超时(反查/解析失败会放大 SSH 的握手耗时)
现象(典型表现)
nc -vz -G 2 192.168.22.12 22显示 succeeded(TCP 三次握手没问题)ssh root@192.168.22.12卡住,随后出现:ssh_dispatch_run_fatal: Connection to 192.168.22.12 port 22: Operation timed out- 或
Read from remote host 192.168.22.12: Operation timed out/client_loop: send disconnect: Broken pipe
快速判定(先把“端口通”细分)
- 看 SSH banner 是否能立即返回(只测协议,不涉及认证):
bashnc -v 192.168.22.12 22
正常情况会快速看到类似 SSH-2.0-OpenSSH_...。如果连上但 banner 很久不出/不出,说明问题更像在 sshd/系统层(例如 DNS 反查阻塞、系统负载、网络策略导致后续数据不稳定),不是“单纯端口被挡”。
- 抓 SSH 卡在哪一步(留证据用):
bashssh -vvv -o ConnectTimeout=5 -o ServerAliveInterval=5 -o ServerAliveCountMax=1 root@192.168.22.12
最小修复(优先消灭 DNS/GSSAPI 造成的特殊情况)
如果你能从同网段主机(例如 .22.18)登录到 .22.12,优先在 服务端做这两个改动(对内网环境通常更稳、更“少坑”):
- 编辑
.22.12的/etc/ssh/sshd_config,确保存在:
UseDNS noGSSAPIAuthentication no
- 校验并重启:
bashsshd -t && systemctl restart sshsystemctl status ssh --no-pager
直觉解释:当 DNS/反查不稳定时,
UseDNS yes可能让 SSH 在握手/审计阶段等待解析结果;把它关掉能让“特殊情况”消失。
如果仍然不稳:按“跨网段三件套”继续排除
- 回程路由是否正确(目标机必须知道怎么回
192.168.11.0/24):
baship route get 192.168.11.12
- 防火墙/ACL:除了放行
22/tcp,还要确保回程方向与状态跟踪规则一致(尤其是网关/NAT/策略路由)。 - MTU/分片问题:跨网段、隧道、PPPoE 场景容易出现“能握手但数据阶段不稳”;建议在 Linux 上用带 DF 的大包
ping做一次验证(必要时先临时把 MSS/MTU 调小验证)。
总体架构(最少但够用)
- 192.168.22.19(监控端 LXC,运行在 192.168.22.12 这台 PVE 上):Prometheus + Grafana + blackbox_exporter(可选 Pushgateway)
- 192.168.22.18(被监控端):nodeexporter(主机指标)+(可选)smartctlexporter(磁盘健康)+ 自定义 textfile 指标(内核/IO error 计数)
这套东西的“数据结构”很简单:
- 时序指标(Prometheus):每 15s 抓一次,故障前后至少覆盖 48 小时。
- 主动探测(blackbox_exporter):从
.19主动 ping / tcp 探测.18/.54,区分“机器死了”和“服务死了”。 - 告警(可选):故障发生时把时间戳钉死(邮件/Telegram/飞书随你,先把规则跑起来)。
尝试 D:监控栈落地(Prometheus + Grafana + blackbox_exporter)
D0. 前置检查(网络与端口)
在 192.168.22.19 上确认能到达 192.168.22.18:
bashping 192.168.22.18Test-NetConnection 192.168.22.18 -Port 22
后续会用到的端口(按默认值):
.18:9100node_exporter.18:9633smartctl_exporter(可选).19:9090Prometheus.19:3000Grafana.19:9115blackbox_exporter.19:9091Pushgateway(可选)
如果你有防火墙/安全组,先放行
.19 -> .18的 9100/9633/22,以及.19 -> .54的 53/3000(只在内网开放就行)。
D1. 在 192.168.22.18 部署 node_exporter(systemd 方式,最稳)
在 .18 执行(版本号你可以换新,但别用“latest”,排查时要可追溯):
bashexport VER="1.7.0"curl -fsSL -o /tmp/node_exporter.tar.gz "https://github.com/prometheus/node_exporter/releases/download/v${VER}/node_exporter-${VER}.linux-amd64.tar.gz"tar -C /tmp -xzf /tmp/node_exporter.tar.gzinstall -m 0755 /tmp/node_exporter-${VER}.linux-amd64/node_exporter /usr/local/bin/node_exporteruseradd --system --no-create-home --shell /usr/sbin/nologin nodeexp || truemkdir -p /var/lib/node_exporter/textfile_collectorchown -R nodeexp:nodeexp /var/lib/node_exportercat >/etc/systemd/system/node_exporter.service <<'EOF'[Unit]Description=Prometheus Node ExporterAfter=network-online.targetWants=network-online.target[Service]User=nodeexpGroup=nodeexpExecStart=/usr/local/bin/node_exporter \--web.listen-address=:9100 \--collector.textfile.directory=/var/lib/node_exporter/textfile_collectorRestart=on-failureRestartSec=2[Install]WantedBy=multi-user.targetEOFsystemctl daemon-reloadsystemctl enable --now node_exportersystemctl status node_exporter --no-pager
验证(在 .12 或任意内网机器):
bashcurl -fsS http://192.168.22.18:9100/metrics | head
D2.(可选但强烈建议)在 192.168.22.18 增加“内核/IO 错误计数”自定义指标
你要抓的是这种关键字:I/O error|timeout|reset|remount read-only|EXT4-fs error|BTRFS error|blk_update_request
做法:用 node_exporter 的 textfile collector 每分钟吐一个计数指标(避免你事后翻日志翻到吐)。
bashcat >/usr/local/bin/collect_kernel_error_metrics.sh <<'EOF'#!/usr/bin/env bashset -euo pipefailOUT="/var/lib/node_exporter/textfile_collector/kernel_errors.prom"TMP="$(mktemp)"# Count kernel messages in last 10 minutes (adjust if needed)COUNT="$(journalctl -k --since "10 min ago" --no-pager 2>/dev/null | \grep -Eic 'I/O error|timeout|reset|remount read-only|EXT4-fs error|BTRFS error|blk_update_request|nvme|ufs' || true)"NOW="$(date +%s)"{echo "# HELP kernel_error_events_10m Number of kernel error-like events in last 10 minutes"echo "# TYPE kernel_error_events_10m gauge"echo "kernel_error_events_10m ${COUNT}"echo "# HELP kernel_error_scrape_time_seconds Last collect time"echo "# TYPE kernel_error_scrape_time_seconds gauge"echo "kernel_error_scrape_time_seconds ${NOW}"} >"${TMP}"mv "${TMP}" "${OUT}"EOFchmod +x /usr/local/bin/collect_kernel_error_metrics.shcat >/etc/systemd/system/kernel-error-metrics.service <<'EOF'[Unit]Description=Collect kernel error metrics for node_exporter textfile collector[Service]Type=oneshotExecStart=/usr/local/bin/collect_kernel_error_metrics.shEOFcat >/etc/systemd/system/kernel-error-metrics.timer <<'EOF'[Unit]Description=Run kernel error metrics collector every 60s[Timer]OnBootSec=30sOnUnitActiveSec=60sAccuracySec=1s[Install]WantedBy=timers.targetEOFsystemctl daemon-reloadsystemctl enable --now kernel-error-metrics.timersystemctl list-timers --no-pager | grep kernel-error-metrics || true
验证:
bashcurl -fsS http://192.168.22.18:9100/metrics | grep -E '^kernel_error_events_10m|^kernel_error_scrape_time_seconds' || true
D3.(可选)在 192.168.22.18 部署 smartctl_exporter(磁盘健康)
说明:如果你的“UFS 2.1”设备不支持 SMART/health,这一步可能拿不到有效数据;但做了不亏(能拿到就直接中大奖)。
bashapt-get updateapt-get install -y smartmontoolsexport VER="0.12.0"curl -fsSL -o /tmp/smartctl_exporter.tar.gz "https://github.com/prometheus-community/smartctl_exporter/releases/download/v${VER}/smartctl_exporter-${VER}.linux-amd64.tar.gz"tar -C /tmp -xzf /tmp/smartctl_exporter.tar.gzinstall -m 0755 /tmp/smartctl_exporter-${VER}.linux-amd64/smartctl_exporter /usr/local/bin/smartctl_exporteruseradd --system --no-create-home --shell /usr/sbin/nologin smartctl-exp || truecat >/etc/systemd/system/smartctl_exporter.service <<'EOF'[Unit]Description=Prometheus Smartctl ExporterAfter=network-online.targetWants=network-online.target[Service]User=smartctl-expGroup=smartctl-expExecStart=/usr/local/bin/smartctl_exporter --web.listen-address=:9633Restart=on-failureRestartSec=2[Install]WantedBy=multi-user.targetEOFsystemctl daemon-reloadsystemctl enable --now smartctl_exporter
验证:
bashcurl -fsS http://192.168.22.18:9633/metrics | head
D4. 在 192.168.22.12(PVE)用 LXC 部署 Prometheus + Grafana + blackbox_exporter(推荐)
你说
.12也是 PVE 主机,那就别在宿主机上堆 Docker 了:直接建一个 LXC 容器跑监控栈,数据/配置独立、可迁移、也更符合“排查期可控变更”的原则。
D4.1 在 PVE(.12)创建一个 Debian LXC 容器
你可以用 PVE Web UI 创建,也可以用命令行。下面是命令行示例(按你的环境替换 <CTID>、<GW>;监控 LXC IP 固定为 192.168.22.19):
bash# 在 PVE 宿主机 192.168.22.12 执行pct create <CTID> local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \--hostname monitoring \--cores 2 --memory 2048 --swap 512 \--rootfs local-lvm:8 \--net0 name=eth0,bridge=vmbr0,ip=192.168.22.19/24,gw=<GW> \--unprivileged 1# 让容器内 systemd 工作更顺滑pct set <CTID> -features keyctl=1,nesting=1pct start <CTID>
这篇文章里我们把监控 LXC 的 IP 固定为:
192.168.22.19。
D4.2 在容器内安装 Prometheus(systemd)
进入容器:
bashpct exec <CTID> -- bash
在容器内执行:
bashapt-get updateapt-get install -y ca-certificates curl taruseradd --system --no-create-home --shell /usr/sbin/nologin prometheus || truemkdir -p /etc/prometheus /var/lib/prometheuschown -R prometheus:prometheus /etc/prometheus /var/lib/prometheusexport VER="2.54.1"curl -fsSL -o /tmp/prometheus.tar.gz "https://github.com/prometheus/prometheus/releases/download/v${VER}/prometheus-${VER}.linux-amd64.tar.gz"tar -C /tmp -xzf /tmp/prometheus.tar.gzinstall -m 0755 /tmp/prometheus-${VER}.linux-amd64/prometheus /usr/local/bin/prometheusinstall -m 0755 /tmp/prometheus-${VER}.linux-amd64/promtool /usr/local/bin/promtoolcp -r /tmp/prometheus-${VER}.linux-amd64/consoles /etc/prometheus/cp -r /tmp/prometheus-${VER}.linux-amd64/console_libraries /etc/prometheus/chown -R prometheus:prometheus /etc/prometheus
创建 /etc/prometheus/prometheus.yml(抓 .18 的 exporter + 主动探测;DNS 用 .54 的 AdGuardDNS):
yamlglobal:scrape_interval: 15sevaluation_interval: 15sscrape_configs:- job_name: "minisforum-node"static_configs:- targets: ["192.168.22.18:9100"]- job_name: "minisforum-smartctl"static_configs:- targets: ["192.168.22.18:9633"]- job_name: "blackbox-icmp"metrics_path: /probeparams:module: [icmp]static_configs:- targets:- 192.168.22.18- 192.168.22.54relabel_configs:- source_labels: [__address__]target_label: __param_target- source_labels: [__param_target]target_label: instance- target_label: __address__replacement: 127.0.0.1:9115- job_name: "blackbox-tcp"metrics_path: /probeparams:module: [tcp_connect]static_configs:- targets:- 192.168.22.18:22- 192.168.22.18:9100- 192.168.22.54:53- 192.168.22.54:3000relabel_configs:- source_labels: [__address__]target_label: __param_target- source_labels: [__param_target]target_label: instance- target_label: __address__replacement: 127.0.0.1:9115
创建 systemd 服务:
bashcat >/etc/systemd/system/prometheus.service <<'EOF'[Unit]Description=PrometheusAfter=network-online.targetWants=network-online.target[Service]User=prometheusGroup=prometheusExecStart=/usr/local/bin/prometheus \--config.file=/etc/prometheus/prometheus.yml \--storage.tsdb.path=/var/lib/prometheus \--storage.tsdb.retention.time=30dRestart=on-failureRestartSec=2[Install]WantedBy=multi-user.targetEOFsystemctl daemon-reloadsystemctl enable --now prometheussystemctl status prometheus --no-pager
D4.3 在容器内安装 blackbox_exporter(systemd)
bashuseradd --system --no-create-home --shell /usr/sbin/nologin blackbox || truemkdir -p /etc/blackbox_exporterchown -R blackbox:blackbox /etc/blackbox_exporterexport VER="0.25.0"curl -fsSL -o /tmp/blackbox.tar.gz "https://github.com/prometheus/blackbox_exporter/releases/download/v${VER}/blackbox_exporter-${VER}.linux-amd64.tar.gz"tar -C /tmp -xzf /tmp/blackbox.tar.gzinstall -m 0755 /tmp/blackbox_exporter-${VER}.linux-amd64/blackbox_exporter /usr/local/bin/blackbox_exportercat >/etc/blackbox_exporter/blackbox.yml <<'EOF'modules:icmp:prober: icmptimeout: 5stcp_connect:prober: tcptimeout: 5sEOFchown -R blackbox:blackbox /etc/blackbox_exportercat >/etc/systemd/system/blackbox_exporter.service <<'EOF'[Unit]Description=Prometheus Blackbox ExporterAfter=network-online.targetWants=network-online.target[Service]User=blackboxGroup=blackboxExecStart=/usr/local/bin/blackbox_exporter \--config.file=/etc/blackbox_exporter/blackbox.yml \--web.listen-address=:9115Restart=on-failureRestartSec=2[Install]WantedBy=multi-user.targetEOFsystemctl daemon-reloadsystemctl enable --now blackbox_exportersystemctl status blackbox_exporter --no-pager
D4.4 在容器内安装 Grafana(systemd)
不要把 Grafana 的 admin 密码写进任何配置文件/仓库。建议安装完后手动设置。
bashapt-get install -y apt-transport-https software-properties-common wget gpgmkdir -p /etc/apt/keyringswget -qO- https://apt.grafana.com/gpg.key | gpg --dearmor >/etc/apt/keyrings/grafana.gpgecho "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" >/etc/apt/sources.list.d/grafana.listapt-get updateapt-get install -y grafanasystemctl enable --now grafana-serversystemctl status grafana-server --no-pager
设置 admin 密码(在容器内执行):
bashgrafana-cli admin reset-admin-password
D4.5 访问地址与最小验证
- Prometheus:
http://192.168.22.19:9090 - Grafana:
http://192.168.22.19:3000 - blackbox_exporter:
http://192.168.22.19:9115
最小验证:
bashcurl -fsS "http://192.168.22.19:9090/-/ready"curl -fsS "http://192.168.22.19:9115/probe?module=icmp&target=192.168.22.18" | head
D5. Grafana 面板与关键观察点(对应 H1~H5)
你不需要“花里胡哨的大盘”。就盯下面这些就够了:
- H1 过热/降频:
- CPU 温度(如果可见):
node_thermal_zone_temp或node_hwmon_temp_celsius - CPU load/iowait:
node_load1、rate(node_cpu_seconds_total{mode="iowait"}[5m])
- CPU 温度(如果可见):
- H2 供电/复位:
- uptime/重启点:
node_boot_time_seconds(突然变化 = reboot) - blackbox 探测:
probe_success{job=~"blackbox-.*"}
- uptime/重启点:
- H3 存储/控制器异常:
- 关键:
kernel_error_events_10m(你自己定义的) - IO time:
rate(node_disk_io_time_seconds_total[5m]) - 文件系统只读(如果发生):
node_filesystem_readonly
- 关键:
- H4 资源耗尽:
- 内存:
node_memory_MemAvailable_bytes - FD(如果启用):
node_filefd_allocated/node_filefd_maximum(视 exporter 版本)
- 内存:
- H5 驱动/省电策略/网卡 reset:
- 网络错误:
rate(node_network_receive_errs_total[5m])、rate(node_network_transmit_errs_total[5m]) - 同样看
kernel_error_events_10m的变化点
- 网络错误:
D6. 告警规则(把时间戳钉死)
你至少要有三条告警(其余都是锦上添花):
- 机器不可达(icmp probe 失败)
- DNS 端口不可达(tcp probe 到 53 失败)
- 内核/IO 错误突增(
kernel_error_events_10m超过阈值)
告警接收渠道先别纠结,先让 Prometheus “能触发告警”这件事成立;否则你复现那一刻还是会错过。
尝试 E:在 192.168.22.18 用 LXC 部署 AdGuardDNS(IP 固定为 192.168.22.54)+ DNS 真实查询探测
目标:把 DNS 业务从宿主机里隔离出来,并且把 DNS 的 IP 固定到
192.168.22.54,这样监控/告警的 target 不会因为容器漂移而失效。重点:排查“宿主机是否先死”,所以 nodeexporter / 自定义 IO 错误计数 / smartctlexporter 仍然部署在宿主
.18;DNS 服务放到容器里只是为了更可控地观测“业务侧”。
E0. 在 PVE(.18)创建 AdGuardDNS 的 LXC 容器(192.168.22.54)
示例(按你的环境替换 <CTID>、<GW>):
bash# 在 PVE 宿主机 192.168.22.18 执行pct create <CTID> local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \--hostname adguarddns \--cores 1 --memory 1024 --swap 256 \--rootfs local-lvm:4 \--net0 name=eth0,bridge=vmbr0,ip=192.168.22.54/24,gw=<GW> \--unprivileged 1pct set <CTID> -features keyctl=1,nesting=1pct start <CTID>
E1. 在容器内安装 AdGuard Home(作为 AdGuardDNS)
进入容器:
bashpct exec <CTID> -- bash
在容器内执行(固定版本,排查期可追溯):
bashapt-get updateapt-get install -y ca-certificates curl tarexport VER="0.107.57"curl -fsSL -o /tmp/adguardhome.tar.gz "https://github.com/AdguardTeam/AdGuardHome/releases/download/v${VER}/AdGuardHome_linux_amd64.tar.gz"tar -C /opt -xzf /tmp/adguardhome.tar.gz/opt/AdGuardHome/AdGuardHome -s installsystemctl status AdGuardHome --no-pager
访问初始化页面(首次配置):
- 管理口:
http://192.168.22.54:3000 - DNS:
192.168.22.54:53(UDP/TCP)
你要把内网客户端 DNS 指向
192.168.22.54。如果你有 DHCP/路由器下发 DNS,就统一从那里改,别一个个设备手动改。
E1. DNS 真实查询探测(不靠 blackbox 的“端口可达”,直接用 dig 验证解析链路)
做法:在 192.168.22.19(监控端 LXC)定时执行 dig,把“成功/失败、延迟”推送到 Pushgateway。
这一步不依赖 AdGuard 管理口账号密码,可观测性更干净。
- 在监控端(
.12的 monitoring LXC)里可选安装 Pushgateway(systemd):
bashapt-get updateapt-get install -y ca-certificates curl taruseradd --system --no-create-home --shell /usr/sbin/nologin pushgateway || truemkdir -p /etc/pushgateway /var/lib/pushgatewaychown -R pushgateway:pushgateway /etc/pushgateway /var/lib/pushgatewayexport VER="1.10.0"curl -fsSL -o /tmp/pushgateway.tar.gz "https://github.com/prometheus/pushgateway/releases/download/v${VER}/pushgateway-${VER}.linux-amd64.tar.gz"tar -C /tmp -xzf /tmp/pushgateway.tar.gzinstall -m 0755 /tmp/pushgateway-${VER}.linux-amd64/pushgateway /usr/local/bin/pushgatewaycat >/etc/systemd/system/pushgateway.service <<'EOF'[Unit]Description=Prometheus PushgatewayAfter=network-online.targetWants=network-online.target[Service]User=pushgatewayGroup=pushgatewayExecStart=/usr/local/bin/pushgateway --web.listen-address=:9091Restart=on-failureRestartSec=2[Install]WantedBy=multi-user.targetEOFsystemctl daemon-reloadsystemctl enable --now pushgatewaysystemctl status pushgateway --no-pager
- Prometheus 增加一个 scrape(在同一台监控容器里就用
127.0.0.1):
yaml- job_name: "pushgateway"honor_labels: truestatic_configs:- targets: ["127.0.0.1:9091"]
- 在监控端新增探测脚本(把
<DNS_IP>固定为192.168.22.54):
bashcat >/opt/monitoring/dns_probe_push.sh <<'EOF'#!/usr/bin/env bashset -euo pipefailDNS_IP="192.168.22.54"NAME="www.baidu.com"PUSH_URL="http://127.0.0.1:9091/metrics/job/dns_probe/instance/${DNS_IP}"OUT="$(dig +tries=1 +time=2 +stats @"${DNS_IP}" "${NAME}" A 2>/dev/null || true)"# success=1 if we got an ANSWER section with at least one A recordif echo "${OUT}" | grep -qE '^;; ANSWER SECTION:'; thenSUCCESS=1elseSUCCESS=0fi# Parse query time in ms from "Query time: 12 msec"LAT_MS="$(echo "${OUT}" | awk -F': ' '/^;; Query time:/{print $2}' | awk '{print $1}' || true)"LAT_MS="${LAT_MS:-0}"cat <<METRICS | curl -fsS --data-binary @- "${PUSH_URL}" >/dev/null# TYPE dns_probe_success gaugedns_probe_success ${SUCCESS}# TYPE dns_probe_latency_ms gaugedns_probe_latency_ms ${LAT_MS}METRICSEOFchmod +x /opt/monitoring/dns_probe_push.sh
- 用 cron/systemd timer 每 15s~60s 跑一次(排查期建议 15s):
bashcrontab -e# 每分钟 4 次*/1 * * * * /opt/monitoring/dns_probe_push.sh*/1 * * * * sleep 15; /opt/monitoring/dns_probe_push.sh*/1 * * * * sleep 30; /opt/monitoring/dns_probe_push.sh*/1 * * * * sleep 45; /opt/monitoring/dns_probe_push.sh
这一步的意义:当你复现“DNS 不通”时,你能立刻看到是 解析延迟逐步升高、还是 直接成功率掉到 0,并且与宿主机
iowait/错误计数对齐。
E2.(可选)AdGuard Home 业务指标(需要管理口凭据,务必不要进仓库)
如果你确实想看 AdGuard 自身的统计(blocked/allowed/qps/upstream latency),可以在 .12 上跑一个 AdGuard exporter,读取 AdGuard 的管理 API 再暴露成 Prometheus 指标。
关键原则:
- 凭据只放在
.12本机的 root-only 文件里(例如/opt/monitoring/secrets/adguard.env,chmod 600) - 不要写进本文仓库、更不要写进 compose 文件
(这里不强制指定 exporter,你用哪个就以其文档为准;排查阶段我更看重 E1 的 DNS 真实探测 + 宿主机指标。)
验证标准(这套监控是否“抓得住问题”)
- 连续运行:至少 7 天(你说通常 1 天+ 触发,7 天才有统计意义)
- 当复现发生时必须能回答:
- 先断的是 icmp 还是 tcp/53?
kernel_error_events_10m是否在故障前 0~10 分钟上升?- iowait 是否先飙升(
cpu iowait/disk io_time)? node_boot_time_seconds是否变化(是否实际重启)?dns_probe_success/dns_probe_latency_ms在故障前是“逐步变坏”还是“瞬断”?
Comments