☰
使用 Helm 将 SparkyFitness 部署到 Kubernetes:Chart 架构、数据库、密钥管理与网络配置实战指南
2026/10/10 2:32:20 网站建设 项目流程
  • 后端
  • 前端
  • 移动开发

【免费下载链接】SparkyFitness

SparkyFitness: Built for Families. Powered by AI. Track food, fitness, water, and health — together.

项目地址:https://gitcode.com/gh_mirrors/sp/SparkyFitness
点击查看免费下载

本文以 helm/README.md 为核心,结合 helm/chart 下的 Chart 源码(values、模板、辅助函数与校验逻辑)展开,系统讲解如何通过社区维护的 Helm Chart 在 Kubernetes 集群上部署 SparkyFitness 全家桶(后端 API、前端、Garmin 微服务与 PostgreSQL),涵盖快速安装、数据库双模式备份、五类 Kubernetes Secret 的三种供给方式、Ingress/HTTPRoute/NetworkPolicy 网络分层以及生产环境安全加固。读完本文,你将能够独立完成一次从helm install到生产级配置调优的完整部署,并理解每个配置项在 Chart 模板中的真实落点。

[!NOTE] 社区维护声明:该 Helm Chart 与 Kubernetes 支持由社区提供,SparkyFitness 维护者目前并不使用 Kubernetes,无法对此安装方式提供完整评审与官方支持。部署前建议在测试集群先行验证。

一、Chart 概览:四个核心组件

Chart 元信息定义在 helm/chart/Chart.yaml:apiVersion: v2,当前版本1.8.0(appVersionv1.8.0),要求 Kubernetes 集群版本>= 1.28.0,并声明了一个命名空间级依赖helmforge/postgresql(版本1.9.5,通过condition: postgresql.enabled控制是否启用)。

整个部署由四个组件构成:

组件镜像默认端口是否可选
Server(后端 API)codewithcj/sparkyfitness_server3010否
Frontend(前端 nginx)codewithcj/sparkyfitness_frontend_nonroot8080(集群内 Service 端口,容器监听 80)否
Garmin(Python 微服务)codewithcj/sparkyfitness_garmin8000是(config.garmin.enabled=true时才部署)
PostgreSQL官方postgres:18.3-trixie,经helmforge/postgresql子 Chart 引入5432是(默认随 Chart 一并部署)

从 values.yaml 中的注释 可以看到各镜像的仓库名细节:Server 为codewithcj/sparkyfitness-server,Frontend 为codewithcj/sparkyfitness-frontend,且tag留空时默认回退到 Chart 的appVersion;若设置了digest,则镜像引用变为<repo>@<digest>形式并优先于 tag(见 _helpers.tpl 的 image helper)。global.imageRegistry默认值为ghcr.io,会被统一拼接到 Server 与 Frontend 镜像前;但要注意该前缀不会作用于 bundled PostgreSQL 子 Chart 与 wait-for-db init 容器——如需把数据库镜像镜像到私有仓库,必须直接设置postgresql.image.repository为完整路径。

Garmin 组件对应仓库中的独立 Python 微服务 SparkyFitnessGarmin/main.py,负责连接 Garmin API 同步运动数据,仅在启用 Garmin 集成时才会渲染 Deployment、Service、PDB 等资源。

二、快速开始:一条命令完成部署

2.1 安装

helm install sparkyfitness ./chart

该命令默认会:

  • 部署 Server、Frontend 与 bundled PostgreSQL(postgresql.enabled默认true);
  • 自动生成各类随机密钥(server.secrets.generate默认true);
  • 使用开箱即用的安全默认值(非 root 运行、丢弃全部 capabilities、seccompProfile: RuntimeDefault等,详见下文"安全上下文")。

安装完成后,NOTES.txt 会打印组件清单、前端 URL、密钥告警(若密钥以明文 Kubernetes Secret 存储)、网络策略未收紧警告以及端口转发指引。

2.2 本地测试:端口转发

Chart 默认开启私有网络 CORS 并信任http://localhost:3004,方便本地联调。在两个独立终端分别执行:

