首页
/ WiFi-DensePose 生产部署指南:从单机 Docker 到 Kubernetes、多云与可观测体系实战

WiFi-DensePose 生产部署指南:从单机 Docker 到 Kubernetes、多云与可观测体系实战

2026-09-07 14:02:09作者:宣海椒Queenly

本篇技术指南以 archive/v1/docs/deployment.md(WiFi-DensePose Deployment Guide)为核心主体,系统讲解如何把 WiFi-DensePose 服务从单节点 Docker 一步步部署为具备高可用、可伸缩、可观测与安全加固的生产集群。读者将掌握:基于环境变量与集中式配置的部署编排、Docker Compose 与 Kubernetes 的完整清单写法、AWS/GCP/Azure 托管服务选型、HPA/VPA 弹性伸缩、Prometheus+Grafana 监控告警,以及数据库备份与灾难恢复的落地方式。文中还结合仓库源码给出环境变量的底层映射关系与可验证依据,方便读者对照真实实现排查部署问题。

适用前提与文档定位(阅读前须知)

本指南对应的主体是 archive/v1 中记载的原始纯 Python 版 WiFi-DensePose API 的生产部署体系(FastAPI + PostgreSQL/Redis + 推理服务 + 观测栈)。需要先明确两点事实,避免误用:

  1. 根据 archive/v1/DEPRECATED.mdADR-187 归档弃用诚实标注archive/v1 整棵代码树已被归档、不再维护,仅作为研究存档保留;其 DensePoseHead 只定义了网络结构、未携带训练权重(随机初始化,无 checkpoint 加载路径)。因此本文是一份面向该 v1 API 技术栈的部署方法参考,不建议在新项目中直接照搬该目录代码;当前仓库中被维护的实现位于 v2/ Rust workspace,落地容器化运行时见 docker/docker-compose.yml
  2. 本指南所引环境变量、端点、模块路径均在 v1 源码(src/config.pysrc/config/settings.pysrc/app.pysrc/main.py)中有真实对应实现,可作为阅读与验证的锚点。

部署选项与总体架构

WiFi-DensePose 生产部署覆盖从单机到大规模集群的完整梯度:

部署方式 适用场景
Docker Compose 单节点开发环境与小型生产部署
Kubernetes 多节点生产部署,支持自动伸缩
云平台 AWS / GCP / Azure 托管服务
边缘部署 IoT 网关与边缘计算设备

该文档给出了一个典型的目标架构,包含负载均衡(Nginx)、CSI 数据源(WiFi 路由器)、横向扩展的 API 服务副本、时序数据库与缓存、以及独立监控栈:

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Load Balancer │    │   WiFi Routers  │    │   Monitoring    │
│    (Nginx)      │    │   (CSI Source)  │    │  (Prometheus)   │
└─────────────────┘    └─────────────────┘    └─────────────────┘
         │                       │                       │
         ▼                       ▼                       ▼
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│  WiFi-DensePose │    │    Database     │    │     Redis       │
│   API Servers   │◄──►│  (PostgreSQL)   │    │    (Cache)      │
│   (3+ replicas) │    │  (TimescaleDB)  │    │                 │
└─────────────────┘    └─────────────────┘    └─────────────────┘

架构中的职责对应到源码并不难确认:API 服务由 src/app.py 中的 FastAPI create_app() 工厂构建,中间件按"速率限制 → 认证 → CORS → 可信主机"顺序装配(RateLimitMiddleware / AuthenticationMiddleware / CORSMiddleware / TrustedHostMiddleware),路由以 settings.api_prefix 为前缀挂载 Pose、Stream,健康检查固定挂在 /health;服务生命周期则由 src/main.py 中的 ServiceOrchestrator 管理,并注册了 SIGINT/SIGTERM 信号处理实现优雅停机。因此架构图里"3+ 副本 + 健康检查 + 优雅上下线"的设计,都对应到 app 与 main 两个入口的真实行为。

前置条件

系统资源要求

文档给出了两档参考基线(非当前仓库实测数据,仅作容量规划起点):

最低配置

  • CPU:4 核 2.4GHz
  • 内存:8GB RAM
  • 存储:100GB SSD
  • 网络:1Gbps 以太网

