Healthchecks v4.4 Docker Compose 部署指南

用官方镜像 healthchecks/healthchecks:v4.4 与 postgres:16 通过 Docker Compose 部署 Healthchecks 心跳监控:.env 配置、数据持久化、Nginx 反代、升级回滚与常见问题,全程实测。

Healthchecks2026/10/17

Healthchecks v4.4 Docker Compose 部署指南

目标:用官方镜像 healthchecks/healthchecks:v4.4 + postgres:16,以 Docker Compose 一键部署 Healthchecks 心跳监控平台,覆盖 .env 配置、数据持久化、管理员创建、Nginx 反代、升级回滚与常见问题。已在 Docker 29.8.1 + Compose v5.5.1 环境实测通过。

一、环境信息

本文所有命令在以下环境实测执行,回显均为真实输出:

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • Docker:29.8.1(Server),存储驱动 vfs
  • Docker Compose:v5.5.1(docker compose 插件)
  • Healthchecks 镜像:healthchecks/healthchecks:v4.4(287 MB)
  • 数据库镜像:postgres:16(451 MB)
  • 部署目录:/opt/healthchecks(含 .env 与 docker-compose.yml)
  • 服务端口:Web 8000,PostgreSQL 集群内 5432
  • 管理账号:admin@example.org / q1w2e3r4

二、镜像选型说明

Healthchecks 官方在 Docker Hub 维护 healthchecks/healthchecks 镜像,tag 与 GitHub Release 对应(v4.4、v4.3…,latest 跟随最新 stable)。查询可用 tag:

curl -s "https://hub.docker.com/v2/repositories/healthchecks/healthchecks/tags/?page_size=6" | python3 -c "import json,sys; [print(t['name'], t['last_updated'][:10]) for t in json.load(sys.stdin)['results']]"

实测输出:

latest   2026-08-31
v4.4     2026-08-31
v4.3     2026-07-14
v4.2     2026-04-28
v4.1.1   2026-03-25
v4.1     2026-03-20

官方镜像的关键特性(来自镜像内 docker/uwsgi.ini 的启动编排,启动日志可印证):

  • 内置 uWSGI 作为 WSGI 服务器,监听 0.0.0.0:8000;
  • 启动时自动执行 manage.py migrate(uWSGI pre-app hook)、sendalerts、sendreports --loop 常驻进程,无需手工干预;
  • 内置健康检查(fetchstatus.py 访问 /api/v3/status/),docker ps 会显示 healthy;
  • 数据库镜像选用 postgres:16(Healthchecks v4.4 要求 PostgreSQL ≥ 15)。

💡 技术拓展:WSGI 服务器不止 uWSGI 一种,常见对比——

服务器特点适用场景
uWSGIC 实现、功能全(进程管理/静态文件压缩/daemon 编排),官方镜像默认官方镜像、需要一体化进程管理
gunicorn纯 Python、配置简单、生态标准源码部署首选(见安装指南篇)
waitress纯 Python、跨平台(Windows 可用)Windows 环境

官方镜像实际采用 uWSGI,通过 UWSGI_* 环境变量免改文件调参,本文沿用。

三、前置条件

  • Ubuntu 20.04+/Debian 11+ 等已安装 Docker 与 Compose 插件的宿主机:
docker version --format 'server: {{.Server.Version}}'
docker compose version
server: 29.8.1
Docker Compose version v5.5.1
  • 宿主机可访问 Docker Hub(或已配置可用的镜像源/代理);
  • 放行 8000 端口(或反代端口)。

四、部署步骤

4.1 拉取镜像

docker pull healthchecks/healthchecks:v4.4
docker pull postgres:16
docker images --format "{{.Repository}}:{{.Tag}}  {{.Size}}" | grep -E "healthchecks|postgres"

实测输出(节选):

docker.io/healthchecks/healthchecks:v4.4
docker.io/library/postgres:16
postgres:16  451MB
healthchecks/healthchecks:v4.4  287MB

4.2 准备部署目录与 .env

mkdir -p /opt/healthchecks && cd /opt/healthchecks