kubectl port-forward svc/sparkyfitness-frontend 3004:80
kubectl port-forward svc/sparkyfitness-server 3010:3010

然后浏览器访问http://localhost:3004。3004是 SparkyFitness 服务端默认的开发端口(在 _helpers.tpl 的 frontendUrl 辅助函数 中也有注释说明:3004 is the SparkyFitness server's default development port)。对应的config.extraTrustedOrigins默认为空,但 Chart 注释中给出了http://localhost:3004的推荐值,用于端口转发场景下放宽 CORS 信任来源。

2.3 运行测试

helm test sparkyfitness

Chart 内置的测试 Pod 定义在 templates/tests/test-connection.yaml,用于验证前端 Service 连通性。若前端已正常响应,测试即通过。

2.4 路由约定

Chart 的 Ingress 与 HTTPRoute 遵循统一的路由拆分规则:/api与/uploads直接打到 Server Service,/打到 Frontend Service;前端 nginx 只负责静态资源与 SPA 路由。不过需要注意一个细节:在 values.yaml 中,ingress.serverPaths默认为空列表——此时单条规则/→ frontend 即可,因为前端镜像内置的 nginx 已经代理了/api/、/uploads/、/health-data、/mcp等路径到 Server。只有当你希望绕过前端 nginx 这一跳、让指定前缀直接打到后端时,才需要显式配置serverPaths(例如["/api", "/uploads", "/mcp"])。这一点与原文档默认"直接分流"的描述相比更贴近 Chart 实际默认行为,两者在显式配置serverPaths后是一致的。

三、数据库:三种部署形态

3.1 Bundled PostgreSQL(默认)

Chart 默认通过命名空间级的helmforge/postgresql依赖拉取官方postgres镜像,使用18.3-trixie标签:

postgresql: enabled: true auth: database: sparkyfitness username: sparky_admin # password: "" # auto-generated if empty image: tag: 18.3-trixie

[!WARNING] 除非在下方显式定义,否则数据库版本由 HelmForge 管理,升级 Chart 时可能意外触发数据库的大版本升级。强烈建议在此处显式固定image.tag。

3.2 双用户模型与首次启动初始化

Chart 应用了 SparkyFitness 的双用户模型:一个数据库 owner(迁移、建表、RLS 策略),一个受限权限的 app 用户(运行时查询)。这在 values.yaml 中有详细注释:

  • sparky_admin(postgresql.auth.username):数据库 owner,负责迁移、schema 管理、RLS 策略应用与跨用户查询;必须拥有CREATEROLE,以便应用在首次启动时创建 app 用户;
  • sparky(server.appDatabase.username,默认sparky):受限权限的运行时用户,由应用首次启动时自动创建,所有常规查询都在 RLS 约束下进行。

该初始化逻辑由 postgresql.initdb.scripts 中的 02-sparky-admin-setup.sh 实现,脚本会在 PostgreSQL 首次初始化时依次执行:

  1. 将数据库 owner 重新指定为sparky_admin(因为 entrypoint 预创建时数据库归 superuser 所有);
  2. 授予CREATEROLE,使应用能够创建sparky角色;
  3. 授予 schema 权限,并向后兼容地安装uuid-ossp、pgcrypto、pg_stat_statements扩展。

[!WARNING] 授予CREATEROLE是为了让应用自动创建受限 app 用户。上游文档建议首次启动后回收该权限,但未来应用更新若新增角色,缺少该权限会导致失败——这是一个需要权衡的安全取舍(详见 Chart 注释中的 "Security Hardening" 提示)。

3.3 定时备份:两种模式二选一

Chart 提供两套互斥的备份方案,同一时刻只能启用其中一种,模板层面通过 _helpers.tpl 的 databaseBackupEnabled 校验 强制约束:

  • postgresql.backup:bundled 依赖自带的S3 兼容备份 CronJob;
  • databaseBackup:Chart 自管的PVC 持久化pg_dumpallCronJob,带日/周/月三级保留策略。
S3 兼容对象存储
postgresql: enabled: true backup: enabled: true schedule: "0 3 * * *" s3: endpoint: "https://minio.example.com" bucket: "sparkyfitness-db" existingSecret: "sparkyfitness-db-backup"

