主题
14 · 运维脚本:健康检查与服务重启
目标:写出
healthcheck.sh——curl 探活,失败则systemctl restart mini-api,并记日志。
前置:10 · 迷你 API · 13 · 脚本结构 · 08 · systemd
1. 环境前提
mini-api.service已按第 10 篇安装并可systemctl status mini-api- 健康 URL 默认:
http://127.0.0.1:8080/health(也可改成经 Nginx 的http://127.0.0.1/health) - 已有
~/lab/scripts/lib/log.sh(无则从 13 篇补上)
bash
mkdir -p ~/lab/scripts/lib ~/lab/logs
curl -sS http://127.0.0.1:8080/health || true1
2
2
2. 交付脚本:healthcheck.sh
bash
cat > ~/lab/scripts/healthcheck.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/log.sh
source "$SCRIPT_DIR/lib/log.sh"
HEALTH_URL="${HEALTH_URL:-http://127.0.0.1:8080/health}"
SERVICE_NAME="${SERVICE_NAME:-mini-api}"
LOG_FILE="${LOG_FILE:-$HOME/lab/logs/healthcheck.log}"
CURL_TIMEOUT="${CURL_TIMEOUT:-5}"
mkdir -p "$(dirname "$LOG_FILE")"
append_log() {
# 同时打到 stdout 与日志文件
local msg
msg="$(log_info "$*")"
echo "$msg" | tee -a "$LOG_FILE"
}
probe() {
curl -fsS --max-time "$CURL_TIMEOUT" -o /dev/null "$HEALTH_URL"
}
restart_service() {
append_log "probe failed; restarting ${SERVICE_NAME}"
if ! sudo systemctl restart "$SERVICE_NAME"; then
log_error "systemctl restart ${SERVICE_NAME} failed"
echo "$(log_error "systemctl restart ${SERVICE_NAME} failed")" >>"$LOG_FILE"
return 1
fi
sleep 2
if probe; then
append_log "restart ok; service healthy"
return 0
fi
log_error "still unhealthy after restart: ${HEALTH_URL}"
echo "$(log_error "still unhealthy after restart")" >>"$LOG_FILE"
return 1
}
main() {
if probe; then
append_log "ok ${HEALTH_URL}"
exit 0
fi
if restart_service; then
exit 0
fi
exit 1
}
main "$@"
EOF
chmod 755 ~/lab/scripts/healthcheck.sh1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
若尚无 lib/log.sh,先执行 13 篇中的 log.sh 片段。
3. 手动验收
bash
# 正常:应 exit 0,日志有 ok
~/lab/scripts/healthcheck.sh
echo "exit=$?"
tail -n 5 ~/lab/logs/healthcheck.log
# 模拟挂掉(练习机):停服务后再检查,应触发 restart
sudo systemctl stop mini-api
~/lab/scripts/healthcheck.sh
sudo systemctl is-active mini-api
curl -sS http://127.0.0.1:8080/health1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
sudo 无密码跑定时任务时:给该用户配置 仅允许 systemctl restart mini-api 的 sudoers(生产再收紧);练习机可先用交互密码验证逻辑。
经 Nginx 探活示例:
bash
HEALTH_URL=http://127.0.0.1/health ~/lab/scripts/healthcheck.sh1
4. 设计要点(可口述)
text
curl 成功 → 记 ok → exit 0
curl 失败 → systemctl restart → 再 curl
成功 → exit 0
仍失败 → exit 1(留给 cron/监控)1
2
3
4
2
3
4
| 点 | 原因 |
|---|---|
听 127.0.0.1 | 不依赖公网;与 10 篇绑定一致 |
curl -f | 4xx/5xx 当失败 |
日志进 ~/lab/logs/ | 15 篇清理脚本有目标 |
| 环境变量可覆盖 | 换服务名/URL 无需改文件 |
5. 动手清单
- [ ]
healthcheck.sh在服务正常时 exit 0 - [ ]
stop后再跑,能自动restart并恢复/health - [ ]
~/lab/logs/healthcheck.log有对应行 - [ ] 用
HEALTH_URL=...覆盖跑通一次
6. 常见翻车
| 翻车 | 处理 |
|---|---|
sudo 密码卡住 cron | 配 NOPASSWD 限定命令,或用 root crontab(更要小心) |
服务名不是 mini-api | SERVICE_NAME=... |
| 探的是 80 但后端挂了 Nginx 仍 502 | 对 upstream URL 探,或同时检查 systemctl is-active |
set -e 与 if probe | if probe; then 中失败不会误杀脚本;保持该写法 |
7. 官方入口
man curl、man systemctl- 回看 10 验收清单
下一篇:备份、日志清理与 cron —— 让检查脚本定时跑起来。