推荐配置

  • CPU:8+ 核 3.0GHz
  • 内存:16GB+ RAM
  • 存储:500GB+ NVMe SSD
  • 网络:10Gbps 以太网
  • GPU:NVIDIA GPU,8GB+ 显存(可选,用于推理加速)

软件依赖

容器运行时与编排工具安装方式如下(对应文档原文命令):

# Docker(20.10+)
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Docker Compose(2.0+)
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

Kubernetes 部署还需要 kubectl 与 Helm:

# kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

# Helm(3.0+)
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

仓库视角:根目录 example.env 可作为环境变量模板的起点;更贴近本仓库当前运行方式的容器编排见 docker/docker-compose.yml(Rust sensing-server + python-sensing),其中的 healthcheckcap_drop: ALLno-new-privileges 等写法与本指南的安全建议一致,可互相印证。

Docker 部署

单节点 Docker Compose

1. 获取源码与环境模板

将仓库(RuView,其中 v1 代码位于 archive/v1)检出到本地后,拷贝环境模板:

git clone https://gitcode.com/GitHub_Trending/wi/RuView
cd RuView

# 将环境模板复制为 .env 并编辑
cp example.env .env

2. 配置环境变量

编辑 .env 文件,以下几组变量对应文档给出的最小可运行集合:

# Application Settings
APP_NAME=WiFi-DensePose API
VERSION=1.0.0
ENVIRONMENT=production
DEBUG=false

# Server Settings
HOST=0.0.0.0
PORT=8000
WORKERS=4

# Security (CHANGE THESE!)
SECRET_KEY=your-super-secret-key-change-this
JWT_SECRET=your-jwt-secret-change-this

# Database
DATABASE_URL=postgresql://postgres:password@postgres:5432/wifi_densepose
REDIS_URL=redis://:password@redis:6379/0

# Hardware
WIFI_INTERFACE=wlan0
CSI_BUFFER_SIZE=1000
HARDWARE_POLLING_INTERVAL=0.1

# Features
ENABLE_AUTHENTICATION=true
ENABLE_RATE_LIMITING=true
ENABLE_WEBSOCKETS=true

这些变量并非"纸面参数",它们被 src/config/settings.py 中的 Settings(基于 pydantic-settings 的 BaseSettings)逐字段读取,再经 src/config.pyConfigManager 汇总为各业务子配置。可以对照源码确认的映射关系包括:

  • SECRET_KEY / JWT_ALGORITHM / JWT_EXPIRE_HOURSget_security_config(),用于 JWT 签发与认证中间件;
  • DATABASE_URLDATABASE_POOL_SIZE(源码默认 10)、DATABASE_MAX_OVERFLOW(默认 20)→ get_database_config(),还会附加 pool_pre_ping=Truepool_recycle=3600 等连接池调优项;
  • REDIS_URL / REDIS_PASSWORDget_redis_config(),包含 socket_connect_timeout=5retry_on_timeout=Truehealth_check_interval=30 等稳健性参数;
  • WIFI_INTERFACE / CSI_BUFFER_SIZE / HARDWARE_POLLING_INTERVALget_hardware_config()
  • POSE_* 系列 → get_pose_config()(含 model_pathconfidence_thresholdbatch_sizemax_persons,源码默认分别为 0.5/32/10,文档中的 0.7/64/20 属于生产调优取值);
  • ENABLE_* 功能开关 → create_app() 中控制是否加载对应中间件/路由(例如关闭 metrics_enabled 则不注册 /api/v1/metrics 端点,docs_url/redoc_url/openapi_urlis_production 时置为 None)。

需要特别提醒:Settings.secret_key 的开发默认值是 dev-not-secret-CHANGE-IN-PROD,生产环境必须通过 SECRET_KEY 覆盖;同时源码在启动时执行 validate_settings(),生产模式下若校验不通过会以 sys.exit(1) 拒绝启动(见 src/main.py)。

3. 用 Docker Compose 启动服务

# 启动所有服务
docker-compose up -d

# 查看服务状态
docker-compose ps

# 跟踪日志
docker-compose logs -f wifi-densepose

# 横向扩展 API 副本
docker-compose up -d --scale wifi-densepose=3

4. 验证部署

# 健康检查(对应 /health 路由)
curl http://localhost:8000/api/v1/health

# 打开 API 文档(非生产模式默认开启 /docs)
open http://localhost:8000/docs