该模式使用 HelmForge 子 Chart 内置的 S3 备份路径,行为与 HelmForge 保持一致,Chart 不做任何覆盖。

PVC 持久化保留备份

Chart 自管的备份 CronJob(模板见 templates/database-backup/cronjob.yaml)将压缩后的pg_dumpall归档写入 PersistentVolumeClaim,并按三个桶执行保留:

  • 每个保留日一个备份;
  • 每个保留周一个备份;
  • 每个保留月一个备份。

例如days: 7, weeks: 5, months: 3表示:最近 7 天每天各保留 1 份、最近 5 周每周各保留 1 份、最近 3 个月每月各保留 1 份。

databaseBackup: enabled: true schedule: "0 4 * * *" persistence: storageClass: ceph-rbd-capacity size: 20Gi retention: days: 7 weeks: 5 months: 3

底层脚本逻辑在 templates/database-backup/configmap.yaml 中,值得关注的实现细节:

  • 备份归档命名sparkyfitness-postgresql-<UTC时间戳>.sql.gz,先写入临时文件再原子mv,避免产生半截损坏的归档;
  • 备份通过pg_dumpall --verbose全量导出,pipefail保证导出失败时任务直接失败,而非静默产出损坏归档;
  • 每日/每周/每月槽位通过硬链接指向归档文件(ln),归档目录中不再被任何槽位引用的文件(-links 1)会被清理,实现"一份数据、多级保留";
  • 保留桶通过build_keep_file计算应保留的日期/周/月列表,再清理不在列表中的旧槽位;
  • PVC 声明带helm.sh/resource-policy: keep注解(见 pvc.yaml),helm uninstall 时 PVC 不会被删除,数据得以保留。

模板层还做了三重校验(_helpers.tpl):databaseBackup启用时要求postgresql.enabled=true(PVC 备份不支持外部数据库);不得与postgresql.backup.enabled同时为真;retention.days/weeks/months至少有一个为正数,否则渲染直接fail。

3.4 外部数据库

关闭 bundled 实例并指向自建数据库:

postgresql: enabled: false externalDatabase: host: "db.example.com" port: 5432 database: "sparkyfitness"

凭据可通过externalDatabase.auth.password、externalDatabase.auth.existingSecret,或 External Secrets Operator 提供。

此时同样适用双用户模型:数据库 owner 需要CREATEROLE,以便应用在首次启动时自动创建受限 app 用户:

ALTER USER <owner> CREATEROLE;

如果不想授予该权限,也可以预先手动创建好 app 用户(server.appDatabase.username,默认sparky)。首次启动成功后可以回收权限:

ALTER USER <owner> NOCREATEROLE;

需要注意:不需要任何 superuser 级别的 PostgreSQL 扩展(Chart 的 initdb 脚本仅安装uuid-ossp、pgcrypto、pg_stat_statements这类常规扩展)。数据库版本方面,Chart 默认使用postgres:18.3-trixie,若使用外部实例请确认版本兼容性。

四、密钥管理:五个 Secret × 三种供给模式

Chart 管理五个相互独立的 Kubernetes Secret:

Secret键使用方
<release>-appapi_encryption_key、better_auth_secretServer
<release>-appdbusername、passwordServer(app DB 用户)
<release>-postgresql-authpostgres-password、user-password、replication-passwordBundled PostgreSQL + Server(DB owner 密码)
<release>-oidcclient_id、client_secretServer(启用 OIDC 时)
<release>-smtpusername、passwordServer(启用邮件时)

每个 Secret 支持三种供给模式:

  1. 自动生成(默认):首次安装时生成随机值,升级时通过 Kubernetes APIlookup保留旧值不轮换;
  2. 已有 Secret:通过各existingSecret字段引用预先创建的 K8s Secret;
  3. External Secrets Operator:从 Vault 等外部提供方拉取。

从模板实现看(server/secret.yaml),自动生成的api_encryption_key与better_auth_secret会先lookup已存在的 Secret 数据,仅在无历史值时生成新随机值(randAlphaNum 64 | sha256sum | b64enc),并在 Secret 上标注argocd.argoproj.io/compare-options: IgnoreExtraneous以配合 GitOps 场景。

