跳到主要内容

服务部署与可观测性

当 Python 自动化变成 API、Webhook 或 worker 后,它就是生产服务:需要受控启动、资源边界、健康状态、指标、日志、告警和升级策略。开发命令 uvicorn --reload 不属于生产运行方式。

1. 健康检查分层

端点含义是否访问下游
/livez进程与事件循环仍可响应
/readyz当前实例可接收流量仅检查必须依赖,且有短超时
/metricsPrometheus 拉取指标
# src/ops_api/main.py
from fastapi import FastAPI, HTTPException
from prometheus_client import Counter, make_asgi_app

app = FastAPI(docs_url=None, redoc_url=None)
requests_total = Counter("ops_api_requests_total", "API requests", ["route", "outcome"])


@app.get("/livez")
def livez() -> dict[str, str]:
# 不检查 Redis、Kubernetes 等下游,避免短暂依赖故障导致所有实例被杀。
return {"status": "ok"}


@app.get("/readyz")
def readyz() -> dict[str, str]:
# check_redis 必须有连接超时,失败时返回 503 让负载均衡停止分流。
if not check_redis(timeout_seconds=1):
raise HTTPException(status_code=503, detail="queue unavailable")
return {"status": "ready"}


# 指标端点应由网络策略限制为 Prometheus 可访问。
app.mount("/metrics", make_asgi_app())

指标至少包括 HTTP 请求数/耗时/错误、队列深度、任务成功失败数、重试与死信数、外部依赖错误和变更执行时长。避免在指标 label 中使用主机名、任务 ID 或 URL 等高基数字段。

2. systemd 运行 API 或 worker

# /etc/systemd/system/ops-api.service
[Unit]
Description=Internal operations API
After=network-online.target
Wants=network-online.target

[Service]
Type=exec
User=ops-api
Group=ops-api
WorkingDirectory=/opt/ops-api
EnvironmentFile=/etc/ops-api/ops-api.env
# 使用项目固定的虚拟环境;workers 根据 CPU、I/O 和连接池容量压测后设定。
ExecStart=/opt/ops-api/.venv/bin/uvicorn ops_api.main:app --host 127.0.0.1 --port 8080 --workers 2
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/var/lib/ops-api

[Install]
WantedBy=multi-user.target
# 修改 unit 或环境文件后重新加载;密钥文件权限应仅允许服务账号读取。
sudo systemctl daemon-reload
sudo systemctl enable --now ops-api.service
sudo systemctl status ops-api.service
sudo journalctl -u ops-api.service --since '15 minutes ago' --no-pager

定时任务优先使用 systemd timer,能获得 journald 日志、失败状态与依赖关系;cron 适合简单兼容场景,但同样应锁定并发、防止重叠运行并把输出送入日志系统。

3. 容器与 Kubernetes 运行约束

容器镜像应使用固定 base digest、多阶段构建、非 root 用户、只读根文件系统、资源限制和镜像扫描。Kubernetes 部署至少需要:

  • readinessProbe 调用 /readyzlivenessProbe 调用 /livez
  • resources.requests/limits 由压测而非猜测设定;
  • 专用 ServiceAccount 与最小 RBAC,不挂载管理员 kubeconfig;
  • terminationGracePeriodSeconds 覆盖最长安全收尾时间;
  • 多副本服务使用 PDB,升级时验证队列 worker 的优雅停止与任务租约。

Webhook API 与 worker 应独立部署和扩缩容。API 负责认证、校验、去重、入队;worker 负责长时任务和重试。不要让 API 进程承担不可中断的变更。

4. 日志、关联与告警

每个 HTTP 请求和队列任务生成或继承 request_id / change_id,贯穿 API、worker、SSH、Kubernetes 调用和通知。日志输出 JSON 到 stdout,由 journald、Loki 或 Elasticsearch 收集;不要在应用内做日志文件轮转。

告警应覆盖“用户影响”和“系统积压”:5xx 比率、readyz 失败、任务积压时间、死信数量、变更失败率和凭据即将过期。单次任务失败不一定要呼叫值班人员,但持续失败和队列无法消费必须告警。

5. 发布与回滚

发布前运行迁移、配置校验和预生产 smoke test;发布后观察 readiness、错误率、任务成功率和队列积压。镜像与部署记录必须保留不可变 digest。回滚应恢复上一份已验证的配置与 digest,并检查是否存在需要补偿的半完成任务。