注意:文档中的健康检查路径 /api/v1/health 与源码的挂载方式存在版本差异——src/app.py 中 health 路由无前缀挂在 /health,而 Pose/Stream 路由使用 settings.api_prefix + "/pose"settings.api_prefix + "/stream"。部署前请以实际运行版本的 OpenAPI(/docs/redoc)为准核对路径。

生产级 Docker Compose

单机生产建议使用独立 Compose 文件,在应用副本前加 Nginx 入口、并补齐 PostgreSQL、Redis、Prometheus、Grafana 全套依赖。文档给出的 docker-compose.prod.yml 完整内容如下,已保留全部关键配置:

version: '3.8'

services:
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/ssl:/etc/nginx/ssl:ro
    depends_on:
      - wifi-densepose
    restart: unless-stopped

  wifi-densepose:
    image: wifi-densepose:latest
    build:
      context: .
      target: production
    environment:
      - ENVIRONMENT=production
      - WORKERS=4
    env_file:
      - .env
    volumes:
      - ./data:/app/data
      - ./logs:/app/logs
      - ./models:/app/models
    depends_on:
      - postgres
      - redis
    restart: unless-stopped
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '2.0'
          memory: 4G
        reservations:
          cpus: '0.5'
          memory: 1G

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: wifi_densepose
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 2G

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    restart: unless-stopped

  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
    volumes:
      - grafana_data:/var/lib/grafana
      - ./monitoring/grafana:/etc/grafana/provisioning:ro
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:
  prometheus_data:
  grafana_data:

值得注意的工程细节:

  • env_file 注入 .env,密钥统一以 POSTGRES_PASSWORDREDIS_PASSWORDGRAFANA_PASSWORD 这类"占位 + Compose 内插值"的方式管理,避免把明文写进 YAML;
  • deploy.resources 同时对 API 副本做 CPU/内存的 limitsreservations 双层约束,与仓库当前 docker/docker-compose.ymldeploy.resources.limits 的约束风格一致;
  • Prometheus 与 Grafana 配置通过只读卷挂载进容器,分别对应仓库中的 monitoring/prometheus-config.ymlmonitoring/grafana-dashboard.jsonmonitoring/alerting-rules.yml,可参考它们反向补齐本机 monitoring/ 目录。

Kubernetes 部署

1. 准备集群基础环境

# 创建命名空间并切换上下文
kubectl create namespace wifi-densepose
kubectl config set-context --current --namespace=wifi-densepose

安装所需 Operator:

# Prometheus Operator(监控栈)
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install prometheus prometheus-community/kube-prometheus-stack \
  --namespace monitoring --create-namespace

# Ingress Controller(入口流量)
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace

2. 创建 Secrets 与 ConfigMaps

Secrets 用于数据库、Redis、应用级密钥与 TLS 证书:

# 数据库密钥
kubectl create secret generic postgres-secret \
  --from-literal=POSTGRES_DB=wifi_densepose \
  --from-literal=POSTGRES_USER=postgres \
  --from-literal=POSTGRES_PASSWORD=your-secure-password

# Redis 密钥
kubectl create secret generic redis-secret \
  --from-literal=REDIS_PASSWORD=your-redis-password

# 应用密钥
kubectl create secret generic wifi-densepose-secrets \
  --from-literal=SECRET_KEY=your-super-secret-key \
  --from-literal=JWT_SECRET=your-jwt-secret \
  --from-literal=DATABASE_URL=postgresql://postgres:password@postgres:5432/wifi_densepose \
  --from-literal=REDIS_URL=redis://:password@redis:6379/0

# TLS 证书
kubectl create secret tls tls-secret \
  --cert=path/to/tls.crt \
  --key=path/to/tls.key

ConfigMaps 用于非敏感配置与初始化文件:

# 应用配置
kubectl create configmap wifi-densepose-config \
  --from-literal=ENVIRONMENT=production \
  --from-literal=LOG_LEVEL=INFO \
  --from-literal=WORKERS=4 \
  --from-literal=ENABLE_AUTHENTICATION=true \
  --from-literal=ENABLE_RATE_LIMITING=true

# Nginx 配置
kubectl create configmap nginx-config \
  --from-file=nginx.conf=./k8s/nginx.conf

# PostgreSQL 初始化 SQL
kubectl create configmap postgres-init \
  --from-file=init.sql=./k8s/init.sql