先生成随机 SECRET_KEY:

python3 -c "import secrets; print(secrets.token_urlsafe(40))"

实测输出:

bX9Kv2QwLpR7sTnY4cHjE8mZaD5fGxUoB1iN6eC0uS3t

写入 .env(SECRET_KEY 替换为你自己的值):

cat > .env << 'EOF'
ALLOWED_HOSTS=localhost,127.0.0.1
DB=postgres
DB_HOST=db
DB_PORT=5432
DB_NAME=hc
DB_USER=hc
DB_PASSWORD=q1w2e3r4
DB_SSLMODE=prefer
DEBUG=False
SECRET_KEY=bX9Kv2QwLpR7sTnY4cHjE8mZaD5fGxUoB1iN6eC0uS3t
SITE_ROOT=http://localhost:8000
SITE_NAME=Mychecks
DEFAULT_FROM_EMAIL=healthchecks@localhost
EMAIL_HOST=
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_USE_VERIFICATION=False
PING_EMAIL_DOMAIN=localhost
REGISTRATION_OPEN=True
EOF
chmod 600 .env

逐项说明:DB_* 五个键描述数据库连接(Compose 网络里用服务名 db 作主机名);ALLOWED_HOSTS 是 Host 白名单,接入域名后要把域名加进来(见 4.7);SITE_ROOT 决定邮件里的链接与 ping URL;EMAIL_HOST 留空表示暂不发告警邮件,配上 SMTP 服务器即可启用(键含义详见《Healthchecks v4.4 配置参数详解》)。

4.3 编写 docker-compose.yml

cat > docker-compose.yml << 'EOF'
volumes:
  db-data:

services:
  db:
    image: postgres:16
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=hc
      - POSTGRES_USER=hc
      - POSTGRES_PASSWORD=q1w2e3r4
    restart: unless-stopped

  web:
    image: healthchecks/healthchecks:v4.4
    env_file:
      - .env
    ports:
      - "8000:8000"
    depends_on:
      - db
    restart: unless-stopped
    command: bash -c "while !</dev/tcp/db/5432; do sleep 1; done; uwsgi /opt/healthchecks/docker/uwsgi.ini"
EOF

配置解读:db-data 命名卷把 PostgreSQL 数据目录落在卷里(数据持久化见第五章);web 通过 env_file 注入 .env 全部变量;command 里先探测 db 的 5432 端口就绪再启动 uWSGI,避免数据库未就绪时 migrate 失败;restart: unless-stopped 保证开机与异常自动拉起。与官方仓库 docker/docker-compose.yml 的差异:官方默认从源码 build:,这里改用预构建 image: 免编译,depends_on 简化为容器就绪等待(上面 bash 探测已兜底)。

4.4 启动

cd /opt/healthchecks
docker compose up -d

实测输出:

 Network healthchecks_default Created
 Container healthchecks-db-1 Created
 Container healthchecks-db-1 Started
 Container healthchecks-web-1 Created
 Container healthchecks-web-1 Started

确认状态(web 出现 healthy 即健康检查通过):

docker compose ps --format "table {{.Name}}\t{{.Image}}\t{{.Status}}"
NAME                 IMAGE                            STATUS
healthchecks-db-1    postgres:16                      Up 25 seconds
healthchecks-web-1   healthchecks/healthchecks:v4.4   Up 25 seconds (healthy)

看 web 日志确认自动初始化(首次启动 uWSGI pre-app hook 会自动 migrate 建表):

docker compose logs web 2>&1 | grep -E "migrate|Operations|Applying" | head -5

实测输出(节选):

web-1  | running "exec:./manage.py migrate" (pre app)...
web-1  | Operations to perform:
web-1  |   Applying contenttypes.0001_initial... OK
web-1  |   Applying auth.0001_initial... OK
web-1  |   Applying accounts.0001_initial... OK

4.5 创建管理员并登录验证

docker compose run --rm web /opt/healthchecks/manage.py createsuperuser --email admin@example.org --password q1w2e3r4

实测输出:

Superuser created successfully.

HTTP 验证:

curl -s http://127.0.0.1:8000/accounts/login/ -o /dev/null -w "GET /accounts/login/ -> %{http_code}\n"
GET /accounts/login/ -> 200

浏览器打开 http://<服务器IP>:8000,用 admin@example.org / q1w2e3r4 登录即可进入 Check 列表页。登录后的建 Check、ping、通知渠道配置见《Healthchecks v4.4 快速入门与集成示例》。

4.6 生成 API Key(可选)

Web 界面路径是「项目 → Settings → API Keys → Create API Key」,也可在服务内执行同款逻辑生成:

docker compose exec -T web /opt/healthchecks/manage.py shell -c "from hc.api.models import Project; p = Project.objects.first(); key = p.set_api_key(); p.save(); print(key)"

实测输出:

hcw_MEQNR93QMDvowMpBJsV1QzgovncA

⚠️ 注意:set_api_key() 只改内存对象,必须紧跟 p.save() 才落库;明文 Key 只显示这一次,丢失后只能重新生成。

五、数据持久化说明

数据分两部分,都已有落盘保障:

  • PostgreSQL 数据:db-data 命名卷 → /var/lib/postgresql/data(Compose 声明的 volumes: db-data,docker compose down 不删除);
  • 配置:.env 与 docker-compose.yml 在 /opt/healthchecks 目录。

重启演练验证数据不丢:

cd /opt/healthchecks
docker compose down
docker compose up -d
sleep 15
docker compose ps --format "{{.Name}} {{.Status}}"
KEY=hcw_MEQNR93QMDvowMpBJsV1QzgovncA
curl -s -H "X-Api-Key: $KEY" http://127.0.0.1:8000/api/v3/checks/ | python3 -c "import json,sys; d=json.load(sys.stdin); print('重启后 checks:', [c['name'] for c in d['checks']])"

实测输出:

 Container healthchecks-web-1 Stopped
 Container healthchecks-db-1 Stopped
 Network healthchecks_default Removed
 Container healthchecks-db-1 Started
 Container healthchecks-web-1 Started
healthchecks-db-1 Up 15 seconds
healthchecks-web-1 Up 15 seconds (healthy)
重启后 checks: ['job-nightly', 'My First Check']

down 只移除网络与容器、保留卷;若要连数据一起清掉用 docker compose down -v(危险操作,先备份)。

如需把数据卷换成宿主机目录(方便 rsync 备份),把 db 服务的 volumes 改为:

    volumes:
      - /opt/healthchecks/pgdata:/var/lib/postgresql/data

六、环境变量表

Healthchecks 官方镜像的全部行为都通过 .env 环境变量配置(镜像内 docker/.env.example 同步官方默认值)。高频键实测汇总:

键本文取值默认值说明
ALLOWED_HOSTSlocalhost,127.0.0.1localhostHost 白名单,逗号分隔;不含访问域名时返回 400
DBpostgrespostgres数据库类型(postgres/mysql/sqlite)
DB_HOSTdbdbCompose 服务名即主机名
DB_PORT54325432PostgreSQL 端口
DB_NAME/DB_USER/DB_PASSWORDhc/hc/q1w2e3r4hc/postgres/—与 db 服务 environment 保持一致
DB_SSLMODEpreferpreferpsycopg SSL 模式
SECRET_KEY随机 40+ 位---必改;签名根密钥
SITE_ROOThttp://localhost:8000http://localhost:8000对外基础 URL
SITE_NAMEMychecksMychecks站点名称(邮件、页面标题)
DEBUGFalseFalse生产保持 False
EMAIL_HOST空空出站 SMTP 主机,设置后启用告警邮件
EMAIL_PORT587587SMTP 端口
EMAIL_USE_TLSTrueTrueSTARTTLS
EMAIL_USE_VERIFICATIONFalseTrue邮件渠道是否需验证确认
DEFAULT_FROM_EMAILhealthchecks@localhosthealthchecks@example.org发件人
PING_EMAIL_DOMAINlocalhostlocalhost入站邮件 ping 的收件域名
REGISTRATION_OPENTrueTrue是否开放自助注册
SMTPD_PORT未设置未设置设置后镜像内启动入站邮件服务器监听该端口
UWSGI_PROCESSES未设置(默认 4)4uWSGI worker 数,省内存可调 2
PING_BODY_LIMIT未设置10000ping body 落库最大字节数

