- 后端
- 前端
- 移动开发
【免费下载链接】SparkyFitness
SparkyFitness: Built for Families. Powered by AI. Track food, fitness, water, and health — together.
本文以 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_server | 3010 | 否 |
| Frontend(前端 nginx) | codewithcj/sparkyfitness_frontend_nonroot | 8080(集群内 Service 端口,容器监听 80) | 否 |
| Garmin(Python 微服务) | codewithcj/sparkyfitness_garmin | 8000 | 是(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:80kubectl 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 sparkyfitnessChart 内置的测试 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 首次初始化时依次执行:
- 将数据库 owner 重新指定为
sparky_admin(因为 entrypoint 预创建时数据库归 superuser 所有); - 授予
CREATEROLE,使应用能够创建sparky角色; - 授予 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>-app | api_encryption_key、better_auth_secret | Server |
<release>-appdb | username、password | Server(app DB 用户) |
<release>-postgresql-auth | postgres-password、user-password、replication-password | Bundled PostgreSQL + Server(DB owner 密码) |
<release>-oidc | client_id、client_secret | Server(启用 OIDC 时) |
<release>-smtp | username、password | Server(启用邮件时) |
每个 Secret 支持三种供给模式:
- 自动生成(默认):首次安装时生成随机值,升级时通过 Kubernetes API
lookup保留旧值不轮换; - 已有 Secret:通过各
existingSecret字段引用预先创建的 K8s Secret; - 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: smtpESO 的认证方式有三种可选(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_pass4.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.comIngress 模板(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 | 非 Root | Capabilities |
|---|---|---|---|
| Server | 1000:1000 | 是 | 无(全部丢弃) |
| Frontend | 101:101 | 是 | 无(全部丢弃,例外见下) |
| Garmin | 1:1 | 是 | 无(全部丢弃) |
| PostgreSQL | 999: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,文件按六个区块组织:
- Global—— 镜像仓库前缀(
global.imageRegistry,默认ghcr.io)、镜像拉取密钥、全局默认 StorageClass、ServiceAccount 总开关、集群域名; - App Configuration—— 运行时设置、OIDC、邮件、Garmin、API Key 限流;
- Networking—— ingress、HTTPRoute、network policies 及各自的
serverPaths直连前缀; - Deployments—— 各组件镜像、资源配额、安全上下文、密钥、持久化(Server 备份/上传 PVC、PostgreSQL PVC、Garmin 资源)、扩展手段(
affinity、nodeSelector、tolerations、topologySpreadConstraints); - External Secrets—— ESO 集成与按类型(app/appdb/postgres/oidc/smtp)的密钥存储配置;
- 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)。
十一、生产部署检查清单
综合以上内容,给出从默认安装到生产可用的最小检查清单:
- 固定数据库版本:显式设置
postgresql.image.tag: 18.3-trixie,避免 Chart 升级连带数据库大版本升级; - 密钥管理:生产环境避免明文 Kubernetes Secret——至少启用
externalSecrets.enabled=true或预置各类existingSecret;GitOps(ArgoCD/Flux、离线渲染)务必配置 ArgoCDignoreDifferences或改用 ESO/已有 Secret,防止密钥轮换导致数据不可恢复; - 备份:在
postgresql.backup(S3)与databaseBackup(PVC 保留)中二选一启用,确认 PVC StorageClass 支持所需访问模式; - 网络:
networkPolicy.enabled=true后逐项补全frontend.networkPolicy.from、OIDC/SMTP/Garmin 的networkPolicy.to、外部数据库的externalDatabase.networkPolicy,注意原生 NetworkPolicy 不能按 FQDN 限流;Ingress 与 HTTPRoute 二选一; - 安全上下文:确认集群 Pod Security 标准与各组件 UID(尤其 Garmin UID 1 在
restricted策略下可能被拒); - 水平扩展:Server 多副本时切换备份/上传 PVC 为 ReadWriteMany,并将
server.strategy改为RollingUpdate; - 登录兜底:保持
forceEmailLogin: true,防止 OIDC 配置问题导致无法登录; - 安装验证:
helm test sparkyfitness验证前端连通性,kubectl port-forward本地验证后再暴露公网。
- 后端
- 前端
- 移动开发
【免费下载链接】SparkyFitness
SparkyFitness: Built for Families. Powered by AI. Track food, fitness, water, and health — together.
相关推荐
使用 Helm 在 Kubernetes 上部署 Buildkite Agent:Chart 配置、密钥管理与 Pipeline 实战
使用 Helm 在 Kubernetes 上部署 Buildkite Agent:Chart 配置、密钥管理与 Pipeline 实战 导读 Buildkite
使用 Helm Chart 部署 vaultingkube:将 Hashicorp Vault 的密钥与配置同步到 Kubernetes
使用 Helm Chart 部署 vaultingkube:将 Hashicorp Vault 的密钥与配置同步到 Kubernetes 本文基于 incuba
使用 Helm 部署 Kanister Operator:Kubernetes 应用级数据管理框架实战指南
使用 Helm 部署 Kanister Operator:Kubernetes 应用级数据管理框架实战指南 导读 Kanister 是一套运行在 Kuberne
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考