4.1 引用已有 Secret

对于 bundled PostgreSQL,postgresql.auth.existingSecret必须提供helmforge/postgresql期望的密码键;owner 用户名仍由postgresql.auth.username指定:

postgresql: auth: existingSecret: "my-bundled-postgres-secret" # keys: postgres-password, user-password, replication-password server: secrets: existingSecret: "my-app-secret" # keys: api_encryption_key, better_auth_secret appDatabase: existingSecret: "my-appdb-secret" # keys: username, password externalDatabase: auth: existingSecret: "my-db-owner-secret" # keys: username, password config: oidc: secrets: existingSecret: "my-oidc-secret" # keys: client_id, client_secret email: secrets: existingSecret: "my-smtp-secret" # keys: username, password

每个existingSecret还支持existingSecretKeys覆盖默认键名(例如server.secrets.existingSecretKeys.apiEncryptionKey默认api_encryption_key),便于适配已有 Secret 的键命名。

4.2 External Secrets Operator(ESO)

Chart 可创建 Vault 后端的SecretStore与按类型区分的ExternalSecret资源(模板见 secrets/secretstore.yaml):

externalSecrets: enabled: true secretStore: name: sparkyfitness vaultPath: sparkyfitness vaultServer: "https://vault.example.com:8200" auth: mountPath: kubernetes role: external-secrets app: enabled: true remoteKey: app_secret smtp: enabled: true remoteKey: smtp

ESO 的认证方式有三种可选(externalSecrets.secretStore.auth.method):

  • kubernetes(默认):Vault Kubernetes 认证,配置mountPath与role;
  • appRole:需要appRole.path(默认approle)、appRole.roleId以及appRole.secretRef(存放 secret id 的 K8s Secret 引用);
  • token:通过tokenSecretRef.name/key引用 Token 所在 Secret。

同时支持secretStore.caConfigMap指定自定义 CA。ESO CRD 的 API 版本由externalSecrets.apiVersion控制:ESO < 0.10.0 用v1beta1,>= 0.10.0 用v1(Chart 默认v1);refreshInterval默认1h,设为0可关闭轮询。

对于数据库凭据,可以改用ClusterSecretStore而非 Chart 托管的SecretStore:

externalSecrets: postgres: enabled: true clusterSecretStore: my-cluster-store remoteKey: db-owner appdb: enabled: true clusterSecretStore: my-cluster-store remoteKey: db-appuser

每个 Secret 的键映射可通过keys列表自定义——将远端存储中的属性名映射为 K8s Secret 内的键名:

externalSecrets: postgres: enabled: true remoteKey: my-db keys: - secretKey: username property: db_user # maps "db_user" in the remote store to "username" in the K8s Secret - secretKey: password property: db_pass

4.3 GitOps 大坑:helm template 下的密钥轮换

自动生成的密钥依赖 Helmlookup在升级时保留旧值。而 ArgoCD 等 GitOps 工具使用helm template(无集群访问,lookup返回 nil),每次渲染都会生成全新的随机值——若将渲染结果直接 apply,会导致密钥轮换,使已有api_encryption_key加密的数据彻底不可恢复(见 server/deployment.yaml 中的详细注释 与 NOTES.txt 的告警文案)。GitOps 场景下应优先使用externalSecrets.*或预置server.secrets.existingSecret。

五、网络:Ingress / HTTPRoute / NetworkPolicy 三层出口

5.1 Ingress

ingress: enabled: true className: nginx hosts: - host: sparkyfitness.example.com paths: - path: / pathType: Prefix tls: - secretName: sparkyfitness-tls hosts: - sparkyfitness.example.com

Ingress 模板(templates/networking/ingress.yaml)会先执行validateRouting校验:ingress.enabled与httpRoute.enabled不能同时为 true,否则渲染直接fail(两套路由把相同路径打到相同后端,会产生重复路由)。启用后的路由规则:

  • /api→server
  • /uploads→server
  • /→frontend

