Healthchecks v4.4 进阶实战与运维

Healthchecks v4.4 运维实战:后台进程体系、入站邮件 ping、周报推送、Prometheus 指标、备份恢复、数据清理、升级迁移与故障排查,全部命令带真实回显。

Healthchecks2026/10/17

Healthchecks v4.4 进阶实战与运维

目标:面向已部署的 Healthchecks v4.4,讲透后台进程体系与日常运维闭环——告警派发与周报推送的进程化托管、入站邮件 ping、Prometheus 指标接入、备份恢复演练、数据清理、版本升级迁移,以及真实故障排查记录。已在 Ubuntu 22.04 源码部署环境实测通过,Docker 部署差异单独标注。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • Healthchecks:v4.4(源码部署 /opt/healthchecks,venv /opt/venv,运行用户 hc)
  • 数据库:PostgreSQL 16.15(PGDG 仓库,集群端口 5433,库 hc/用户 hc/密码 q1w2e3r4)
  • systemd 服务:healthchecks-web、healthchecks-sendalerts;环境文件 /etc/healthchecks
  • 管理账号:admin@example.org;演示 Check:backup-db(UUID 83459720-9231-40d0-b7c6-5d237327951d)
  • API Key:hcw_WEvuuwb0tRz3jxAhM3BfYkT2bGAi
  • 官方镜像部署补充验证:healthchecks/healthchecks:v4.4 + postgres:16(Compose v5.5.1)

二、软件概览:后台进程体系

Healthchecks 是典型的「Web + 异步任务」双轨架构,自托管运维的核心就是把这几类进程管明白:

进程/命令职责部署形态与托管方式
web(gunicorn/uwsgi)Web 界面、API、接收 ping源码:systemd healthchecks-web;镜像:内置 uwsgi
manage.py sendalerts每 2 秒扫描到期 Check,状态翻转时发告警常驻进程;源码:systemd 常驻;镜像:内置自动运行
manage.py sendreports周报/月报/提醒邮件常驻进程(同上,镜像内置)
manage.py smtpd入站邮件 ping 的 SMTP 服务器可选;镜像用 SMTPD_PORT 启用
manage.py pruneobjects清理 S3 上过期的 ping body批处理;配置了 S3 才有意义
manage.py prunetokenbucket清理过期的令牌桶(限流)记录批处理;建议每周 cron
manage.py settelegramwebhookTelegram 渠道回调注册一次性

💡 技术拓展:为什么 sendalerts 必须常驻而不能用 cron 每分钟跑一次?早期版本(v3.x 及以前)sendalerts 支持单次运行模式,社区文档普遍建议 crontab 每分钟调用;v4.4 的实现里循环写在 handle() 内部(while not self.shutdown: ... sleep(2)),启动即常驻、靠信号优雅退出。用 cron 调常驻进程会每分钟叠一个进程,务必以 systemd 服务或镜像内置编排为准。

三、实战示例

3.1 告警派发的进程化托管与验证

healthchecks-sendalerts.service 单元(与 web 同构,EnvironmentFile 共享邮件配置):

[Unit]
Description=Healthchecks alert dispatcher (sendalerts)
After=network.target postgresql.service
Wants=postgresql.service

[Service]
Type=simple
User=hc
Group=hc
EnvironmentFile=/etc/healthchecks
WorkingDirectory=/opt/healthchecks
ExecStart=/opt/venv/bin/python manage.py sendalerts
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

启用并确认:

systemctl enable --now healthchecks-sendalerts
systemctl is-active healthchecks-sendalerts
Created symlink /etc/systemd/system/multi-user.target.wants/healthchecks-sendalerts.service → /etc/systemd/system/healthchecks-sendalerts.service.
active

端到端验证方法(实测记录):把演示 Check backup-db 用 API 改成 60 秒周期 + 60 秒宽限并停止 ping,约 2 分钟后状态转 down,告警邮件随即发出。邮件侧用 aiosmtpd 调试服务器抓包(python -m aiosmtpd -n -l 127.0.0.1:2525,/etc/healthchecks 的 EMAIL_HOST=127.0.0.1/EMAIL_PORT=2525 指向它),真实抓到的两封邮件主题:

Subject: UP | backup-db
Subject: DOWN | backup-db

DOWN 邮件正文(节选)说明了判定原因与现状摘要:

The check "backup-db" has gone down.
Reason: success signal did not arrive on time, grace time passed.
Total pings: 8 (since Oct 16, 2026)
Status changed to down at: Fri, 16 Oct 2026 15:42:22 +0000

验证后把 Check 周期改回正式值(POST /api/v3/checks/<uuid> 传回 schedule/grace)。

3.2 入站邮件 ping(Email-to-Ping)

适用场景:任务所在机器没有出站 HTTP 但能发邮件,或想留一份「任务输出全文」在 ping 记录里。三步启用:

第一步:配置收件域名(PING_EMAIL_DOMAIN)并在 /etc/healthchecks 补充后重启服务(源码部署直接手动起 smtpd):

cd /opt/healthchecks
set -a && . /etc/healthchecks && set +a
(nohup su hc -s /bin/bash -c "cd /opt/healthchecks && exec /opt/venv/bin/python manage.py smtpd --port 2526" > /tmp/hcsmtpd.log 2>&1 &)

实测输出:

Starting SMTP listener on 0.0.0.0:2526 ...

第二步:向 Check 的入站地址发邮件。地址格式 <check-uuid>@<PING_EMAIL_DOMAIN>(Check 详情页可复制)。实测用 Python smtplib 发送:

# /tmp/mailping.py
import smtplib
from email.message import EmailMessage
m = EmailMessage()
m["From"] = "cron@db-server.internal"
m["To"] = "83459720-9231-40d0-b7c6-5d237327951d@localhost"
m["Subject"] = "backup-db report"
m.set_content("backup finished OK, size=1.2G")
with smtplib.SMTP("127.0.0.1", 2526) as s:
    s.send_message(m)
print("mail sent")
python3 /tmp/mailping.py
mail sent

第三步:确认 ping 已落库(n_pings +1,且 Check 由 down 转 up):

n_pings: 11 status: up

⚠️ 注意两点:① manage.py smtpd 是入站专用服务器,只接受 Check 地址(<uuid>@域名),发给 admin@example.org 这类普通地址会拒收 550 5.1.1 Recipient rejected——所以它不能当出站邮件的测试端;② 入站邮件的正文会存进 ping 记录(受 PING_BODY_LIMIT 约束),配合 Check 的「subject/body 关键字过滤」可以实现「邮件里含 FAIL 才算失败」的语义。

镜像部署启用方式:.env 加 SMTPD_PORT=2526 并在 compose 里为 web 服务映射该端口,容器启动时自动拉起 smtpd,无需手动运行。

3.3 周报/月报推送(sendreports)

用户级开关在「Profile → Reports」(off/weekly/monthly),配合 next_report_date 到期发送。实测强制触发一次周报:

第一步:把账号设为周报且将下次发送时间拨到过去:

# /tmp/rep.py
from hc.accounts.models import Profile
from django.utils.timezone import now
from datetime import timedelta as td
p = Profile.objects.get(user__email="admin@example.org")
p.reports = "weekly"
p.next_report_date = now() - td(minutes=1)
p.save()
print("reports:", p.reports, "next_report_date:", p.next_report_date)
cd /opt/healthchecks
/opt/venv/bin/python manage.py shell < /tmp/rep.py
reports: weekly next_report_date: 2026-10-16 15:44:41.461047+00:00

第二步:运行 sendreports(v4.4 中它同样是常驻进程,不传 --loop 时处理完到期项即退出,适合演练与 cron 每小时兜底):

set -a && . /etc/healthchecks && set +a
/opt/venv/bin/python manage.py sendreports

实测输出:

sendreports is now running
Done.

第三步:在 aiosmtpd 抓包端确认周报邮件发出:

Subject: Weekly Report

💡 说明:周报内容含项目内 Check 的在线率/掉线摘要,是低频运维(如领导周会)的好抓手。若 Done. 但没发信,多半是 next_report_date 已在处理中被推进(乐观锁设计,防止重复发送),重新把时间拨过去即可;真正没配置 SMTP 时报 AssertionError: No SMTP configuration,先补环境变量(记得 set -a; . /etc/healthchecks; set +a)。