密钥/配置与运行时强耦合的这一设计,在源码侧同样可见:ConfigManager 提供 set_environment_override()/clear_environment_overrides()(见 src/config.py),把"配置项"抽象成可热替换的环境变量覆盖;SECRET_KEYJWT_SECRETDATABASE_URLREDIS_URL 正是 get_security_config()/get_database_config()/get_redis_config() 的输入来源。因此 K8s Secret 的值可以做到与 Docker 阶段 .env 完全同名互通。

3. 部署持久化卷(PVC)

文档建议为数据、模型、PostgreSQL、Redis 分别申请独立 PVC(存储类 fast-ssd 需按集群实际提供):

# k8s/pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wifi-densepose-data-pvc
  namespace: wifi-densepose
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi
  storageClassName: fast-ssd

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wifi-densepose-models-pvc
  namespace: wifi-densepose
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 50Gi
  storageClassName: fast-ssd

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-data-pvc
  namespace: wifi-densepose
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 200Gi
  storageClassName: fast-ssd

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: redis-data-pvc
  namespace: wifi-densepose
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
  storageClassName: fast-ssd

模型与数据目录分离非常重要:姿态推理模型以只读方式挂给副本(对应 .envPOSE_MODEL_PATH 指向的目录),原始 CSI/日志走独立的数据盘,避免副本重建时丢失任何离线积累。

4. 应用全部 Kubernetes 清单

kubectl apply -f k8s/pvc.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml
kubectl apply -f k8s/ingress.yaml

# 观察部署状态
kubectl get pods -w
kubectl get services
kubectl get ingress

5. 配置 Ingress 与 TLS

# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: wifi-densepose-ingress
  namespace: wifi-densepose
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"
    nginx.ingress.kubernetes.io/rate-limit: "100"
spec:
  tls:
  - hosts:
    - api.wifi-densepose.com
    secretName: wifi-densepose-tls
  rules:
  - host: api.wifi-densepose.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: wifi-densepose-service
            port:
              number: 80

域名 api.wifi-densepose.com 为文档示例值,实际部署必须替换为你自己的域名并保证 DNS 解析指向 Ingress 入口。

云平台部署

AWS 部署

1. EKS 集群

# 安装 eksctl
curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin

# 创建 EKS 集群(节点 1~10 自动伸缩)
eksctl create cluster \
  --name wifi-densepose \
  --region us-west-2 \
  --nodegroup-name workers \
  --node-type m5.xlarge \
  --nodes 3 \
  --nodes-min 1 \
  --nodes-max 10 \
  --managed

2. RDS PostgreSQL

aws rds create-db-instance \
  --db-instance-identifier wifi-densepose-db \
  --db-instance-class db.r5.large \
  --engine postgres \
  --engine-version 15.4 \
  --allocated-storage 100 \
  --storage-type gp2 \
  --storage-encrypted \
  --master-username postgres \
  --master-user-password your-secure-password \
  --vpc-security-group-ids sg-xxxxxxxxx \
  --db-subnet-group-name default \
  --backup-retention-period 7 \
  --multi-az

3. ElastiCache Redis

aws elasticache create-cache-cluster \
  --cache-cluster-id wifi-densepose-redis \
  --cache-node-type cache.r5.large \
  --engine redis \
  --num-cache-nodes 1 \
  --security-group-ids sg-xxxxxxxxx \
  --subnet-group-name default

GCP 部署

1. GKE 集群

gcloud container clusters create wifi-densepose \
  --zone us-central1-a \
  --machine-type n1-standard-4 \
  --num-nodes 3 \
  --enable-autoscaling \
  --min-nodes 1 \
  --max-nodes 10 \
  --enable-autorepair \
  --enable-autoupgrade

2. Cloud SQL for PostgreSQL

gcloud sql instances create wifi-densepose-db \
  --database-version POSTGRES_15 \
  --tier db-n1-standard-2 \
  --region us-central1 \
  --storage-size 100GB \
  --storage-type SSD \
  --backup-start-time 02:00

Azure 部署

1. AKS 集群

az group create --name wifi-densepose-rg --location eastus

az aks create \
  --resource-group wifi-densepose-rg \
  --name wifi-densepose-aks \
  --node-count 3 \
  --node-vm-size Standard_D4s_v3 \
  --enable-addons monitoring \
  --generate-ssh-keys