前端 URL 的推导优先级在 _helpers.tpl 中定义为:httpRoute.hostname>ingress.hosts[0](有 TLS 则https://)>config.frontendUrl>http://localhost:3004。

5.2 Gateway API(HTTPRoute)

httpRoute: enabled: true hostname: sparkyfitness.example.com parentRef: name: my-gateway namespace: gateway-system sectionName: https

生成的HTTPRoute(templates/networking/httproute.yaml)与 Ingress 模板共享相同的路径拆分逻辑:/api、/uploads打 Server Service,/打 Frontend Service。同样支持httpRoute.serverPaths显式直连后端前缀。

5.3 Network Policies:最小权限网络拓扑

当networkPolicy.enabled: true时,Chart 生成四组最小权限策略(模板见 templates/networking/networkpolicy.yaml):

  • Frontend:入站默认放行任意来源(可通过frontend.networkPolicy.from收紧到 ingress-controller 命名空间);出站仅允许访问 Server(按sparkyfitness.io/server: "true"标签选择)与 DNS(53/UDP、53/TCP);
  • Server:入站仅接受来自 Frontend 的流量;出站仅允许访问数据库(bundled 按 pod 标签选择端口 5432;外部数据库按externalDatabase.networkPolicy.cidrs / namespaceSelector / podSelector收敛,未配置时回退为按端口放行任意目标并告警),可选地放行到 Garmin 微服务、OIDC 提供方(443)、SMTP 服务器;
  • PostgreSQL:仅接受来自 Server 的流量(同时需自行开启postgresql.networkPolicy.enabled=true以使用 HelmForge 内置策略);
  • Garmin:仅接受来自 Server 的流量,出站可访问外部 Garmin API。

需要特别注意:原生 NetworkPolicy 无法按 FQDN 限制出站,OIDC/SMTP/Garmin 等外部目标要么固定为已知 IP 网段(ipBlock),要么使用支持 FQDN 策略的 CNI(如 Cilium)。此外,NOTES.txt 会在以下情况打印警告:networkPolicy.enabled=true但 frontend 入站未收紧、OIDC/SMTP/Garmin 出站未指定networkPolicy.to、使用外部数据库但未配置任何出站收敛目标。Chart 采用"未配置即回退为宽松放行 + 告警"的兼容策略,生产环境务必逐项补全。

六、功能开关:OIDC / 邮件 / Garmin

6.1 OIDC / SSO

config: oidc: enabled: true providerSlug: authentik providerName: "Authentik" issuerUrl: "https://auth.example.com/application/o/sparkyfitness/" secrets: clientId: "..." clientSecret: "..."

模板层(server/configmap.yaml)在 OIDC 启用时强制要求providerSlug、providerName、issuerUrl三个必填项,并将以下配置注入环境变量:SPARKY_FITNESS_OIDC_AUTH_ENABLED、SPARKY_FITNESS_OIDC_PROVIDER_SLUG/NAME/ISSUER_URL/SCOPE/DOMAIN、AUTO_REGISTER(默认true)、AUTO_REDIRECT(默认false)、LOGO_URL、ADMIN_GROUP,以及高级选项TOKEN_AUTH_METHOD、ID_TOKEN_SIGNED_ALG、USERINFO_SIGNED_ALG、TIMEOUT(留空则走应用默认值)。客户端凭据通过<release>-oidcSecret 注入。同时可配置config.oidc.networkPolicy.to限定到 OIDC 提供方的出站目标。

6.2 邮件通知(SMTP)

config: email: enabled: true host: smtp.example.com port: 587 from: fitness@example.com secrets: username: "..." password: "..."

启用后注入SPARKY_FITNESS_EMAIL_HOST/PORT/SECURE/FROM/USER/PASS(其中secure默认false,对应显式 STARTTLS 的常见 587 端口场景),凭据走<release>-smtpSecret。

6.3 Garmin Connect

config: garmin: enabled: true

启用后 Chart 额外渲染一个独立的 Python 微服务 Deployment(镜像codewithcj/sparkyfitness-garmin,端口 8000),并在 Server 端注入GARMIN_MICROSERVICE_URL(指向<release>-garmin:<port>)与GARMIN_SERVICE_IS_CN(中国区开关config.garmin.isChinaRegion)。该微服务负责连接 Garmin API 拉取运动数据,与仓库中的 SparkyFitnessGarmin 服务对应。

[!NOTE] Garmin 上游镜像内置USER=daemon(UID 1)。部分严格实施 Pod Security Admissionrestricted策略的集群(Kyverno/OPA Gatekeeper)会拒绝 UID < 1000 的 Pod。若遇此情况,可改用更高 UID 的镜像(garmin.image.repository)或为该命名空间放宽策略(values.yaml 注释)。

6.4 登录方式与运行时开关

config段还提供了多个登录相关开关,均直接映射为 Server 环境变量(见 configmap.yaml):

  • forceEmailLogin: true(默认):强制启用邮箱/密码登录,作为 OIDC 锁定时的兜底;
  • disableEmailLogin: false:隐藏登录页的邮箱/密码入口(会被forceEmailLogin覆盖);
  • disablePasskeyLogin/forcePasskeyLogin:passkey 登录的强制关闭/强制开启(后者优先,覆盖前者与管理员开关)。

其他运行时配置包括nodeEnv(默认production)、timezone(默认Etc/UTC)、logLevel(debug/info/warn/error,默认info)、disableSignup、adminEmail(自动管理员邮箱,留空跳过)、allowPrivateNetworkCors(自托管/私有网络场景才需要)以及 API Key 限流rateLimiting.windowMs / maxRequests(留空走应用默认:100 请求/60 秒)。

七、安全上下文:零特权运行基线

每个组件都以与其上游镜像一致的安全上下文运行:

组件UID:GID非 RootCapabilities
Server1000:1000是无(全部丢弃)
Frontend101:101是无(全部丢弃,例外见下)
Garmin1:1是无(全部丢弃)
PostgreSQL999:999是无(全部丢弃)

所有 Pod 均设置seccompProfile: RuntimeDefault与allowPrivilegeEscalation: false。安全上下文可通过<component>.podSecurityContext与<component>.containerSecurityContext完全定制。

几个值得注意的实现细节:

  • Server 容器启用readOnlyRootFilesystem: true,备份、上传、临时上传分别挂载 PVC 或 emptyDir(/app/SparkyFitnessServer/backup、/uploads、/temp_uploads);
  • Frontend 同样只读根文件系统,nginx 可写目录以 emptyDir 挂载;由于上游镜像的 nginx 模板硬编码listen 80;,容器以非 root(101:101)+ cap-drop ALL 运行时要绑定 80 端口,必须通过capabilities.add: [NET_BIND_SERVICE]在 Pod 层补回该能力(文件能力在allowPrivilegeEscalation: false的 NoNewPrivs 下会被剥离,见 values.yaml 注释);
  • 备份 CronJob 默认以 postgres 标准 UID 999 运行,且不建议关闭其readOnlyRootFilesystem。

八、水平扩展:Server 多副本与任务拆分

server.replicas默认 1。当设为大于 1 时,server/deployment.yaml 会自动拆出两个角色:<release>-server(replicas-1个副本)与<release>-jobs(固定 1 副本),二者共享同一模板并都携带sparkyfitness.io/server: "true"标签(Service 与 NetworkPolicy 按此标签选择)。-jobs副本运行定时任务,其余副本设置SPARKY_FITNESS_DISABLE_SCHEDULED_JOBS=true,保证每个定时任务只执行一次。

配套约束(values.yaml):

  • 多副本时备份/上传 PVC 必须使用 ReadWriteMany 存储类,否则Deployment默认的Recreate策略(单副本必选,因为默认 PVC 是 ReadWriteOnce)无法滚动更新;
  • 多副本时可启用podDisruptionBudget(minAvailable/maxUnavailable二选一)。

探针方面,Server 以/api/health做 HTTP 存活/就绪探测(就绪探测每 5 秒一次),Frontend 以/探测,Garmin 使用 TCP socket 探测。

九、ArgoCD 集成:消除无限同步循环

自动生成密钥依赖 Helmlookup跨升级保留值。由于 ArgoCD 使用helm template(lookup返回 nil),每次渲染结果中的 Secret 数据都会被视为"变更",导致每次 diff 都显示改动。解决方案是在 ArgoCD Application 中加入:

spec: ignoreDifferences: - group: "" kind: Secret jsonPointers: - /data

配合 ArgoCD 资源跟踪的RespectIgnoreDifferences=true,可避免无谓的同步循环。同样地,Chart 在自动生成的 Secret 上标注了argocd.argoproj.io/compare-options: IgnoreExtraneous(server/secret.yaml)辅助比对。

十、完整 Values 参考:六个配置区块

完整的带注释参考位于 helm/chart/values.yaml,文件按六个区块组织:

  1. Global—— 镜像仓库前缀(global.imageRegistry,默认ghcr.io)、镜像拉取密钥、全局默认 StorageClass、ServiceAccount 总开关、集群域名;
  2. App Configuration—— 运行时设置、OIDC、邮件、Garmin、API Key 限流;
  3. Networking—— ingress、HTTPRoute、network policies 及各自的serverPaths直连前缀;
  4. Deployments—— 各组件镜像、资源配额、安全上下文、密钥、持久化(Server 备份/上传 PVC、PostgreSQL PVC、Garmin 资源)、扩展手段(affinity、nodeSelector、tolerations、topologySpreadConstraints);
  5. External Secrets—— ESO 集成与按类型(app/appdb/postgres/oidc/smtp)的密钥存储配置;
  6. Extra Objects—— 通过extraObjects附加任意 Kubernetes 清单。

其他常用覆盖项还包括:server.persistence.backup/uploads的容量与 StorageClass(组件级优先于global.storageClass,见 _helpers.tpl 的 storageClass helper)、server.extraEnv/extraEnvFrom/extraVolumes/extraVolumeMounts/initContainers等自定义注入点,以及databaseBackup.archivePrefix(归档文件名前缀,默认sparkyfitness)与pgDumpAllArgs(默认--clean --if-exists)。

十一、生产部署检查清单

综合以上内容,给出从默认安装到生产可用的最小检查清单:

  1. 固定数据库版本:显式设置postgresql.image.tag: 18.3-trixie,避免 Chart 升级连带数据库大版本升级;
  2. 密钥管理:生产环境避免明文 Kubernetes Secret——至少启用externalSecrets.enabled=true或预置各类existingSecret;GitOps(ArgoCD/Flux、离线渲染)务必配置 ArgoCDignoreDifferences或改用 ESO/已有 Secret,防止密钥轮换导致数据不可恢复;
  3. 备份:在postgresql.backup(S3)与databaseBackup(PVC 保留)中二选一启用,确认 PVC StorageClass 支持所需访问模式;
  4. 网络:networkPolicy.enabled=true后逐项补全frontend.networkPolicy.from、OIDC/SMTP/Garmin 的networkPolicy.to、外部数据库的externalDatabase.networkPolicy,注意原生 NetworkPolicy 不能按 FQDN 限流;Ingress 与 HTTPRoute 二选一;
  5. 安全上下文:确认集群 Pod Security 标准与各组件 UID(尤其 Garmin UID 1 在restricted策略下可能被拒);
  6. 水平扩展:Server 多副本时切换备份/上传 PVC 为 ReadWriteMany,并将server.strategy改为RollingUpdate;
  7. 登录兜底:保持forceEmailLogin: true,防止 OIDC 配置问题导致无法登录;
  8. 安装验证:helm test sparkyfitness验证前端连通性,kubectl port-forward本地验证后再暴露公网。
  • 后端
  • 前端
  • 移动开发

【免费下载链接】SparkyFitness

SparkyFitness: Built for Families. Powered by AI. Track food, fitness, water, and health — together.

项目地址:https://gitcode.com/gh_mirrors/sp/SparkyFitness
点击查看免费下载
上一篇:isomorphic-git findRoot API 详解:从任意路径向上查找 Git 仓库根目录
下一篇:LAN Share|局域网发文件,连上WiFi就能用

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询