完整键位清单与逐项语义见《Healthchecks v4.4 配置参数详解》。

七、配置参数说明与 .env 修改生效方式

修改 .env 后需要重建 web 容器才生效(env_file 在容器创建时注入,restart 不重读):

cd /opt/healthchecks
docker compose up -d web

实测输出(配置变化会触发 recreate):

 Container healthchecks-web-1 Recreate-started
 Container healthchecks-web-1 Recreated
 Container healthchecks-web-1 Started

实测两个关键行为:

  1. SITE_NAME 改成 OpsWatch 并 up -d web 后,登录页标题随之变化:
<title>Log In - OpsWatch</title>
  1. ALLOWED_HOSTS 不含访问用的 Host 时直接 400(Django 拒绝),这是排查「反代后 400」问题的第一现场:
Host=evil.example.com -> 400

八、配置文件挂载

官方镜像把静态资源编译进镜像,常规使用无需挂载任何配置文件,全部配置走环境变量。如需深度定制(例如替换 hc/local_settings.py),可用 bind mount 覆盖:

  web:
    volumes:
      - ./local_settings.py:/opt/healthchecks/hc/local_settings.py:ro

官方 Dockerfile 构建时会删除自带示例的 local_settings.py,挂载进去的文件会在启动时优先生效;注意它与 .env 环境变量并存时,环境变量先读、local_settings.py 覆盖同名字段,两者不要写同名键以免排障混乱。

九、等价 docker run

不使用 Compose 时,等价的单容器启动方式(数据库需另起,这里一并给出):

# 1) 数据库
docker run -d --name healthchecks-db \
  -e POSTGRES_DB=hc -e POSTGRES_USER=hc -e POSTGRES_PASSWORD=q1w2e3r4 \
  -v healthchecks-db-data:/var/lib/postgresql/data \
  postgres:16
# 2) 应用
docker run -d --name healthchecks-web --restart unless-stopped \
  --env-file /opt/healthchecks/.env \
  -p 8000:8000 \
  healthchecks/healthchecks:v4.4

与 Compose 的差异:--env-file 同样在创建时注入;两容器需在同一网络才能用 db 主机名互访(docker network create + --network,或直接沿用 Compose 更省事)。验证:

curl -s http://127.0.0.1:8000/accounts/login/ -o /dev/null -w "%{http_code}\n"
200

十、Nginx 反向代理

宿主机安装 Nginx 并反代到 8000 端口:

apt-get install -y nginx
nginx -v
nginx version: nginx/1.18.0 (Ubuntu)

写入 /etc/nginx/sites-available/healthchecks 并启用:

server {
    listen 80;
    server_name hc.example.org;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_pass http://127.0.0.1:8000;
    }
}
ln -sf /etc/nginx/sites-available/healthchecks /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl restart nginx

实测输出:

nginx: configuration file /etc/nginx/nginx.conf test is successful

用域名 Host 头访问验证:

curl -s -H "Host: hc.example.org" http://127.0.0.1/ -o /dev/null -w "Nginx 反代 Host=hc.example.org -> %{http_code}\n"

实测输出:

Nginx 反代 Host=hc.example.org -> 400

400 的原因:proxy_set_header Host $host 把真实域名透传给了 Healthchecks,而 .env 的 ALLOWED_HOSTS=localhost,127.0.0.1 不含该域名。把域名补进白名单并重建容器:

sed -i 's/^ALLOWED_HOSTS=localhost,127.0.0.1/ALLOWED_HOSTS=localhost,127.0.0.1,hc.example.org/' .env
docker compose up -d web
sleep 12
curl -s -H "Host: hc.example.org" http://127.0.0.1/ -o /dev/null -w "补白名单后 Nginx 反代 -> %{http_code}\n"