2. Azure Database for PostgreSQL

az postgres server create \
  --resource-group wifi-densepose-rg \
  --name wifi-densepose-db \
  --location eastus \
  --admin-user postgres \
  --admin-password your-secure-password \
  --sku-name GP_Gen5_2 \
  --storage-size 102400

云端部署的核心收益是让数据库、缓存、证书等有状态组件全部走托管服务(自动备份、多可用区、加密),EKS/GKE/AKS 只承载无状态 API 副本——这样 HPA 缩容、故障重建都不会造成数据丢失。如果你的生产数据需要具备时间序列特性(CSI 流、姿态事件、系统指标),可进一步把 PostgreSQL 升级为 TimescaleDB 的托管形态或自建扩展(见下节)。

生产配置详解

完整生产环境变量文件

文档提供了一份 .env.prod 作为"生产基线清单",覆盖应用、服务、安全、数据库、Redis、硬件、姿态处理、功能开关、监控与性能共十个分组:

# Production environment file
cat > .env.prod << EOF
# Application
APP_NAME=WiFi-DensePose API
VERSION=1.0.0
ENVIRONMENT=production
DEBUG=false

# Server
HOST=0.0.0.0
PORT=8000
WORKERS=4

# Security
SECRET_KEY=${SECRET_KEY}
JWT_SECRET=${JWT_SECRET}
JWT_ALGORITHM=HS256
JWT_EXPIRE_HOURS=24

# Database
DATABASE_URL=${DATABASE_URL}
DATABASE_POOL_SIZE=20
DATABASE_MAX_OVERFLOW=30
DATABASE_POOL_TIMEOUT=30

# Redis
REDIS_URL=${REDIS_URL}
REDIS_POOL_SIZE=10

# Hardware
WIFI_INTERFACE=wlan0
CSI_BUFFER_SIZE=2000
HARDWARE_POLLING_INTERVAL=0.05

# Pose Processing
POSE_CONFIDENCE_THRESHOLD=0.7
POSE_PROCESSING_BATCH_SIZE=64
POSE_MAX_PERSONS=20

# Features
ENABLE_AUTHENTICATION=true
ENABLE_RATE_LIMITING=true
ENABLE_WEBSOCKETS=true
ENABLE_REAL_TIME_PROCESSING=true

# Monitoring
ENABLE_METRICS=true
METRICS_PORT=8080
LOG_LEVEL=INFO

# Performance
ENABLE_GPU=true
MIXED_PRECISION=true
OPTIMIZE_FOR_INFERENCE=true
EOF

对照源码进一步理解其中几组"性能相关"开关的真实含义:

  • ENABLE_METRICS=trueMETRICS_PORT=8080:在 src/app.py 中只有 settings.metrics_enabled 为真时才注册 /api/v1/metrics 端点,Prometheus 抓取目标即 wifi-densepose:8080(与 Compose 阶段端口一致);
  • ENABLE_REAL_TIME_PROCESSING / ENABLE_WEBSOCKETS:进入 get_streaming_config(),决定 WebSocket 连接管理(websocket_ping_intervalwebsocket_timeout)与实时处理链路是否启用;
  • POSE_* 三件套:文档建议的 0.7 / 64 / 20 高于源码默认(0.5 / 32 / 10),说明生产吞吐更大、对误报更敏感时应调高阈值与批大小、放宽人数上限;
  • DATABASE_POOL_SIZE / DATABASE_MAX_OVERFLOW:文档给 20/30,源码默认 10/20,API 多副本时应在数据库侧预留充足并发连接配额。

PostgreSQL / TimescaleDB 调优

对时序型负载,文档建议同时做两件事:一是基础参数调优,二是启用 TimescaleDB 扩展并把核心表转成 hypertable:

-- postgresql.conf optimizations
shared_buffers = 256MB
effective_cache_size = 1GB
maintenance_work_mem = 64MB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1.1
effective_io_concurrency = 200
work_mem = 4MB
min_wal_size = 1GB
max_wal_size = 4GB

-- TimescaleDB extension
CREATE EXTENSION IF NOT EXISTS timescaledb;

-- Create hypertables for time-series data
SELECT create_hypertable('csi_data', 'timestamp');
SELECT create_hypertable('pose_detections', 'timestamp');
SELECT create_hypertable('system_metrics', 'timestamp');

