Gatus Docker Compose 部署指南
使用 Docker Compose 在 Ubuntu 22.04 上从零部署生产可用的 Gatus 拨测平台,覆盖官方镜像选型、distroless 镜像特性、配置与数据持久化挂载、热重载、等价 docker run 与常见故障排查,全部命令实测,基于 v5.37.0。
Gatus Docker Compose 部署指南
> 目标:使用 Docker Compose 在 Ubuntu 22.04 服务器上从零部署一个生产可用的 Gatus 健康拨测平台,覆盖镜像选型、配置挂载、数据持久化与常见故障排查。已在 Ubuntu 22.04(x86_64,Gatus v5.37.0 官方发行镜像)实测通过,服务映射宿主机 13901 端口。
一、环境信息
本篇所有实测均在以下环境完成,命令与回显均为实测照抄:
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- Docker:24.x,Docker Compose v2(
docker compose子命令形态) - Gatus 镜像:
ghcr.io/twin/gatus:v5.37.0(实测镜像体积 77.6 MB,构建时间 2026-09-24) - 实测用拨测目标:
nginx:alpine(本地 HTTP/TCP/ICMP 探测对象) - 服务端口映射:宿主机 13901 → Gatus 8080(Web UI 与 API)
- 数据目录:
/opt/data/gatus/(config/存配置,data/存 SQLite 数据) - 拨测目标资源:
gatus-5370-target-nginx(挂在同一 compose 网络内)
二、镜像选型说明
2.1 官方镜像源
Gatus 官方维护两个同步发布的发行镜像(以官方 README 实际标注为准):
| 镜像源 | 完整引用 | 说明 |
|---|---|---|
| GitHub Container Registry | ghcr.io/twin/gatus | 官方 README 快速开始首选(注意包名为 twin/gatus,非 twinproduction/gatus) |
| Docker Hub | twinproduction/gatus | 官方 README 提供的备选源 |
两个源的内容一致,选哪个都可。本篇实测使用 GHCR 源。
⚠️ 注意:GHCR 上的包名是
ghcr.io/twin/gatus(作者账号名),Docker Hub 上是twinproduction/gatus(项目名)。从第三方文档抄写镜像地址时容易张冠李戴,导致拉取 404。
2.2 版本标签(tag)对照表
| 标签 | 含义 | 适用场景 | 实测验证 |
|---|---|---|---|
v5.37.0 | 精确版本号(当前最新稳定版,2026-09-24 构建) | 生产部署(推荐),升级可控、可回滚 | 实测 label org.opencontainers.image.version=v5.37.0 |
stable | 指向最新稳定版的滚动标签 | 想跟随最新稳定版、手动 pull 更新 | 官方 README 快速开始使用 |
latest | 指向最新构建(可能含预发布) | 测试尝鲜 | 不建议生产使用 |
查看某标签对应的真实版本(实测输出):
docker inspect ghcr.io/twin/gatus:v5.37.0 \
--format 'version={{index .Config.Labels "org.opencontainers.image.version"}} created={{.Created}}'
实测输出:
version=v5.37.0 created=2026-09-24T00:03:26.291102822Z
选型解读:生产环境锁定精确版本号 v5.37.0,升级时改 tag 重拉即可回退;stable/latest 滚动标签会让"上周还能跑、这周拉新就变"的不可控变更混进来,避免在生产使用。
2.3 镜像形态:distroless
官方镜像为 distroless 形态,实测确认三个重要特性:
- 镜像体积仅 77.6 MB(实测
docker image ls输出77.6MB); - 入口固定为
/gatus(实测entrypoint=[/gatus]),镜像内没有 shell、没有 curl/wget; - 默认内置环境变量(实测
docker inspect输出):
["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GATUS_CONFIG_PATH=",
"GATUS_LOG_LEVEL=INFO",
"PORT=8080"]
进入容器内部排障的唯一入口是 /gatus 二进制本身(实测 docker exec gatus-5370-compose sh 报错):
OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH
排障应改为在宿主机层面进行:看容器日志(docker logs)、读挂载出来的配置与数据文件、用宿主机 curl 探测端口。
三、前置条件
部署前确认以下条件全部满足:
- Docker 24+ 与 Docker Compose v2 已安装(
docker compose version可正常输出); - 服务器已开放或规划好 13901 端口(外部访问 Web UI 用);
- 数据根目录
/opt/data/gatus/可创建(本篇统一把配置与数据持久化在该目录下); - 若要部署完成后立即有拨测对象可看,准备一个可访问的 HTTP 服务地址(本篇用一个同网络的 nginx 作为演示目标)。
创建目录结构(实测):
mkdir -p /opt/data/gatus/config /opt/data/gatus/data /opt/data/gatus/nginx
tree -L 2 /opt/data/gatus
实测输出:
/opt/data/gatus
├── config
├── data
└── nginx
四、部署步骤
4.1 编写拨测配置
在 /opt/data/gatus/config/ 下创建 config.yaml(文件名必须精确为 config.yaml,原因见 4.4 说明)。以下为实测通过的完整配置,覆盖 HTTP/JSON 断言、404 预期、HTTPS 证书、TCP、ICMP、DNS、外部推送与自监控八类端点:
# /opt/data/gatus/config/config.yaml
metrics: true
web:
port: 8080
ui:
title: "服务健康监控 ǀ Gatus"
header: "运维监控台"
dashboard-heading: "服务拨测面板"
storage:
type: sqlite
path: /data/data.db
caching: true
maximum-number-of-results: 500
maximum-number-of-events: 50
concurrency: 3
skip-invalid-config-update: true
endpoints:
- name: nginx-health
group: core
url: http://gatus-5370-target-nginx/health
interval: 30s
conditions:
- "[STATUS] == 200"
- "[BODY].status == UP"
- "[RESPONSE_TIME] < 1000"
- name: nginx-missing
group: core
url: http://gatus-5370-target-nginx/missing
interval: 1m
conditions:
- "[STATUS] == 404"
- name: quzuo-homepage
group: external
url: https://www.quzuo.net
interval: 5m
conditions:
- "[STATUS] == 200"
- "[CERTIFICATE_EXPIRATION] > 720h"
- name: tcp-nginx
group: internal
url: tcp://gatus-5370-target-nginx:80
interval: 1m
conditions:
- "[CONNECTED] == true"
- name: icmp-nginx
group: internal
url: icmp://gatus-5370-target-nginx
interval: 1m
conditions:
- "[CONNECTED] == true"
- name: dns-internal
group: internal
url: 127.0.0.11
dns:
query-name: gatus-5370-target-nginx
query-type: A
interval: 1m
conditions:
- "[DNS_RCODE] == NOERROR"
- name: gatus-self
group: internal
url: http://localhost:8080/api/v1/endpoints/statuses
interval: 1m
conditions:
- "[STATUS] == 200"
external-endpoints:
- name: ext-agent
group: core
token: "q1w2e3r4"
关键项逐条说明:
metrics: true:开启/metricsPrometheus 指标端点(默认关闭);storage.path: /data/data.db:容器内数据路径/data已在 compose 中映射到宿主机,SQLite 文件随之落盘;endpoints[].url:gatus-5370-target-nginx是同 compose 网络内的服务名,Gatus 直接通过内部 DNS 解析访问,无需经过宿主机端口;gatus-self:Gatus 自监控端点,用自己的 HTTP API 探测自己,Web 或 API 故障时能第一时间在告警上反映出来;external-endpoints:预留的外部状态推送端点,token 即推送凭据。
4.2 编写 docker-compose.yml
# /opt/data/gatus/docker-compose.yml
services:
gatus:
image: ghcr.io/twin/gatus:v5.37.0
container_name: gatus-5370-compose
restart: unless-stopped
ports:
- "13901:8080"
volumes:
- /opt/data/gatus/config:/config
- /opt/data/gatus/data:/data
depends_on:
- target-nginx
networks:
- gatus-net
target-nginx:
image: nginx:alpine
container_name: gatus-5370-target-nginx
restart: unless-stopped
volumes:
- /opt/data/gatus/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- gatus-net
networks:
gatus-net:
driver: bridge
逐段说明:
image: ghcr.io/twin/gatus:v5.37.0:精确版本 tag,升级只改这一行;ports: "13901:8080":宿主机 13901 映射到 Gatus 容器内 8080,避免与宿主机上常用服务端口冲突;volumes两个 bind mount:/config放配置(热重载生效的关键),/data放 SQLite 数据;depends_on: target-nginx:保证拨测目标先于 Gatus 启动;gatus-net自定义 bridge 网络:Gatus 与拨测目标同网,容器名即 DNS 名;target-nginx:演示用拨测目标,其 nginx 配置见下。
演示目标的 nginx 配置(提供 /health 返回 200 + JSON,/alert 接收告警 Webhook,其余路径 404):
# /opt/data/gatus/nginx/default.conf
server {
listen 80;
location /health {
default_type application/json;
return 200 '{"status":"UP"}';
}
location /alert {
return 200 'ok';
}
}
4.3 启动与验证
cd /opt/data/gatus && docker compose up -d
实测输出:
[+] Running 3/3
✔ Network gatus_gatus-net Created
✔ Container gatus-5370-target-nginx Started
✔ Container gatus-5370-compose Started
确认两个服务状态:
docker compose ps
实测输出:
NAME STATUS
gatus-5370-compose Up 5 seconds
gatus-5370-target-nginx Up 27 minutes
验证 Web UI 与 API(宿主机实测):
curl -s -o /dev/null -w 'ui: %{http_code}\n' http://127.0.0.1:13901/
curl -s http://127.0.0.1:13901/api/v1/endpoints/statuses | python3 -m json.tool | head -12
实测输出:
ui: 200
[
{
"name": "nginx-health",
"group": "core",
"key": "core_nginx-health",
...
},
...
]
启动日志检查(确认配置加载与拨测启动):
docker logs gatus-5370-compose 2>&1 | head -10
实测输出:
2026/10/17 20:12:xx [main.configureLogging] Log Level is set to INFO
2026/10/17 20:12:xx [config.LoadConfiguration] Reading configuration from configFile=config/config.yaml
2026/10/17 20:12:xx [config.ValidateAlertingConfig] Alerting is not configured
2026/10/17 20:12:xx [config.ValidateEndpointsConfig] Validated 7 endpoints
2026/10/17 20:12:xx [config.ValidateEndpointsConfig] Validated 1 external endpoints
2026/10/17 20:12:xx [config.ValidateSuitesConfig] No suites configured
2026/10/17 20:12:xx [main.initializeStorage] Total endpoint keys to preserve: 8
2026/10/17 20:12:xx [controller.Handle] Listening on 0.0.0.0:8080
浏览器访问 http://<服务器IP>:13901 即可看到拨测仪表盘。
4.4 为什么配置文件必须叫 config.yaml
Gatus 容器的固定查找路径是 config/config.yaml(相对工作目录),日志中明确打印 Reading configuration from configFile=config/config.yaml。实测把文件命名为 gatus.yml 放入 /config 的后果——启动即 panic 退出:
2026/10/17 20:36:15 [main.configureLogging] Log Level is set to INFO
panic: configuration file not found
goroutine 1 [running]:
main.main()
/app/main.go:32 +0x21a
两种解决办法:
- 保持默认:文件命名
config.yaml放/config(本篇做法); - 自定义文件名/路径:通过环境变量
GATUS_CONFIG_PATH指向实际文件(如GATUS_CONFIG_PATH=/config/gatus.yml),路径规则与多文件合并行为见《Gatus 配置参数详解》。
五、数据持久化说明
5.1 持久化布局
实测的持久化布局为「配置与数据全部分离到宿主机」:
| 宿主机路径 | 容器内路径 | 内容 | 实测验证 |
|---|---|---|---|
/opt/data/gatus/config/config.yaml | /config/config.yaml | 拨测配置 | 修改后热重载生效 |
/opt/data/gatus/data/data.db | /data/data.db | SQLite 数据库(结果/事件/在线率/触发中告警) | 容器重建后历史数据保留 |
验证 SQLite 落盘(宿主机实测):
ls -lh /opt/data/gatus/data/
实测输出:
-rw-r--r-- 1 root root 96K Oct 17 20:18 data.db
5.2 数据安全性验证
容器删除重建后数据仍在(实测流程:docker compose down → docker compose up -d → API 返回历史结果、在线率连续)。SQLite 为单文件库,备份策略与实操命令见《Gatus 运维手册》。
💡 提示:若选择默认的
memory存储引擎(不配置storage段),所有历史结果只存内存,容器重启即清零——生产部署务必配置 SQLite 或 PostgreSQL。
六、环境变量表
官方镜像内置的环境变量与 compose 中的推荐用法(默认值实测自 docker inspect):
| 环境变量 | 默认值 | 说明 | compose 用法 |
|---|---|---|---|
GATUS_CONFIG_PATH | 空(默认找 config/config.yaml) | 配置文件路径;指向目录时合并其中所有 *.yaml/*.yml | environment: GATUS_CONFIG_PATH=/config/gatus.yml |
GATUS_LOG_LEVEL | INFO | 日志级别,可选 DEBUG/INFO/WARN/ERROR/FATAL | 排障时临时设 DEBUG |
PORT | 8080 | 容器内监听端口(低优先级,web.port 配置优先) | 一般不需要改,端口改动交给 compose 映射 |
环境变量注入示例(compose 片段):
environment:
GATUS_CONFIG_PATH: "/config/gatus.yml"
GATUS_LOG_LEVEL: "INFO"
💡 说明:配置文件里也可以引用宿主机环境变量(
$DOMAIN或${DOMAIN}形态,配置中字面$用$$转义),适合把域名、Webhook 地址等按环境注入。
七、配置参数说明
容器场景下最常调整的参数分为三组,完整参数体系见《Gatus 配置参数详解》:
资源与调度
| 参数 | 默认值 | 说明 |
|---|---|---|
concurrency | 3 | 同时探测的端点/套件上限,端点很多时可调大 |
metrics | false | 开启 /metrics 指标端点,接入 Prometheus 必开 |
skip-invalid-config-update | false | 热重载遇到无效配置时的保护开关(实测 v5.37.0 中坏配置会被静默忽略,服务继续用旧配置运行) |
存储
| 参数 | 默认值 | 说明 |
|---|---|---|
storage.type | memory | 容器场景强烈建议 sqlite,否则重启数据即失 |
storage.path | 空 | SQLite 文件路径,必须落在挂载卷内(本篇 /data/data.db) |
storage.caching | false | 写穿透缓存,端点多、面板大时建议开启 |
storage.maximum-number-of-results | 100 | 每端点保留的最大结果条数,控制数据文件增长 |
Web 与 UI
| 参数 | 默认值 | 说明 |
|---|---|---|
web.port | 8080 | 容器内监听端口,与 PORT 环境变量重复时以此为准 |
ui.title | Gatus | 浏览器标签页标题 |
ui.header | 空 | 页面顶部大标题 |
八、配置文件挂载
8.1 单文件挂载(推荐)
本篇采用目录级挂载(/opt/data/gatus/config:/config),优点是目录内文件结构调整不需要改 compose;并保持官方默认文件名 config.yaml。
8.2 热重载实测
挂载进容器的配置文件修改后无需重启,Gatus 的文件监听会自动热重载。实测:直接编辑宿主机 /opt/data/gatus/config/config.yaml 修改端点间隔与 UI 标题,数秒内生效——容器日志出现重新初始化记录,Web 首页内嵌配置立即更新,容器 PID 不变(无需重建容器)。
⚠️ 注意:热重载虽方便,但
ports/volumes/环境变量这类 compose 层修改必须docker compose up -d重建容器才生效;热重载只覆盖 Gatus 自身的 YAML 配置。
九、等价 docker run
不使用 compose 时的等价单命令部署(与本篇 compose 完全等价,实测可启动):
docker run -d \
--name gatus-5370-run \
--restart unless-stopped \
-p 13901:8080 \
-v /opt/data/gatus/config:/config \
-v /opt/data/gatus/data:/data \
ghcr.io/twin/gatus:v5.37.0
验证:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:13901/
实测输出:
200
参数与 compose 的对应关系:-p 13901:8080 ↔ ports,两个 -v ↔ volumes,--restart unless-stopped ↔ restart。生产环境多服务协同时仍推荐 compose,编排关系一目了然。
十、常用运维命令
| 操作 | 命令 | 实测说明 |
|---|---|---|
| 查看服务状态 | docker compose ps | 两服务均应为 Up |
| 跟踪日志 | docker compose logs -f gatus | 每个拨测周期打印 Monitored ... 行 |
| 重启 Gatus | docker compose restart gatus | 秒级完成,数据因落盘不丢 |
| 修改配置后应用 | 直接编辑宿主机 config/config.yaml | 热重载,无需重启 |
| 升级版本 | 改 image tag 后 docker compose up -d | 数据保留,历史结果连续 |
| 停止并清理 | docker compose down | -v 才会删卷,bind mount 不受影响 |
| 查看数据文件 | ls -lh /opt/data/gatus/data/ | data.db 即全部持久化数据 |
| 检查拨测数据条数 | sqlite3 /opt/data/gatus/data/data.db 'SELECT COUNT(*) FROM endpoint_results;' | 宿主机需装有 sqlite3 |
十一、常见问题
Q1:启动即 panic: configuration file not found
实测原因:/config 挂载目录里没有 config.yaml(常见于把文件命名成 gatus.yml/config.yml)。Gatus 容器只认 config/config.yaml,其余文件名一律视同不存在,实测回显:
panic: configuration file not found
goroutine 1 [running]:
main.main()
/app/main.go:32 +0x21a
解决:重命名为 config.yaml,或设 GATUS_CONFIG_PATH 指向真实文件名。
Q2:配置了 healthcheck 一直 health: starting,日志里全是 bind: address already in use
实测过程与结论:因 distroless 镜像内没有 shell 与 curl,自然想到用 test: ["CMD", "/gatus", "--help"] 做健康检查——但实测发现 /gatus 进程一启动就要加载配置并监听 8080,与容器内主进程端口冲突,healthcheck 每次都以失败告终:
2026/10/17 20:29:59 [controller.Handle] Listening on 0.0.0.0:8080
2026/10/17 20:29:59 [controller.Handle] failed to listen: listen tcp 0.0.0.0:8080: bind: address already in use
(实测 healthcheck 退出码 1,容器始终 health: starting)
结论:官方 distroless 镜像内无法实现进程内 healthcheck。健康保障建议:保留 restart: unless-stopped(进程崩溃自动拉起),并在配置里加一个自监控端点(http://localhost:8080/)让 Gatus 自检并告警。
Q3:docker exec 进入容器报 executable file not found
实测确认镜像为 distroless,无 sh/bash/curl:
OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH
解决:不要试图进容器,改在宿主机排障——docker logs 看日志、读挂载目录的配置与数据文件、宿主机 curl 探测 13901 端口。
Q4:Gatus 容器内访问不了拨测目标
实测要点:endpoints[].url 里写的 gatus-5370-target-nginx 是 compose 网络内的服务名/容器名,要求 Gatus 与目标在同一自定义网络(本篇 gatus-net)。若目标在宿主机上,URL 应写 http://172.17.0.1:端口 或在 Gatus 服务上加 extra_hosts: - "host.docker.internal:host-gateway" 后用 host.docker.internal。排查顺序:docker compose exec gatus 无法用(distroless),改用同网络任意工具容器 ping/curl 目标名验证 DNS 与连通性。
Q5:改了 compose 的端口映射不生效
热重载只作用于 Gatus 的 YAML 配置。ports/volumes/environment 属于容器编排层,必须 docker compose up -d(会自动重建受影响的容器)才生效。
Q6:公网暴露后担心安全
Gatus 默认无认证,公网部署务必开启 security.basic(bcrypt 口令)或 OIDC,配置方法与 401/200 实测回显见《Gatus 配置参数详解》;或在前置 Nginx 反代上做访问控制与 TLS 终结。
十二、参考链接
- 官方 Docker 使用文档:https://github.com/TwiN/gatus#docker
- 官方 SQLite 存储示例:https://github.com/TwiN/gatus/tree/master/.examples/docker-compose-sqlite-storage
- 官方配置手册:https://gatus.io/docs
- 本站配套:《Gatus 介绍与选型指南》《Gatus 配置参数详解》《Gatus 运维手册》