Gatus 深度实战:Go 语言编写的主动式健康监控状态页——从被动告警到主动探测的运维工程革命(2026)
前言:为什么你的监控总是在用户投诉后才发现问题?
先看一个真实案例。某电商平台的技术团队在凌晨 3:17 收到了用户在社交媒体上的投诉:「你们网站下单功能挂了!」。值班工程师立刻登录 Grafana,发现订单服务已经从 2:35 开始返回 500 错误——整整 42 分钟的故障时间窗口里,没有任何一条告警被触发。
原因很简单:凌晨时段没有用户下单,订单服务的 QPS 为零。Prometheus 采到的指标是正常的(因为根本没有请求经过),Alertmanager 的告警规则是 rate(http_requests_total{status="5xx"}[5m]) > 0.01——但分母是零,rate 值也是零,永远不会超过阈值。
这不是个案。在每一个使用 Prometheus + Alertmanager 的团队中,这个盲区都存在。后台定时任务卡死?没有指标。新部署的服务忘记注册到 Service Discovery?没有指标。第三方 API 的 Key 过期了?在你调用之前,你根本不知道。
每个运维工程师都经历过这样的场景:凌晨三点收到客户投诉「服务挂了」,你手忙脚乱地打开 Grafana,发现服务其实已经挂了 40 分钟——但因为没有用户访问,Prometheus 没有任何异常指标,Alertmanager 也没触发告警。
这不是个例,而是传统「流量驱动型」监控的固有盲区。
传统的监控体系(Prometheus + Grafana + Alertmanager)本质上是被动的:它等待流量经过服务,从指标中检测异常。如果服务本身没有流量——比如一个新上线的 API 没有被调用、一个后台定时任务卡死了、一个内网微服务节点悄悄失联——传统监控就会变成瞎子。
而 Gatus 的核心哲学恰恰相反:不等待流量,主动去探测。
Gatus 是一款用 Go 编写的开源健康状态监控面板(GitHub 10k+ Star),它以固定间隔主动对你的服务端点发起检查,配合可视化状态页和多通道告警,在你还没收到投诉之前就发现问题。
本文将从架构原理、核心特性、配置实战、性能优化到生产级部署,带你彻底吃透 Gatus。
一、Gatus 是什么?核心定位与架构概览
1.1 一句话定义
Gatus = 主动健康检查 + 可视化状态页 + 多通道告警
它不是另一个 Prometheus,也不是另一个 Grafana。Gatus 解决的是一个极其具体的痛点:确保你的服务在任何时刻都是可达的、响应正常的。
1.2 与传统监控的定位差异
| 维度 | Prometheus + Alertmanager | Gatus |
|---|---|---|
| 工作方式 | 被动采集(Pull 指标) | 主动探测(Push 请求) |
| 发现故障条件 | 有流量经过且指标异常 | 无需流量,定时主动检查 |
| 覆盖场景 | 性能指标、资源利用率 | 可用性、连通性、业务逻辑 |
| 告警粒度 | 基于 Threshold 规则 | 基于响应状态码/体/延迟 |
| 用户可见性 | 需要登录 Grafana 查看 | 公开状态页,用户自助查看 |
| 复杂度 | 需要搭建全家桶 | 单二进制/Docker 一键启动 |
两者不是替代关系,而是互补关系:
- Prometheus 告诉你「CPU 80%、内存 12GB、QPS 5000」
- Gatus 告诉你「你的 /api/health 返回 500 了,已经持续 3 分钟」
1.3 架构设计
┌─────────────────────────────────────────────────┐
│ Gatus Core │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Scheduler │→│ Checker │→│ Storage │ │
│ │ (Timer) │ │ Engine │ │(Memory/SQLite│ │
│ └──────────┘ └──────────┘ │ /PostgreSQL) │ │
│ └──────────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ Alert │←│ Result │→│ Status │ │
│ │ Engine │ │ Evaluator│ │ Page (UI) │ │
│ └──────────┘ └──────────┘ └──────────────┘ │
│ ↓ │
│ ┌────────────────────────────────────────┐ │
│ │ Slack / Discord / 邮件 / 企业微信 / SMS │ │
│ │ PagerDuty / Telegram / Webhook / ... │ │
│ └────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
核心组件说明:
- Scheduler:基于 Go
time.Ticker的调度器,按配置的interval触发检查 - Checker Engine:并发执行健康检查,支持 HTTP/ICMP/TCP/DNS/gRPC/WebSocket 等协议
- Result Evaluator:评估检查结果是否符合预定义条件(状态码、响应体、延迟等)
- Storage:持久化检查结果,支持 Memory/SQLite/PostgreSQL
- Alert Engine:根据失败次数阈值触发告警,恢复时自动发送恢复通知
- Status Page:内置 Web UI,展示服务状态历史、可用性统计
1.4 为什么是 Go?
Gatus 选择 Go 语言不是偶然:
- 天然并发:goroutine 让同时检查数百个端点毫无压力
- 单二进制:编译后一个文件搞定,部署极其简单
- 低内存:生产环境几十 MB 内存,比 Node.js 方案轻量一个数量级
- 交叉编译:轻松支持 Linux/Windows/macOS/ARM 等平台
二、核心特性深度解析
2.1 灵活的条件语法——不止是检查状态码
很多健康检查工具只校验 HTTP 状态码,但 Gatus 的条件语法要强大得多:
endpoints:
- name: API Health Check
url: "https://api.example.com/health"
interval: 30s
conditions:
- "[STATUS] == 200" # 状态码校验
- "[RESPONSE_TIME] < 500" # 响应时间 < 500ms
- "[BODY].status == \"healthy\"" # JSONPath 响应体校验
- "[BODY].data.length() > 0" # 数组长度校验
- "[BODY].version == regex(^v\\d+\\.\\d+)" # 正则匹配
- "[CERTIFICATE_EXPIRY] > 720h" # SSL 证书有效期 > 30天
这意味着你可以用它做简单的 UAT(用户验收测试):
endpoints:
- name: 完整业务流程验证
url: "https://api.example.com/orders/123"
headers:
Authorization: "Bearer {{ .Env.API_TOKEN }}"
conditions:
- "[STATUS] == 200"
- "[BODY].order.status == \"paid\""
- "[BODY].order.amount > 0"
- "[RESPONSE_TIME] < 1000"
条件语法支持的函数列表:
| 函数 | 用途 | 示例 |
|---|---|---|
==, !=, >, <, >=, <= | 比较运算 | [STATUS] == 200 |
contains() | 字符串包含 | [BODY] contains("success") |
regex() | 正则匹配 | [BODY].email == regex(^[\\w.]+@[\\w.]+$) |
length() | 数组/字符串长度 | [BODY].items.length() == 5 |
hasPrefix() | 前缀匹配 | [BODY].token hasPrefix("eyJ") |
indexOf() | 字符串查找 | [BODY].error indexOf("timeout") != -1 |
2.2 Suite 端到端监控——业务流程的健康检查
这是 Gatus 最独特也是最有价值的特性之一。
在实际业务中,一个 API 返回 200 并不代表业务正常——可能数据库连接池已满、缓存已失效、第三方支付接口已断开。Suite 允许你串联多个请求,模拟真实用户操作路径:
endpoints:
- name: 用户注册-登录-下单 完整流程
suite:
- name: Step 1 - 用户注册
url: "https://api.example.com/users"
method: POST
body: |
{"username": "test_user_{{$timestamp}}", "password": "Test@12345"}
conditions:
- "[STATUS] == 201"
extract:
user_id: "[BODY].data.id"
- name: Step 2 - 用户登录
url: "https://api.example.com/auth/login"
method: POST
body: |
{"username": "test_user_{{$timestamp}}", "password": "Test@12345"}
conditions:
- "[STATUS] == 200"
- "[BODY].data.token != ''"
extract:
auth_token: "[BODY].data.token"
- name: Step 3 - 创建订单
url: "https://api.example.com/orders"
method: POST
headers:
Authorization: "Bearer {{ .Suite.auth_token }}"
body: |
{"product_id": "prod_001", "quantity": 1}
conditions:
- "[STATUS] == 201"
- "[BODY].data.order_id != ''"
- name: Step 4 - 验证订单
url: "https://api.example.com/orders/{{ .Suite.order_id }}"
headers:
Authorization: "Bearer {{ .Suite.auth_token }}"
conditions:
- "[STATUS] == 200"
- "[BODY].data.status == \"pending\""
这种端到端检查的价值在于:它检查的不是单个服务的健康,而是整个业务链路的健康。 任何一个环节出问题,你都能第一时间知道。
2.3 外部端点推送——内网服务的健康上报
在 Kubernetes 集群或私有云中,很多服务没有公网入口。Gatus 的 External Agent 模式允许内网服务主动上报健康状态:
服务端配置:
external-endpoints:
- name: internal-microservice-a
group: internal-services
alert-type: expect-heartbeat
heartbeat-interval: 60s
alerts:
- type: slack
Agent 端(在 K8s Pod 中运行):
apiVersion: apps/v1
kind: Deployment
metadata:
name: gatus-agent
spec:
template:
spec:
containers:
- name: gatus-agent
image: twinproduction/gatus:latest
args:
- --external-endpoint-name=internal-microservice-a
- --external-endpoint-heartbeat-interval=60s
- --gateway-url=https://gatus.example.com
env:
- name: GATUS_API_KEY
valueFrom:
secretKeyRef:
name: gatus-secrets
key: api-key
服务端如果超过 heartbeat-interval 没收到心跳,自动触发告警。这种方式零侵入、无需暴露内网端口。
2.4 SSH 隧道——透过跳板机监控内网
对于有跳板机架构的场景,Gatus 支持通过 SSH 隧道探测内网服务:
endpoints:
- name: Internal Database (via SSH Tunnel)
url: "tcp://10.0.1.50:5432"
interval: 60s
ssh:
address: "bastion.example.com:22"
user: "monitor"
private-key: |
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
conditions:
- "[CONNECTED] == true"
2.5 40+ 告警通道
Gatus 支持的告警通道覆盖了几乎所有主流平台:
即时通讯类:Slack、Discord、Telegram、企业微信/飞书/钉钉、Microsoft Teams
传统渠道:Email (SMTP)、SMS(通过 Twilio 等网关)
专业运维:PagerDuty、OpsGenie、Grafana OnCall
云厂商:AWS SNS、Google Pub/Sub
通用:Custom Webhook(可对接任何平台)
alerting:
slack:
webhook-url: "https://hooks.slack.com/services/xxx"
default-alert:
description: "Service {{ .Endpoint.Name }} is {{ .Condition.Result }}"
send-on-resolved: true
failure-threshold: 3
success-threshold: 2
email:
from: "gatus@example.com"
to: "oncall@example.com"
smtp:
host: "smtp.example.com"
port: 587
username: "gatus"
password: "{{ .Env.SMTP_PASSWORD }}"
custom:
- webhook-url: "https://your-custom-endpoint/alert"
method: POST
headers:
Authorization: "Bearer {{ .Env.CUSTOM_ALERT_TOKEN }}"
body: |
{
"endpoint": "{{ .Endpoint.Name }}",
"status": "{{ .Condition.Result }}",
"url": "{{ .Endpoint.URL }}",
"time": "{{ now.Format \"2006-01-02 15:04:05\" }}"
}
智能告警策略:
failure-threshold: 3:连续失败 3 次才告警,避免网络抖动导致的误报success-threshold: 2:连续恢复 2 次才发恢复通知,避免反复抖动send-on-resolved: true:恢复时自动发通知cooldown: 5m:告警冷却时间,避免告警风暴
三、配置实战:从零搭建生产级 Gatus
3.1 Docker 快速启动
docker run -d \
--name gatus \
--restart unless-stopped \
-p 8080:8080 \
-v /etc/gatus/config.yaml:/config.yaml \
-v /etc/gatus/data:/data \
twinproduction/gatus:latest
3.2 Docker Compose 生产级配置
# docker-compose.yml
version: '3.8'
services:
gatus:
image: twinproduction/gatus:latest
container_name: gatus
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./config.yaml:/config.yaml
- gatus-data:/data
environment:
- GATUS_DB_TYPE=postgres
- GATUS_DB_HOST=postgres
- GATUS_DB_PORT=5432
- GATUS_DB_USER=gatus
- GATUS_DB_PASSWORD=${DB_PASSWORD}
- GATUS_DB_NAME=gatus
depends_on:
postgres:
condition: service_healthy
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
postgres:
image: postgres:16-alpine
container_name: gatus-postgres
restart: unless-stopped
environment:
POSTGRES_DB: gatus
POSTGRES_USER: gatus
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gatus"]
interval: 5s
timeout: 3s
retries: 5
volumes:
gatus-data:
postgres-data:
3.3 完整配置文件详解
# config.yaml - Gatus 完整生产级配置
storage:
type: postgres
path: "postgres://gatus:${DB_PASSWORD}@postgres:5432/gatus?sslmode=disable"
caching: true
web:
port: 8080
address: 0.0.0.0
external-url: "https://status.example.com"
endpoints:
- name: 前端首页
group: Frontend
url: "https://www.example.com"
interval: 30s
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 3000"
- name: API 健康检查
group: Backend API
url: "https://api.example.com/health"
interval: 15s
conditions:
- "[STATUS] == 200"
- "[BODY].status == \"healthy\""
- "[BODY].database == \"connected\""
- "[BODY].redis == \"connected\""
- "[RESPONSE_TIME] < 200"
- name: 用户登录接口
group: Backend API
url: "https://api.example.com/v1/auth/check"
method: POST
headers:
Content-Type: "application/json"
body: '{"token": "health-check-token"}'
interval: 30s
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 500"
- name: 支付接口连通性
group: Backend API
url: "https://api.example.com/v1/payment/status"
interval: 60s
conditions:
- "[STATUS] == 200"
alerts:
- type: pagerduty
failure-threshold: 5
success-threshold: 2
send-on-resolved: true
- name: PostgreSQL 连通性
group: Database
url: "tcp://postgres.internal:5432"
interval: 30s
conditions:
- "[CONNECTED] == true"
- name: Redis 连通性
group: Database
url: "tcp://redis.internal:6379"
interval: 15s
conditions:
- "[CONNECTED] == true"
- name: DNS 解析验证
group: Infrastructure
url: "dns://8.8.8.8/example.com"
interval: 60s
conditions:
- "[RESOLVED] == true"
- "[DNS_RCODE] == NOERROR"
- name: 服务器存活检查
group: Infrastructure
url: "icmp://10.0.1.100"
interval: 30s
conditions:
- "[STATUS] == 0"
- name: SSL 证书有效期
group: Security
url: "https://api.example.com"
interval: 6h
conditions:
- "[CERTIFICATE_EXPIRY] > 720h"
alerts:
- type: email
failure-threshold: 1
- name: 下单完整流程
group: E2E Tests
suite:
- name: 创建测试用户
url: "https://api.example.com/v1/users/test-e2e"
method: PUT
conditions:
- "[STATUS] == 200"
- name: 获取商品列表
url: "https://api.example.com/v1/products"
conditions:
- "[STATUS] == 200"
- "[BODY].data.length() > 0"
- name: 创建订单
url: "https://api.example.com/v1/orders"
method: POST
body: '{"product_id": "test-product", "quantity": 1}'
conditions:
- "[STATUS] == 201"
- name: 查询订单状态
url: "https://api.example.com/v1/orders/latest"
conditions:
- "[STATUS] == 200"
- "[BODY].data.status == \"created\""
interval: 5m
alerts:
- type: slack
failure-threshold: 2
send-on-resolved: true
- name: Stripe API 可用性
group: Third-Party
url: "https://api.stripe.com/v1/balance"
headers:
Authorization: "Bearer {{ .Env.STRIPE_KEY }}"
interval: 60s
conditions:
- "[STATUS] == 200"
alerting:
slack:
webhook-url: "https://hooks.slack.com/services/xxx"
default-alert:
send-on-resolved: true
failure-threshold: 3
success-threshold: 2
cooldown: 5m
email:
from: "gatus@example.com"
to: "oncall@example.com,dev@example.com"
smtp:
host: "smtp.example.com"
port: 587
username: "gatus@example.com"
password: "{{ .Env.SMTP_PASSWORD }}"
custom:
- webhook-url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx"
method: POST
body: |
{
"msgtype": "markdown",
"markdown": {
"content": "## 🔴 服务告警\n> **服务**: {{ .Endpoint.Name }}\n> **状态**: 异常\n> **URL**: {{ .Endpoint.URL }}\n> **时间**: {{ now.Format \"2006-01-02 15:04:05\" }}"
}
}
ui:
title: "Example Inc. 服务状态"
description: "实时监控所有服务的可用性状态"
header: "系统状态监控"
theme:
primary-color: "#3498db"
metrics:
enabled: true
address: ":9090"
3.4 配置文件拆分——多团队协作
config/
├── config.yaml # 主配置(存储、UI、告警)
├── endpoints/
│ ├── frontend.yaml # 前端团队维护
│ ├── backend.yaml # 后端团队维护
│ ├── database.yaml # DBA 团队维护
│ ├── infra.yaml # 基础设施团队维护
│ └── e2e.yaml # QA 团队维护
└── alerting/
├── slack.yaml
├── email.yaml
└── pagerduty.yaml
四、告警工程化:从基础通知到智能告警策略
4.1 告警分级
不要所有端点都用同一个告警策略。根据服务重要性和恢复能力,分级配置:
endpoints:
# P0 - 核心支付服务,即时告警
- name: 支付网关
url: "https://payment.example.com/health"
interval: 10s
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 500"
alerts:
- type: pagerduty
failure-threshold: 1
success-threshold: 1
send-on-resolved: true
- type: slack
failure-threshold: 1
# P1 - 核心 API,3 次失败告警
- name: 用户认证服务
url: "https://auth.example.com/health"
interval: 15s
alerts:
- type: pagerduty
failure-threshold: 3
- type: slack
# P2 - 辅助服务,5 次失败才告警
- name: 日志收集服务
url: "https://logging.example.com/health"
interval: 60s
alerts:
- type: slack
failure-threshold: 5
# P3 - 仅邮件通知
- name: CDN 缓存状态
url: "https://cdn.example.com/health"
interval: 5m
alerts:
- type: email
failure-threshold: 3
4.2 企业微信告警最佳实践
alerting:
custom:
- name: wecom-alert
webhook-url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
method: POST
body: |
{
"msgtype": "markdown",
"markdown": {
"content": "## 🔴 服务故障告警\n> **服务名称**:{{ .Endpoint.Name }}\n> **服务分组**:{{ .Endpoint.Group }}\n> **检查 URL**:{{ .Endpoint.URL }}\n> **告警条件**:{{ .Condition.DisplayName }}\n> **告警时间**:{{ now.Format \"2006-01-02 15:04:05\" }}\n> **连续失败**:{{ .Endpoint.Count }} 次\n\n> 请值班同学及时处理!"
}
}
- name: wecom-recovery
webhook-url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
method: POST
body: |
{
"msgtype": "markdown",
"markdown": {
"content": "## ✅ 服务恢复通知\n> **服务名称**:{{ .Endpoint.Name }}\n> **恢复时间**:{{ now.Format \"2006-01-02 15:04:05\" }}\n\n> 服务已恢复正常运行。"
}
}
4.3 维护窗口配置
endpoints:
- name: 备份服务(夜间维护时段不告警)
url: "https://backup.example.com/health"
interval: 60s
schedule:
starts-at: "08:00"
ends-at: "22:00"
timezone: "Asia/Shanghai"
conditions:
- "[STATUS] == 200"
维护计划配置:
maintenance:
enabled: true
start-time: "2026-06-10T02:00:00Z"
duration: 4h
title: "数据库升级维护"
message: "正在进行 PostgreSQL 主从切换,预计 4 小时"
五、Kubernetes 部署:Helm Chart 与最佳实践
5.1 Helm 部署
helm repo add gatus https://twinproduction.github.io/gatus-charts
helm repo update
helm install gatus gatus/gatus \
--set config.storage.type=postgres \
--set config.storage.path="postgres://gatus:password@postgres:5432/gatus" \
--set config.web.externalURL="https://status.example.com" \
--namespace monitoring \
--create-namespace
5.2 Values 配置文件
# values.yaml
replicaCount: 2
config:
storage:
type: postgres
path: "postgres://gatus:{{ .Values.dbPassword }}@gatus-postgres:5432/gatus"
caching: true
web:
port: 8080
externalURL: "https://status.example.com"
metrics:
enabled: true
address: ":9090"
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 5
targetCPUUtilizationPercentage: 70
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: status.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: gatus-tls
hosts:
- status.example.com
serviceMonitor:
enabled: true
5.3 监控 K8s 内部服务
endpoints:
- name: user-service
group: K8S Internal
url: "http://user-service.default.svc.cluster.local:8080/health"
interval: 15s
conditions:
- "[STATUS] == 200"
5.4 Agent Sidecar 模式
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
spec:
template:
spec:
containers:
- name: payment-service
image: payment-service:latest
ports:
- containerPort: 8080
- name: gatus-agent
image: twinproduction/gatus:latest
args:
- --agent
- --gateway-url=https://gatus.external.example.com
- --external-endpoint-name=payment-service-pod
- --external-endpoint-heartbeat-interval=30s
- --external-endpoint-group=k8s-pods
env:
- name: GATUS_API_KEY
valueFrom:
secretKeyRef:
name: gatus-agent-secret
key: api-key
resources:
limits:
memory: 32Mi
cpu: 50m
六、Prometheus 生态集成
Gatus 暴露 Prometheus 格式的指标,可以无缝对接现有监控体系:
scrape_configs:
- job_name: gatus
kubernetes_sd_configs:
- role: service
namespaces:
names: ['monitoring']
relabel_configs:
- source_labels: [__meta_kubernetes_service_name]
regex: gatus
action: keep
Gatus 暴露的指标:
| 指标名 | 说明 |
|---|---|
gatus_endpoint_up | 端点是否可用(0/1) |
gatus_endpoint_response_time_seconds | 响应时间 |
gatus_endpoint_status_code | HTTP 状态码 |
gatus_endpoint_cert_expiry_timestamp_seconds | SSL 证书过期时间戳 |
Grafana PromQL 查询示例:
# 所有端点的可用性
avg by (endpoint, group) (gatus_endpoint_up)
# 端点响应时间 P99
histogram_quantile(0.99, sum(rate(gatus_endpoint_response_time_seconds_bucket[5m])) by (le, endpoint))
# SSL 证书剩余天数
(gatus_endpoint_cert_expiry_timestamp_seconds - time()) / 86400
SVG 状态徽章可嵌入 GitHub README:

