pvpserver · 实时 PVP 对战游戏服务

pvpserver 是 game 命名空间下的一个对战游戏后端,镜像 ghcr.io/yldm-tech/pvpserver 由 yldm-tech 自建。

从 manifest 可推断它是一个 Go/Gin 编写的 HTTP + WebSocket 服务:容器以 GIN_MODE=release 运行,对外暴露 8080 HTTP 端口、9090 metrics 端口;配置里带有 game 段(tick_rate、send_rate、max_players、匹配与排名开关),并通过 ConfigMap、ExternalSecret 接入 PostgreSQL、Redis 与 Consul。它是 game 类目下的常规无状态服务,由 ApplicationSet yldm-services 生成对应的 ArgoCD Application game-pvpserver,kustomization 设置 namespace: gamenamePrefix: game-,所以集群内资源都带 game- 前缀。

部署形态

  • Name
    命名空间
    Description
    game
  • Name
    工作负载类型
    Description
    Deployment(无状态,RollingUpdate,maxSurge 1 / maxUnavailable 0)
  • Name
    镜像与版本
    Description
    ghcr.io/yldm-tech/pvpserver:2.3.1(tag 由 argocd-image-updater 按 semver 写回 kustomization)
  • Name
    副本数
    Description
    2(HPA 下限 2,上限 8)
  • Name
    调度
    Description
    无 nodeSelector / workload 标签;配置 podAntiAffinity(preferred,topologyKey kubernetes.io/hostname)尽量把两个副本分散到不同节点
  • Name
    端口
    Description
    容器 8080(http)、9090(metrics)
  • Name
    资源
    Description
    requests 512Mi / 500m,limits 1Gi / 1000m
  • Name
    存储
    Description
    无 PVC,无状态服务,仅挂载 ConfigMap

容器声明了完整的三类探针,全部走 8080:startupProbe 命中 /health(最长 60s 启动窗口),livenessProbe 命中 /health,readinessProbe 命中 /health/ready。优雅退出方面,preStop 先 sleep 15terminationGracePeriodSeconds 为 30,配合 RollingUpdate 的 maxUnavailable 0 让滚动更新期间始终有可用副本。镜像拉取用 ghcr-secret(GHCR 私有镜像)。

配置与依赖

服务挂载两个 ConfigMap:集群共享的 base-config(挂到 /root/configs/base)和本服务的 pvpserver-configpvp.yaml 挂到 /root/configs/services/games/pvp.yaml)。pvp.yaml 中绝大多数连接参数用 ${ENV:default} 占位,真实值由容器环境变量注入,环境变量又来自 ExternalSecret 同步出的 Secret,因此敏感信息不落在 git 里。

ExternalSecret pvpserver-secret 通过 ClusterSecretStore vault-backend 从 Vault 拉取,刷新间隔 1h,写出名为 pvpserver-db-secret 的 Secret。它的 remoteRef.key 跨三个 Vault 路径:

Vault 路径取出的字段
yldm/production/pvpserverdb_host、db_port、db_name、db_user、db_password、redis_db
yldm/production/commonredis_host、redis_port、redis_password、jwt_secret、jwt_expires_in、jwt_refresh_expires_in
yldm/databaseDB_ADMIN_USER / DB_ADMIN_PASSWORD(user / password)

依赖的中间件:

  • 数据库走 PostgreSQL,但 DB_HOST 在 deployment 里硬编码为 pgbouncer.postgres.svc.cluster.local,即通过 PgBouncer 连接池接入 postgres 命名空间的 Postgres,业务库默认名 yldm_pvp
  • Redis 用于 pubsub 与缓存,配置里 db: 4、key 前缀 pvp:,pubsub 走 redis 引擎并启用死信队列(保留 168h)。
  • Consul 服务发现已启用(CONSUL_ENABLED=true),地址 consul.consul.svc.cluster.local:8500

关键 env 还包括限流(RATE_LIMIT_GLOBAL=1000 / RATE_LIMIT_BURST=2000)、JSON 结构化日志(LOG_FORMAT=jsonLOG_OUTPUT=stdoutLOG_LEVEL=info)以及 METRICS_ENABLED=true

访问与监控

集群内提供两个 Service:普通 ClusterIP pvpserver(80 → 8080)与 headless pvpserver-headless(clusterIP None,同样 80 → 8080)。

对外通过 Ingress pvpserver-ingress 暴露,ingressClassName: traefik,host 为 pvp.yldm.tech,TLS 证书由 cert-manager 的 letsencrypt-prod ClusterIssuer 签发到 secret pvpserver-tls-cert,并强制 SSL 重定向。DNS 经 external-dns 写成指向 Cloudflare Tunnel(*.cfargotunnel.com)的 CNAME 且开启 Cloudflare proxied。Ingress 上有针对 WebSocket 的一组配置:websocket-services 指向 game-pvpserver,proxy read/send/connect 超时均 3600s,并启用 cookie 会话亲和(pvpserver-session,max-age 10800)以保证 WebSocket 长连在同一后端 Pod 上,入口侧限流 limit-rps: 100

监控方面,Pod 带 prometheus.io/scrape: "true"prometheus.io/port: "9090"prometheus.io/path: "/metrics" 注解暴露指标;本目录下没有 ServiceMonitor 或 PrometheusRule。伸缩与可用性:HPA pvpserver-hpa 按 CPU 70% / 内存 80% 在 2–8 副本间扩缩;VPA pvpserver-vpaupdateMode: "Off"(仅给建议,不自动改资源,区间 cpu 200m–2 / memory 256Mi–2Gi);PDB pvpserverminAvailable: 1,配合至少 2 副本,节点驱逐时不会被单副本 PDB 卡住。

返回 game 服务总览

评论