-- Create indexes
CREATE INDEX idx_pose_detections_person_id ON pose_detections (person_id);
CREATE INDEX idx_pose_detections_zone_id ON pose_detections (zone_id);
CREATE INDEX idx_csi_data_router_id ON csi_data (router_id);

其中 csi_data 是逐包 CSI(信道状态信息)样本,pose_detections 是姿态估计事件,system_metrics 是运行指标——三张表都以时间戳为分区键做自动分区,配合 router_id/person_id/zone_id 业务索引,才能支撑高频率写入与按区域、按人检索。

Redis 调优

# redis.conf optimizations
maxmemory 2gb
maxmemory-policy allkeys-lru
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfsync everysec

allkeys-lru 淘汰策略配合 maxmemory 上限,保证缓存/会话在内存压力下不 OOM;appendonly yes + appendfsync everysec 在持久化与写入性能之间取得平衡——这与 Redis 在系统中所承担的角色(速率限制计数、WebSocket 连接状态、短期缓存)匹配。

弹性伸缩与负载均衡

HorizontalPodAutoscaler(HPA)

以 CPU 70% 与内存 80% 两个维度驱动 3~20 副本伸缩,并配置了独立的升缩稳定窗口与速率策略:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: wifi-densepose-hpa
  namespace: wifi-densepose
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: wifi-densepose
  minReplicas: 3
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Percent
        value: 10
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
      - type: Percent
        value: 50
        periodSeconds: 60

伸缩行为的关键点:缩容稳定窗口 300s、每 60s 最多缩 10%;扩容稳定窗口仅 60s、每 60s 最多扩 50%——即"快速响应突增、谨慎回收资源",非常契合姿态推理这类带有瞬时热点负载的在线服务。

VerticalPodAutoscaler(VPA)

若不想手算副本数对应的资源规格,可让 VPA 自动给出每副本的 CPU/内存建议并自动更新(updateMode: Auto):

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: wifi-densepose-vpa
  namespace: wifi-densepose
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: wifi-densepose
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
    - containerName: wifi-densepose
      maxAllowed:
        cpu: 4
        memory: 8Gi
      minAllowed:
        cpu: 500m
        memory: 1Gi

注意 VPA 的 Auto 模式会通过重建 Pod 来应用资源变更,实践中常与 HPA 配合使用(VPA 负责单副本规格、HPA 负责副本数量),且建议先以 Off/Initial 观察建议再开启自动更新。

Nginx 负载均衡配置

入口层采用 least_conn 策略在多副本间分发,并同时提供 SSL 终结、速率限制、gzip 与 WebSocket 升级支持:

upstream wifi_densepose_backend {
    least_conn;
    server wifi-densepose-1:8000 max_fails=3 fail_timeout=30s;
    server wifi-densepose-2:8000 max_fails=3 fail_timeout=30s;
    server wifi-densepose-3:8000 max_fails=3 fail_timeout=30s;
}

server {
    listen 80;
    listen 443 ssl http2;
    server_name api.wifi-densepose.com;

    # SSL configuration
    ssl_certificate /etc/nginx/ssl/tls.crt;
    ssl_certificate_key /etc/nginx/ssl/tls.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req zone=api burst=20 nodelay;

    # Gzip compression
    gzip on;
    gzip_types text/plain application/json application/javascript text/css;

    location / {
        proxy_pass http://wifi_densepose_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }

    location /health {
        access_log off;
        proxy_pass http://wifi_densepose_backend;
    }
}

两份超时与 WebSocket 升级配置和 ENABLE_WEBSOCKETS 的开销是直接相关的:实时姿态流走 WebSocket 长连接,因此 Nginx 必须开启 Upgrade/Connection: upgrade 并把读写超时调到可覆盖一次推理回传的时间尺度,否则长连接会被网关 60s 掐断。

监控与可观测性

Prometheus 抓取配置

# monitoring/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - "wifi_densepose_rules.yml"

scrape_configs:
  - job_name: 'wifi-densepose'
    static_configs:
      - targets: ['wifi-densepose:8080']
    metrics_path: /metrics
    scrape_interval: 10s

  - job_name: 'postgres'
    static_configs:
      - targets: ['postgres-exporter:9187']

  - job_name: 'redis'
    static_configs:
      - targets: ['redis-exporter:9121']

  - job_name: 'nginx'
    static_configs:
      - targets: ['nginx-exporter:9113']

应用自身的抓取目标 wifi-densepose:8080/metrics 正对应 .env.prod 里的 ENABLE_METRICS=trueMETRICS_PORT=8080;PostgreSQL、Redis、Nginx 则各配一个 exporter 从旁采集。仓库根目录的 monitoring/prometheus-config.ymlmonitoring/alerting-rules.yml 是现成的同构配置,可对照查看 scrape job 与告警规则的另一种落地写法。

Grafana 面板

文档给出一个最小可用的 JSON 面板模型,核心是三条 PromQL:

{
  "dashboard": {
    "title": "WiFi-DensePose Monitoring",
    "panels": [
      {
        "title": "Request Rate",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(http_requests_total[5m])",
            "legendFormat": "{{method}} {{status}}"
          }
        ]
      },
      {
        "title": "Response Time",
        "type": "graph",
        "targets": [
          {
            "expr": "histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))",
            "legendFormat": "95th percentile"
          }
        ]
      },
      {
        "title": "Pose Detection Rate",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(pose_detections_total[5m])",
            "legendFormat": "Detections per second"
          }
        ]
      }
    ]
  }
}