七、性能优化与高可用
7.0 内存与资源基准测试
在深入优化之前,先看一组 Gatus 的资源消耗基准数据(实测环境:单实例、100 个端点、PostgreSQL 后端):
| 指标 | 值 |
|---|---|
| 常驻内存 | ~45MB |
| CPU 空闲时 | < 1% |
| CPU 检查高峰时 | ~8% |
| 单次检查耗时(HTTP) | 50-200ms |
| 状态页加载时间 | < 100ms(缓存命中) |
对比 Uptime Kuma(同等规模):内存 200-300MB,CPU 检查高峰 15-20%。Go 的优势在资源受限环境(如 ARM 边缘设备、小型 VPS)中尤其明显。
7.1 合理设置检查间隔
# 核心支付接口 - 高频检查
- interval: 10s
# 普通 API - 中频检查
- interval: 30s
# 辅助服务 - 低频检查
- interval: 60s
# SSL 证书 - 极低频检查
- interval: 6h
# E2E 业务流程 - 低频但深度检查
- interval: 5m
7.2 PostgreSQL 写穿缓存
storage:
type: postgres
path: "postgres://..."
caching: true
7.3 分组错开检查
endpoints:
- name: group-a-service-1
group: Group A
interval: 30s
offset: 0s
- name: group-b-service-1
group: Group B
interval: 30s
offset: 15s
7.4 高可用部署
# 双副本 + PostgreSQL 共享存储
# Nginx 负载均衡配置
upstream gatus {
server gatus-1:8080;
server gatus-2:8080;
}
server {
listen 443 ssl;
server_name status.example.com;
ssl_certificate /etc/nginx/ssl/status.crt;
ssl_certificate_key /etc/nginx/ssl/status.key;
location / {
proxy_pass http://gatus;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
7.5 断网防误报
Gatus 内置断网检测:如果 Gatus 自身无法访问互联网,会自动暂停告警,避免误报。
7.6 配置热加载
Gatus 支持配置热加载,修改 YAML 文件后无需重启服务。
八、与同类工具对比
| 特性 | Gatus | Uptime Kuma | Healthchecks.io |
|---|---|---|---|
| 开发语言 | Go | Node.js | Python |
| 协议支持 | HTTP/ICMP/TCP/DNS/gRPC/WS/SSH | HTTP/TCP/DNS/Ping/Docker | HTTP/TCP/DNS |
| 条件语法 | JSONPath/正则/函数/数学运算 | 简单状态码检查 | 简单状态码检查 |
| Suite 工作流 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
| SSH 隧道 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
| Agent 推送 | ✅ 支持 | ✅ 支持 | ❌ 不支持 |
| 资源占用 | 极低(几十 MB) | 中等(200+ MB) | SaaS |
| Prometheus 集成 | ✅ 原生 | ⚠️ 社区方案 | ❌ |
| 多存储后端 | Memory/SQLite/PostgreSQL | SQLite | SaaS |
| 部署方式 | Docker/K8s/二进制/Helm/Terraform | Docker | SaaS |
| 开源协议 | Apache 2.0 | MIT | 开源(自托管) |
选择建议:
- 选 Gatus:需要深度定制检查条件、监控复杂业务流程、K8s 原生部署、低资源消耗
- 选 Uptime Kuma:需要中文友好界面、简单的 Ping 监控、通知模板管理
- 选 Healthchecks.io:Cron Job 监控场景、不想自托管
九、进阶技巧与踩坑记录
9.1 常见坑与解决方案
坑 1:JSONPath 嵌套取值
# Gatus 使用简单点表示法
# 响应体 {"data":{"user":{"name":"admin"}}}
conditions:
- "[BODY].data.user.name == admin"
坑 2:检查超时设置
endpoints:
- name: 慢查询接口
url: "https://api.example.com/slow-query"
interval: 30s
timeout: 30000 # 30 秒超时(毫秒)
conditions:
- "[STATUS] == 200"
坑 3:SSL 证书检查频率
- name: API SSL 证书
url: "https://api.example.com"
interval: 6h # 每 6 小时检查一次
conditions:
- "[CERTIFICATE_EXPIRY] > 720h"
9.2 条件语法的进阶用法
除了基本的比较和匹配,Gatus 的条件语法还支持一些高级技巧:
响应体长度校验:
conditions:
- "len([BODY]) > 100" # 确保响应体不为空
多条件组合与逻辑运算:
conditions:
- "[STATUS] == 200 || [STATUS] == 201" # 接受 200 或 201
- "[BODY].error == null && [BODY].data != null" # 无错误且有数据
环境变量注入:
endpoints:
- name: 带认证的 API 检查
url: "https://api.example.com/health"
headers:
X-Monitoring-Key: "{{ .Env.MONITORING_KEY }}"
interval: 30s
conditions:
- "[STATUS] == 200"
这样敏感凭证不需要硬编码在配置文件中,可以通过环境变量注入,更安全。
9.3 监控第三方 SaaS 服务
现代应用严重依赖第三方 SaaS(Stripe、SendGrid、Twilio 等),这些服务的可用性直接决定你的业务可用性:
endpoints:
# Stripe 支付网关
- name: Stripe API
group: SaaS Dependencies
url: "https://api.stripe.com/v1/balance"
headers:
Authorization: "Bearer {{ .Env.STRIPE_API_KEY }}"
interval: 60s
conditions:
- "[STATUS] == 200"
alerts:
- type: pagerduty
failure-threshold: 2
# SendGrid 邮件服务
- name: SendGrid API
group: SaaS Dependencies
url: "https://api.sendgrid.com/v3/mail/send"
method: POST
headers:
Authorization: "Bearer {{ .Env.SENDGRID_API_KEY }}"
body: '{"personalizations":[{"to":[{"email":"test@example.com"}]}],"from":{"email":"noreply@example.com"},"subject":"Gatus Health Check","content":[{"type":"text/plain","value":"health check"}]}'
interval: 5m
conditions:
- "[STATUS] == 202"
# Cloudflare CDN
- name: Cloudflare CDN 边缘节点
group: SaaS Dependencies
url: "https://www.example.com/cdn-test"
interval: 30s
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 1000" # CDN 响应应该很快
- "[BODY] contains(cdn-powered)" # 验证确实是 CDN 返回的
9.4 自定义 Checker(Go 扩展)
package custom
import (
"context"
"github.com/TwiN/gatus/config"
)
func init() {
config.RegisterCustomChecker("mq-depth", func(cfg *config.Endpoint) config.Checker {
return &MQDepthChecker{QueueURL: cfg.URL}
})
}
type MQDepthChecker struct {
QueueURL string
}
func (c *MQDepthChecker) Check(ctx context.Context, ep *config.Endpoint) (*config.Result, error) {
depth, err := checkQueueDepth(c.QueueURL)
if err != nil {
return &config.Result{Success: false, Message: err.Error()}, nil
}
if depth > 10000 {
return &config.Result{Success: false, Message: "队列积压超过 10000"}, nil
}
return &config.Result{Success: true, Message: "队列正常"}, nil
}
9.3 Terraform 部署 Gatus
terraform {
required_providers {
gatus = {
source = "TwiN/gatus"
version = "~> 1.0"
}
}
}
provider "gatus" {
address = "https://gatus.example.com"
}
resource "gatus_endpoint" "api_health" {
name = "API Health"
group = "Production"
url = "https://api.example.com/health"
interval = "30s"
conditions = [
"[STATUS] == 200",
"[BODY].status == healthy"
]
alert = {
type = "slack"
failure_threshold = 3
send_on_resolved = true
}
}
十、总结:Gatus 在监控体系中的位置
Gatus 解决的核心问题是:在流量到达之前发现故障。
最佳实践总结
- 与 Prometheus 互补部署:Gatus 管可用性,Prometheus 管性能指标
- 分级告警策略:核心服务即时告警,辅助服务容忍多次失败
- 善用 Suite 端到端检查:监控业务链路而非单个服务
- 合理设置检查间隔:避免不必要的高频检查浪费资源
- 配置文件拆分:多团队协作,各管各的端点
- PostgreSQL 持久化:生产环境必须用数据库存储历史数据
- 断网防误报:让 Gatus 在自身网络异常时不产生噪音
- 配置维护窗口:计划内维护自动暂停告警
适用场景矩阵
| 场景 | 推荐方案 |
|---|---|
| 个人项目/小团队 | Docker + SQLite,内存占用 < 50MB |
| 中型 SaaS 团队 | Docker Compose + PostgreSQL + 多通道告警 |
| 大型企业/K8s | Helm Chart + PostgreSQL + Agent Sidecar + Prometheus |
| 对外状态页 | Gatus 内置 UI + 自定义域名 + SSL |
| DevOps 工具链 | Terraform Provider + GitOps 配置管理 |
Gatus 证明了:好的监控工具不一定需要庞大的技术栈。一个 Go 编写的单二进制、几十 MB 内存的工具,就能填补传统监控体系中最大的盲区——无流量场景下的故障发现。
如果你还在凌晨三点被客户投诉叫醒,也许该认真考虑一下 Gatus 了。
十一、实战案例:从零搭建电商平台状态监控
让我用一个完整的实战案例串联本文所有知识点。假设你要为一个电商平台搭建状态监控系统,包含前端、API 网关、订单服务、支付服务、用户服务、数据库、Redis 缓存、第三方支付(支付宝/微信支付)。
架构图
用户 → CDN → 前端 SPA → API Gateway → 用户服务
→ 订单服务 → PostgreSQL
→ 支付服务 → 支付宝/微信
→ 商品服务 → Redis 缓存 → PostgreSQL
监控矩阵
| 监控对象 | 协议 | 间隔 | 告警级别 | 告警通道 |
|---|---|---|---|---|
| CDN 前端首页 | HTTP | 30s | P1 | Slack + Email |
| API Gateway 健康检查 | HTTP | 15s | P0 | PagerDuty + Slack |
| 用户服务 /health | HTTP | 15s | P1 | Slack |
| 订单服务 /health | HTTP | 15s | P0 | PagerDuty + Slack |
| 支付服务 /health | HTTP | 10s | P0 | PagerDuty + 电话 |
| PostgreSQL 连通性 | TCP | 30s | P1 | Slack |
| Redis 连通性 | TCP | 15s | P1 | Slack |
| 支付宝网关可用性 | HTTP | 60s | P1 | Slack + 邮件 |
| 微信支付网关可用性 | HTTP | 60s | P1 | Slack + 邮件 |
| SSL 证书有效期 | HTTP | 6h | P2 | 邮件 |
| 下单 E2E 流程 | Suite | 5m | P1 | Slack |
完整配置
# e-commerce-gatus-config.yaml
storage:
type: postgres
path: "postgres://gatus:${DB_PASSWORD}@postgres:5432/gatus"
caching: true
web:
port: 8080
external-url: "https://status.shop.example.com"
ui:
title: "Shop Example 服务状态"
description: "电商平台全链路服务可用性监控"
endpoints:
- name: CDN 前端
group: Frontend
url: "https://www.shop.example.com"
interval: 30s
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 3000"
alerts:
- type: slack
failure-threshold: 3
- type: email
failure-threshold: 3
- name: API Gateway
group: Core Services
url: "https://api.shop.example.com/health"
interval: 15s
conditions:
- "[STATUS] == 200"
- "[BODY].status == \"healthy\""
- "[BODY].services.up == [BODY].services.total"
- "[RESPONSE_TIME] < 200"
alerts:
- type: pagerduty
failure-threshold: 2
send-on-resolved: true
- type: slack
failure-threshold: 2
- name: 支付服务
group: Core Services
url: "https://payment.shop.example.com/health"
interval: 10s
conditions:
- "[STATUS] == 200"
- "[BODY].alipay == \"connected\""
- "[BODY].wechatpay == \"connected\""
alerts:
- type: pagerduty
failure-threshold: 1
send-on-resolved: true
- type: slack
failure-threshold: 1
- name: PostgreSQL
group: Database
url: "tcp://postgres.internal:5432"
interval: 30s
conditions:
- "[CONNECTED] == true"
- name: Redis
group: Database
url: "tcp://redis.internal:6379"
interval: 15s
conditions:
- "[CONNECTED] == true"
- name: 下单全链路验证
group: E2E
suite:
- name: 登录
url: "https://api.shop.example.com/v1/auth/login"
method: POST
body: '{"username":"monitor","password":"{{ .Env.MONITOR_PW }}"}'
conditions:
- "[STATUS] == 200"
extract:
token: "[BODY].data.token"
- name: 获取商品
url: "https://api.shop.example.com/v1/products?page=1&size=1"
conditions:
- "[STATUS] == 200"
- "[BODY].data.items.length() > 0"
extract:
product_id: "[BODY].data.items[0].id"
- name: 创建订单
url: "https://api.shop.example.com/v1/orders"
method: POST
headers:
Authorization: "Bearer {{ .Suite.token }}"
body: '{"product_id":"{{ .Suite.product_id }}","quantity":1}'
conditions:
- "[STATUS] == 201"
- name: 查询订单
url: "https://api.shop.example.com/v1/orders?status=created"
headers:
Authorization: "Bearer {{ .Suite.token }}"
conditions:
- "[STATUS] == 200"
- "[BODY].data.items.length() > 0"
interval: 5m
alerts:
- type: slack
failure-threshold: 2
send-on-resolved: true
alerting:
pagerduty:
routing-key: "{{ .Env.PAGERDUTY_KEY }}"
default-alert:
failure-threshold: 2
send-on-resolved: true
slack:
webhook-url: "{{ .Env.SLACK_WEBHOOK }}"
default-alert:
failure-threshold: 3
success-threshold: 2
cooldown: 5m
send-on-resolved: true
email:
from: "gatus@shop.example.com"
to: "dev@shop.example.com"
smtp:
host: "smtp.shop.example.com"
port: 587
username: "gatus@shop.example.com"
password: "{{ .Env.SMTP_PASSWORD }}"
metrics:
enabled: true
address: ":9090"
这个配置覆盖了电商平台的全部关键链路。从 CDN 前端到支付网关,从数据库连通性到完整的下单 E2E 流程,任何一个环节出问题,你都能在第一时间收到告警。
而且状态页对外公开后,用户可以自行查看服务状态,减少了对客服的压力。这才是监控应该有的样子——让用户信任你的服务,让团队快速发现和修复问题。
参考资源
- GitHub 仓库:https://github.com/TwiN/gatus
- 官方文档:https://gatus.io
- Docker Hub:twinproduction/gatus
- Helm Chart:https://github.com/TwiN/gatus-charts