3.4 Prometheus 指标接入

配置 METRICS_KEY(默认未启用)后开放 /api/v3/metrics/ 指标文档端点,供官方 exporter 抓取:

echo "METRICS_KEY=q1w2e3r4-metrics" >> /etc/healthchecks
systemctl restart healthchecks-web

实测两种请求(无密钥 403,带密钥返回抓取游标 JSON):

无密钥 -> 403
{"ts": 1792166213, "max_ping_id": 11, "max_notification_id": 6, "num_unprocessed_flips": 0}

接入 Prometheus:用官方 healthchecks-exporter(社区)或自写脚本定期拉取该 JSON,num_unprocessed_flips(未处理的翻转数)持续 > 0 即 sendalerts 积压,max_ping_id 增速即 ping 流量水位。Check 级别的 up/down 总览可直接用全局 Badge 嵌入看板。

3.5 备份与恢复演练

备份:PG 在线逻辑备份(不锁表):

su postgres -c "pg_dump -p 5433 hc" > /tmp/hc-backup.sql
ls -lh /tmp/hc-backup.sql
grep -c "^CREATE TABLE" /tmp/hc-backup.sql

实测输出:

-rw-r--r-- 1 root root 72K Oct 16 15:48 /tmp/hc-backup.sql
23

恢复演练(新库验证备份可用):

echo "CREATE DATABASE hc_restore;" | su postgres -c "psql -p 5433"
su postgres -c "psql -p 5433 -d hc_restore < /tmp/hc-backup.sql" 2>&1 | tail -2

实测输出(节选):

CREATE DATABASE
ALTER TABLE
ALTER TABLE

备份策略建议:每日 pg_dump(加 --clean --if-exists 便于整库回灌),保留 7 天滚动 + 每周一份异地;/etc/healthchecks 与 hc/local_settings.py(含 SECRET_KEY)一并纳入备份——SECRET_KEY 丢失等于 API Key 全部报废。SQLite 形态更简单:停写窗口拷贝 hc.sqlite 文件,或 sqlite3 hc.sqlite ".backup '/tmp/hc.sqlite.bak'"。

3.6 数据清理

ping 记录与令牌桶随时间增长,两个清理命令实测:

cd /opt/healthchecks
/opt/venv/bin/python manage.py pruneobjects
/opt/venv/bin/python manage.py prunetokenbucket

实测输出:

Object storage is not configured
Done! Pruned 0 token bucket entries

解读:pruneobjects 清理 S3/MinIO 上的过期 ping body,未配置 S3_* 时如上直接退出;prunetokenbucket 清理限流表(0 条说明无残留)。数据库内 ping 行的保留条数由 PING_LOG_LIMIT(默认 100)控制,每次新 ping 到达时按 Check 裁剪,无需人工干预。建议给 prunetokenbucket 加每周 cron:

echo "0 4 * * 0 cd /opt/healthchecks && /opt/venv/bin/python manage.py prunetokenbucket" | crontab -

3.7 升级迁移

官方镜像部署(推荐路径,实测 v4.3 → v4.4):升级 = 换 tag + 重建,新容器启动时 pre-app hook 自动执行 migrate:

docker pull healthchecks/healthchecks:v4.4
# docker-compose.yml 中镜像 tag 改为 v4.4 后:
docker compose pull web && docker compose up -d web

实测启动日志与新库状态核对:

web-1  | running "exec:./manage.py migrate" (pre app)...
web-1  | Operations to perform:
web-1  |   No migrations to apply.
升级后 checks: ['job-nightly', 'My First Check']

(v4.3 → v4.4 数据库结构兼容,迁移集相同;若某次升级有新迁移,日志里会出现 Applying <app>.<migration>... OK 行,属正常。)

源码部署升级路径(标准五步):