三个面板分别回答三个问题:QPS 与错误分布(http_requests_total)、95 分位延迟(http_request_duration_seconds_bucket)、以及业务吞吐——每秒姿态检出数(pose_detections_total)。最后这个"业务指标"是姿态系统特有的,比起纯基础设施指标更能反映服务是否真正在干活。仓库已提供可导入的成品面板 monitoring/grafana-dashboard.json

告警规则

# monitoring/wifi_densepose_rules.yml
groups:
  - name: wifi-densepose
    rules:
      - alert: HighErrorRate
        expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.1
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: High error rate detected
          description: "Error rate is {{ $value }} errors per second"

      - alert: HighResponseTime
        expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 1
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: High response time detected
          description: "95th percentile response time is {{ $value }} seconds"

      - alert: PoseDetectionDown
        expr: rate(pose_detections_total[5m]) == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: Pose detection stopped
          description: "No pose detections in the last 2 minutes"

三条规则(5xx 错误率持续 5 分钟 > 0.1/s、95 分位延迟 > 1s 持续 5 分钟、姿态检出数归零持续 2 分钟)分别对应稳定性、体验、业务存活三个告警维度。其中 PoseDetectionDown 的设计很实用:当 CSI 数据源或推理管线静默停摆时,HTTP 层面可能依然 200,只有业务吞吐归零才会触发 critical。

安全加固

网络策略

通过 NetworkPolicy 把 API Pod 的入站流量收敛到 Ingress 命名空间、出站流量收敛到 PostgreSQL 与 Redis:

# Network policies
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: wifi-densepose-netpol
  namespace: wifi-densepose
spec:
  podSelector:
    matchLabels:
      app: wifi-densepose
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx
    ports:
    - protocol: TCP
      port: 8000
  egress:
  - to:
    - podSelector:
        matchLabels:
          component: postgres
    ports:
    - protocol: TCP
      port: 5432
  - to:
    - podSelector:
        matchLabels:
          component: redis
    ports:
    - protocol: TCP
      port: 6379

Pod 安全上下文

apiVersion: v1
kind: Pod
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 1000
    fsGroup: 1000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: wifi-densepose
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
        - ALL

这一"非 root + 只读根文件系统 + 丢弃全部 capabilities + seccomp RuntimeDefault"的组合与仓库当前运行时容器 docker/docker-compose.yml 中的 security_opt: no-new-privilegescap_drop: ALL 是同一种最小权限哲学。需要注意的是:readOnlyRootFilesystem: true 要求日志、模型、数据目录都通过 emptyDir/PVC 显式挂载(对应 Compose 阶段的三块 volume)。

密钥管理(External Secrets)

把 Secrets 的存储从 etcd 上移到云厂商的密钥服务,实现密钥轮换无需重建 Secret:

# 安装 external secrets operator
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets \
  --namespace external-secrets-system \
  --create-namespace

# AWS Secrets Manager 集成示例
kubectl apply -f - <<EOF
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: aws-secrets-manager
  namespace: wifi-densepose
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-west-2
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets-sa
EOF

