cardserver · 卡牌游戏服务端

cardserver 是 game 命名空间下的卡牌(card)游戏服务端,镜像构建自 ghcr.io/yldm-tech/cardserver。它以 Gin(GIN_MODE=release)对外提供 HTTP 与 WebSocket 服务,依赖 PostgreSQL 持久化、Redis 做缓存与 PubSub,并向 Consul 注册自身以供服务发现。配置里声明了 tick_rate: 30 / send_rate: 10 / max_players: 100 等游戏循环参数,属于一个有状态游戏逻辑但无本地持久卷的无状态副本部署。

部署形态

  • Name
    命名空间
    Description
    game(kustomization 设置 namespace: game + namePrefix: game-,生成资源名 game-cardserver-*
  • Name
    工作负载
    Description
    Deployment,RollingUpdatemaxSurge: 1 / maxUnavailable: 0
  • Name
    镜像
    Description
    ghcr.io/yldm-tech/cardserver:2.3.1(tag 由 argocd-image-updater 按 semver 写回 kustomization images:),imagePullPolicy: Always,拉取用 ghcr-secret
  • Name
    副本数
    Description
    2(与 HPA minReplicas 一致)
  • Name
    端口
    Description
    容器 http 8080、metrics 9090
  • Name
    资源
    Description
    requests 250m CPU / 256Mi,limits 500m CPU / 512Mi
  • Name
    调度
    Description
    未设 nodeSelector / workload 标签;podAntiAffinitypreferred(weight 100,topologyKey: kubernetes.io/hostname)尽量把两个副本分散到不同节点
  • Name
    探针
    Description
    startupProbe /health(最多 12×5s),livenessProbe /health(15s 周期),readinessProbe /health/ready(5s 周期)
  • Name
    优雅退出
    Description
    preStopsleep 15terminationGracePeriodSeconds: 30
  • Name
    存储
    Description
    无 PVC;只挂载两个 ConfigMap(base-config 挂到 /root/configs/basecardserver-configcard.yaml 挂到 /root/configs/services/games/card.yaml),均 readOnly

配置与依赖

游戏配置来自 ConfigMap cardserver-configcard.yaml,关键项:game.tick_rate: 30send_rate: 10max_players: 100world_width/height: 2000;数据库 driver 为 postgres、库名默认 yldm_cardmax_open_conns: 25、迁移目录 migrations/card;Redis db: 4、key 前缀 card:;PubSub 用 Redis 引擎(前缀 card:pubsub:,开启 dead_letter,保留 168h)。card.yaml 内用 ${VAR:default} 占位,实际值由下面的环境变量注入。

数据库连向 pgbouncer.postgres.svc.cluster.localDB_HOST 在 deployment 中硬编码为该地址),即经 PgBouncer 连接池访问 PostgreSQL。服务注册指向 consul.consul.svc.cluster.local:8500CONSUL_ENABLED=true),以 service_name cardserver、tags game/card/v1 注册并暴露 /health 健康检查。限流相关 env:RATE_LIMIT_GLOBAL=1000RATE_LIMIT_BURST=2000

敏感配置由 ExternalSecret cardserver-db-secret(ClusterSecretStore vault-backendrefreshInterval: 1h)从 Vault 拉取,合成同名 Secret 后注入容器:

Secret keyVault remoteRef.keyproperty
DB_PORT / DB_NAME / DB_USER / DB_PASSWORD / REDIS_DByldm/production/cardserverdb_port / db_name / db_user / db_password / redis_db
REDIS_HOST / REDIS_PORT / REDIS_PASSWORDyldm/production/commonredis_host / redis_port / redis_password
JWT_SECRET / JWT_EXPIRES_IN / JWT_REFRESH_EXPIRES_INyldm/production/commonjwt_secret / jwt_expires_in / jwt_refresh_expires_in
DB_ADMIN_USER / DB_ADMIN_PASSWORDyldm/databaseuser / password

注意 DB_HOST 不来自 Vault,而是 deployment 里直接写死的 PgBouncer 地址;JWT 与 Redis 凭据走共享路径 yldm/production/common,DB 管理员账号走共享路径 yldm/database

访问与监控

集群内通过 Service cardserver(ClusterIP,port 80 → targetPort 8080)访问;另有一个 headless Service cardserver-headlessclusterIP: None),其 manifest 中 namespace 写的是 app(与主 Service 的 game 不同,且 kustomization 会统一覆盖为 game,最终名 game-cardserver-headless)。

外部入口为 Ingress cardserver-ingress,host card.yldm.techingressClassName: traefik,后端指向 game-cardserver:80。TLS 证书由 cert-manager letsencrypt-prod ClusterIssuer 签发到 cardserver-tls-cert。DNS 经 external-dns 写一条 CNAME 指向 Cloudflare Tunnel(*.cfargotunnel.com,proxied)。为支持 WebSocket,Ingress 标注了 websocket-services: game-cardserver、读写/连接超时各 3600s,并启用 cookie 粘性会话(cardserver-session,max-age 10800s);另有 proxy-body-size: 10mlimit-rps: 100。注意这些 nginx.ingress.kubernetes.io/* 注解为 nginx ingress 语义,而 ingressClassName 是 traefik —— 部分注解在 traefik 下未必生效,以集群实际 ingress controller 行为为准。

监控方面,Pod 带 prometheus.io/scrape: "true"prometheus.io/port: "9090"prometheus.io/path: "/metrics" 注解(annotation 抓取),METRICS_ENABLED=true。本目录下没有 ServiceMonitor 或 PrometheusRule。弹性与可用性:HPA cardserver-hpa 按 CPU 70% / 内存 80% 在 minReplicas: 2 ~ maxReplicas: 8 间伸缩;VPA cardserver-vpaupdateMode: "Off"(仅给建议,区间 100m1 CPU、128Mi1Gi);PDB cardserverminAvailable: 1

返回 game 总览

评论