# 1) 备份数据库(见 3.5)
su postgres -c "pg_dump -p 5433 hc" > /tmp/hc-pre-upgrade.sql
# 2) 停服务
systemctl stop healthchecks-web healthchecks-sendalerts
# 3) 替换程序文件(保留 hc/local_settings.py 与 static-collected/)
cd /tmp && curl -LO https://github.com/healthchecks/healthchecks/archive/refs/tags/v4.5.tar.gz
tar xzf v4.5.tar.gz
rsync -a --exclude 'hc/local_settings.py' --exclude 'static-collected' healthchecks-4.5/ /opt/healthchecks/
# 4) 更新依赖并迁移
/opt/venv/bin/pip install -r /opt/healthchecks/requirements.txt
cd /opt/healthchecks && /opt/venv/bin/python manage.py migrate
# 5) 启动并验证
systemctl start healthchecks-web healthchecks-sendalerts
curl -s http://127.0.0.1:8000/accounts/login/ -o /dev/null -w "%{http_code}\n"

⚠️ 注意:跨多个 minor 版本升级时,逐版本升(4.2→4.3→4.4)比直接跳级稳;每次升级前 pg_dump 是底线。版本变更后用 manage.py shell -c "import hc; print(hc.__version__)" 核对实际代码版本。

3.8 服务健康巡检脚本

一条命令巡检全栈(可直接放进 cron 或 CI):

systemctl is-active healthchecks-web healthchecks-sendalerts
curl -s http://127.0.0.1:8000/api/v3/status/ -o /dev/null -w "status api -> %{http_code}\n"
su postgres -c "pg_isready -p 5433 -d hc"

实测输出:

active
active
status api -> 200
/tmp/pg_isready.KFQevT:5433 - accepting connections

四、常见问题(FAQ)

Q1:告警邮件发送失败,日志报 SMTPRecipientsRefused?

实测报错(sendalerts 日志中):

smtplib.SMTPRecipientsRefused: {'admin@example.org': (550, b'5.1.1 Recipient rejected')}

原因就是出站 SMTP 指到了 Healthchecks 自家的入站 smtpd(它只收 Check 地址)。解决:出站 EMAIL_HOST 指向真正的邮件服务器;调试抓包用通用调试服务器(python -m aiosmtpd -n -l 127.0.0.1:2525)。区分口诀:收任务邮件用 smtpd(入站),发告警邮件用 EMAIL_HOST(出站)。

Q2:num_unprocessed_flips 一直大于 0?

翻转事件积压,说明 sendalerts 没在跑或跑挂了。排查:systemctl is-active healthchecks-sendalerts;看日志 journalctl -u healthchecks-sendalerts -n 100;若频繁崩溃重启,确认 /etc/healthchecks 权限(600,hc 用户可读)与数据库连接参数。

Q3:手动执行管理命令报 AssertionError: No SMTP configuration?

systemd 环境文件只对服务进程生效,shell 手动执行要自己加载:set -a; . /etc/healthchecks; set +a; manage.py <命令>(3.3 实测踩过)。Docker 部署用 docker compose run --rm web ... 自动继承容器环境,无此问题。

Q4:升级后页面 500?

三个高频原因:① 漏跑 migrate(新版本有新迁移);② 依赖没装全(requirements.txt 之外,pruneobjects/S3 需要 pip install minio,漏装实测报 ModuleNotFoundError: No module named 'minio');③ local_settings.py 覆盖了新版已改名的字段。按 3.7 的五步走并用 manage.py check 预检。

Q5:PostgreSQL 版本不满足报错?

django.db.utils.NotSupportedError: PostgreSQL 15 or later is required (found 14.24).——Ubuntu 22.04 默认源是 PG 14,用 PGDG 仓库装 16(详见《Healthchecks v4.4 Ubuntu 22.04 安装指南》4.2 与 FAQ)。

Q6:ping 记录太多,怎么瘦身?

单 Check 保留条数由 PING_LOG_LIMIT(默认 100)自动裁剪,无需手工删;S3 body 由 pruneobjects 清。表膨胀严重时对 api_ping 等表做 VACUUM ANALYZE;再不够就降低 PING_BODY_LIMIT 从源头减负。

Q7:Docker 部署怎么执行这些管理命令?

把本文的 manage.py <命令> 换成 docker compose run --rm web /opt/healthchecks/manage.py <命令>;sendalerts/sendreports/smtpd 镜像内置自动运行,无需也不应再手工启动;日志统一看 docker compose logs web。

五、参考链接