在 GCP 侧可把 provider 换成 gcp + Secret Manager,Azure 则换 azure + Key Vault,SecretStore 的资源形态保持一致。结合前文源码中 ConfigManager.set_environment_override() 的能力,运行时仍然以环境变量形态消费这些外部密钥,对应用代码完全透明。

备份与灾难恢复

PostgreSQL 定时备份脚本

#!/bin/bash
# backup-database.sh

BACKUP_DIR="/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="wifi_densepose_backup_${TIMESTAMP}.sql"

# Create backup
pg_dump -h postgres -U postgres -d wifi_densepose > "${BACKUP_DIR}/${BACKUP_FILE}"

# Compress backup
gzip "${BACKUP_DIR}/${BACKUP_FILE}"

# Upload to S3
aws s3 cp "${BACKUP_DIR}/${BACKUP_FILE}.gz" s3://wifi-densepose-backups/

# Clean old backups (keep last 30 days)
find ${BACKUP_DIR} -name "*.gz" -mtime +30 -delete

脚本要点:pg_dump 生成逻辑备份 → gzip 压缩 → aws s3 cp 异地归档 → find -mtime +30 只保留最近 30 天。逻辑备份(SQL)对跨版本恢复最友好;若使用 TimescaleDB hypertable,可额外考虑 timescaledb_backup 工具或持续归档(WAL)作为补充。

集群级灾难恢复(Velero)

Kubernetes 层面的对象与卷快照可用 Velero Schedule 统一管理:

# Velero backup configuration
apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: wifi-densepose-backup
  namespace: velero
spec:
  schedule: "0 2 * * *"
  template:
    includedNamespaces:
    - wifi-densepose
    storageLocation: default
    volumeSnapshotLocations:
    - default
    ttl: 720h0m0s

每天凌晨 2 点对 wifi-densepose 命名空间做一次包含卷快照的备份,保留 720 小时(30 天),与上一脚本的保留窗口一致。RPO 层面注意:仅靠每日全量备份最多丢失 24 小时数据,对 CSI/姿态事件这类时序流,建议同时保留托管库(云 RDS/Cloud SQL 自带的 PITR)或 TimescaleDB 连续归档。

故障排查

常见问题定位命令

1. Pod 启动失败

kubectl get pods -n wifi-densepose
kubectl logs -f deployment/wifi-densepose -n wifi-densepose
kubectl describe pod <pod-name> -n wifi-densepose

2. 数据库连接问题

# 用一次性 Pod 测试连通性
kubectl run -it --rm debug --image=postgres:15-alpine --restart=Never -- \
  psql -h postgres -U postgres -d wifi_densepose

# 查看数据库日志
kubectl logs -f deployment/postgres -n wifi-densepose

3. 性能问题

kubectl top pods -n wifi-densepose
kubectl top nodes
kubectl get hpa -n wifi-densepose
curl http://localhost:8080/metrics

调试命令集

# 端口转发做本地调试
kubectl port-forward service/wifi-densepose-service 8000:80 -n wifi-densepose

# 进入 Pod 执行命令
kubectl exec -it deployment/wifi-densepose -n wifi-densepose -- /bin/bash

# 检查 Service 端点
kubectl get endpoints -n wifi-densepose

# 查看 Ingress 状态与事件
kubectl describe ingress wifi-densepose-ingress -n wifi-densepose

补充两点源码级排查提示(对应 src/main.py 的启动逻辑):

  • 启动日志中若出现 Configuration issues found:,且环境为 production,进程会直接 sys.exit(1)(如 SECRET_KEY 仍是开发默认值、未配置 DATABASE_URL、未配置任何路由器或姿态模型等,都会被 src/config.pyvalidate_configuration() 收集为 issue)。这是"Pod 反复 CrashLoopBackOff"最常见的原因,先看日志再 describe Pod;
  • ENABLE_DATABASE_FAILSAFE / ENABLE_REDIS_FAILSAFE 两个开关(源码默认开启)会在 PostgreSQL/Redis 不可用时自动降级到 SQLite 与禁用缓存,生产环境如不希望"静默降级",应在 ConfigMap 中显式关闭并让依赖故障直接暴露。

扩展阅读

围绕部署与使用,仓库内还有以下可直接衔接的资料(均在 archive/v1 归档范围内,新项目请优先参考 v2/ 与根目录文档):

登录后查看全文
热门项目推荐
相关项目推荐