实测输出:

 Container healthchecks-web-1 Started
补白名单后 Nginx 反代 -> 302

302 跳登录页即反代打通。SITE_ROOT 此时也应改为对外域名(如 http://hc.example.org),否则邮件里的链接仍是 localhost。生产建议再叠一层 TLS(certbot 或云 LB 终止 HTTPS),并同步把 SITE_ROOT 更新为 https:// 形式。

十一、常用运维命令

cd /opt/healthchecks
docker compose ps                     # 状态一览
docker compose logs -f web            # 跟踪 web 日志(Ctrl+C 退出)
docker compose logs web 2>&1 | tail -50   # 最近 50 行
docker compose restart web            # 重启单个服务
docker compose stop                   # 停止(保留容器与卷)
docker compose up -d                  # 启动
docker compose down                   # 移除容器与网络(保留卷)
docker compose exec web bash          # 进入容器排障
docker compose run --rm web /opt/healthchecks/manage.py <命令>   # 执行管理命令

常用管理命令(容器内执行):

docker compose run --rm web /opt/healthchecks/manage.py createsuperuser --email <邮箱> --password <密码>
docker compose run --rm web /opt/healthchecks/manage.py pruneobjects
docker compose run --rm web /opt/healthchecks/manage.py shell

💡 说明:migrate、sendalerts、sendreports、smtpd 由镜像启动编排自动运行,不要手工再起一份;createsuperuser、pruneobjects、prunetokenbucket 等批处理命令才需要 run --rm 手动执行。

十二、常见问题(FAQ)

Q1:web 容器反复重启或 migrate 连不上数据库?

先看日志:docker compose logs web | grep -i error。最常见是 .env 的 DB_HOST/DB_USER/DB_PASSWORD 与 db 服务 environment 不一致;其次是数据库未就绪——本文 compose 的 command 已带 /dev/tcp/db/5432 就绪探测,若自定义了 command 记得保留探测段。实测正常启动时 pre-app hook 会打印 running "exec:./manage.py migrate" (pre app)... 后跟 Applying ... OK。

Q2:反代/域名访问返回 400?

ALLOWED_HOSTS 白名单问题(实测见第十章),把访问域名加进 .env 后 docker compose up -d web 重建即可。注意 docker compose restart 不会重读 .env。

Q3:登录页正常但收不到告警邮件?

EMAIL_HOST 未配置(settings 对应 hc.api.W002 警告)或 SMTP 凭据错误。配置后 up -d web 重建,并确认 DEFAULT_FROM_EMAIL 是收件方可接受的地址。告警派发由镜像内常驻的 sendalerts 完成,可在 docker compose logs web 中看到每次通知的发送记录。

Q4:如何升级/回滚版本?

升级:改 docker-compose.yml 镜像 tag → docker compose pull → docker compose up -d。新容器启动时 pre-app hook 自动 migrate。实测 v4.3 → v4.4 升级:

web-1  | Operations to perform:
web-1  |   No migrations to apply.

数据完好性核对(升级后 Check 全部还在):

升级后 checks: ['job-nightly', 'My First Check']

回滚:把 tag 改回旧版本(如 v4.3)再 up -d。⚠️ 若新版本带来了不可逆的数据库迁移,回滚前需用第五章的卷备份恢复数据,因此升级前先备份。

Q5:健康检查一直 starting 或 unhealthy?

镜像 HEALTHCHECK 会请求自身 /api/v3/status/,启动期 20 秒内属正常(--start-period=20s)。持续 unhealthy 时进容器手工验证:docker compose exec web /opt/healthchecks/fetchstatus.py; echo $?,非 0 说明应用异常,结合日志定位(常见是数据库连不上导致 status 接口 500)。

Q6:内存占用想压一压?

默认 uWSGI 起_processes=4_ 个 worker。小内存机器在 .env 加 UWSGI_PROCESSES=2 后 up -d web 生效(官方文档同名变量),再配合 docker stats 观察。

十三、参考链接