使用 Helm Chart 在 Kubernetes 上部署 Tandoor Recipes:values 配置、Secret 管理与流量接入实战
【免费下载链接】recipesApplication for managing recipes, planning meals, building shopping lists and much much more!项目地址: https://gitcode.com/GitHub_Trending/re/recipes
Tandoor Recipes(即本仓库的recipes应用)是一款用于管理菜谱、规划膳食、生成购物清单的开源食谱管理应用。本文将基于仓库中社区贡献的 docs/install/helmChart.md 指南,完整讲解如何通过第三方 Helm Chart(csg33k/helm-charts中的tandoorchart)在已有 PostgreSQL 的 Kubernetes 集群上快速部署 Tandoor Recipes,包括values.yaml的每一项核心配置、环境变量与启动脚本的对应关系、Secret 的安全注入方式,以及用 Gateway API 的HTTPRoute完成流量接入的完整流程。读完本文,你将获得一份可直接复制落地、并理解其底层原理的 Helm 部署方案。
指南性质与适用前提
该指南由社区贡献,既非官方支持,也不会被官方持续更新或测试。使用时请结合 docs/install/helmChart.md 和 chart 发布方的最新
values.yaml核对版本差异。
在开始之前,需要明确两个前提假设:
- 你已有一个可访问的 PostgreSQL 数据库。本 chart 的初始版本不负责创建数据库,只负责部署应用本身,数据库连接参数全部通过环境变量注入。
- chart 初始版本不内置 LoadBalancer。应用流量需要你自己通过 Ingress 清单或 Gateway API 的
HTTPRoute指向 chart 创建出的 Service。
另外需要特别注意 Tandoor 2 的兼容性变化:根据 docs/install/kubernetes.md 的警告,Tandoor 2 已将 nginx 服务集成进默认 Docker 容器,并把服务端口从 8080 改为 80。本仓库的 Dockerfile 中EXPOSE 80 8080与 boot.sh 中的 nginx 启动逻辑印证了这一演进,因此在配置路由或 Ingress 时,请以你所使用镜像版本实际暴露的端口为准。
核心配置:values.yaml 逐项解析
社区指南给出了一个"基础最小化可运行"的示例values.yaml,本节逐段拆解,并结合仓库源码解释每个参数的实际作用。
命名空间与资源名称覆盖
namespaceOverride: food fullnameOverride: "recipes"namespaceOverride: food:强制 chart 内所有资源(包括下方extraResources中定义的 Secret)都部署在food命名空间。后续的helm install、HTTPRoute都基于该命名空间编写。fullnameOverride: "recipes":覆盖 chart 自动生成的应用资源名称前缀,最终应用 Service 名为recipes,这也是后面HTTPRoute中backendRefs.name必须对齐的值。
指南注明这两项"并非必需",只是为了保证与作者环境的命名一致,使路由示例开箱可用。如果你的环境命名不同,请同步修改
HTTPRoute中的 backend 名称。
global 段:镜像与版本
# Change to latest version if out of date. #global: # create_namespace: false # image: vabene1111/recipes # tandoor_version: 2.3global段整体被注释掉,表示全部采用 chart 内置默认值:
create_namespace:是否由 chart 自动创建命名空间,默认为关闭(false),需提前手动建好food命名空间,或由helm install -n food在目标集群策略允许时创建。image/tandoor_version:镜像仓库地址与 Tandoor 版本标签。当前仓库主镜像为vabene1111/recipes,解注释后按需调整版本(例如2.3)。建议显式锁定版本号以提升稳定性、避免意外迁移,这一点与 docs/install/k8s/50-deployment.yaml 中"建议显式指定 tag"的建议一致。
env 段:应用环境变量
env: ## Values below will get you to a basic working installation - name: DB_ENGINE value: django.db.backends.postgresql - name: POSTGRES_HOST value: shared-rw.postgres-operator.svc.cluster.local - name: POSTGRES_PORT value: "5432" - name: POSTGRES_DB value: fooddb - name: SECRET_KEY valueFrom: secretKeyRef: name: recipes-secrets key: secret-key - name: POSTGRES_USER valueFrom: secretKeyRef: name: recipes-secrets key: username - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: recipes-secrets key: password ## I skipped email support but feel free to add it as well.这些环境变量会被注入应用容器,其消费逻辑可以直接在仓库启动脚本 boot.sh 中找到:
DB_ENGINE:固定为 Django 的 PostgreSQL 后端django.db.backends.postgresql。boot.sh依据该值(或DATABASE_URL以postgres开头)判断是否进入"等待数据库就绪"与POSTGRES_PASSWORD校验分支。POSTGRES_HOST/POSTGRES_PORT/POSTGRES_DB:数据库地址、端口与库名。boot.sh会用pg_isready --host=${POSTGRES_HOST} --port=${POSTGRES_PORT} --user=${POSTGRES_USER}轮询等待数据库可用,最多尝试 20 次、每次间隔 5 秒;超时会打印诊断信息并以非零码退出容器。SECRET_KEY/POSTGRES_USER/POSTGRES_PASSWORD:推荐通过secretKeyRef从 Kubernetes Secret 中引用,避免明文写在values.yaml中。boot.sh会校验SECRET_KEY与POSTGRES_PASSWORD是否为空,缺失时打印[WARNING]并继续启动(但后续应用将无法正常工作),因此务必正确注入。
补充说明:
boot.sh还支持*_FILE形式的变量(如SECRET_KEY_FILE、POSTGRES_PASSWORD_FILE),容器启动时会自动读取文件内容填充对应变量。若你的 Secret 以文件卷形式挂载,同样适用。
persistence 段:数据持久化
persistence: enabled: true volumes: - name: staticfiles mountPath: /opt/recipes/staticfiles size: 1Gi - name: mediafiles mountPath: /opt/recipes/mediafiles size: 1Gienabled: true:启用持久化声明(PVC)。- 两个卷分别挂载到容器内的
/opt/recipes/staticfiles(Django 静态文件)与/opt/recipes/mediafiles(用户上传的图片等媒体文件)。这两个路径与 boot.sh 中的默认值MEDIA_ROOT=/opt/recipes/mediafiles、STATIC_ROOT=/opt/recipes/staticfiles完全对应。
指南特别强调:虽然持久化"并非严格必需",但强烈建议创建,否则每次 Pod 重启都会丢失已收集的静态文件与用户上传的媒体文件。boot.sh在启动时执行python manage.py collectstatic --noinput --clear重新收集静态文件,媒体文件则不可再生,必须落盘保存。
extraResources 段:一次性注入 Secret
## In Production, use a different way of getting the secrets in. unless this code never leaves your server. ## In a "Prod" like homelab you should use ESO or Sealed Secrets, etc populate these values. extraResources: - apiVersion: v1 kind: Secret metadata: name: recipes-secrets namespace: food type: Opaque stringData: password: superSecretDBPass secret-key: ## output of openssl rand -base64 32 | tr -d '/+=' | head -c 32 username: db_usernameextraResources允许在安装 chart 的同时附带创建额外 Kubernetes 资源。这里用它直接声明了env段引用的recipes-secretsSecret(Opaque 类型,包含password、secret-key、username三个键):
secret-key生成方式:openssl rand -base64 32 | tr -d '/+=' | head -c 32,即取 32 字节随机数并裁剪为 32 字符的 Django SECRET_KEY。- 安全提醒(原指南原文语义):直接把 Secret 写进
values.yaml仅适用于"这份代码不会离开你的服务器"的场景;在类生产环境(如 Homelab 生产)应改用External Secrets Operator(ESO)或Sealed Secrets等方案来注入这些值,不要把明文密钥提交到代码仓库。
安装 Chart
配置好values.yaml(文件名可自定义,如myvalues.yaml)后,执行:
helm install recipe-manager -n food oci://ghcr.io/csg33k/helm-charts/tandoor --version 0.0.1 -f myvalues.yaml参数含义:
| 参数 | 说明 |
|---|---|
recipe-manager | 本次 Helm Release 的名称 |
-n food | 安装到food命名空间(与namespaceOverride保持一致) |
oci://ghcr.io/csg33k/helm-charts/tandoor | 以 OCI 方式拉取 chart,无需手动添加 repo |
--version 0.0.1 | 指定 chart 版本,官方提示"若过期请更新到最新版本" |
-f myvalues.yaml | 覆盖默认值的自定义配置文件 |
流量接入:HTTPRoute 示例
Chart 本身不创建 LoadBalancer,安装完成后应用 Service(名为recipes,端口 80)已就绪,剩下就是如何把外部流量引进来。指南给出了基于Gateway API的HTTPRoute示例:
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: food-https namespace: food spec: parentRefs: - name: http-gateway ## Change this namespace: default ## Change this sectionName: https hostnames: - food.domain.tld ## Change this rules: - backendRefs: - name: recipes ## If the name is different for your env, update it accordingly. port: 80需要修改的占位项:
parentRefs.name/parentRefs.namespace:指向你集群中已部署的 Gateway 资源(示例假定它名为http-gateway、位于default命名空间)。parentRefs.sectionName:Gateway 监听器名称,示例为https。hostnames:替换为你的真实域名,如food.domain.tld。backendRefs.name:必须与fullnameOverride生成的 Service 名一致(此处为recipes),端口 80。
如果你使用的是传统 Ingress 控制器而非 Gateway API,也可以参考仓库自带的 docs/install/k8s/70-ingress.yaml:它展示了将/media、/static路径路由到 nginx 容器(端口 80)、其余流量路由到 gunicorn(端口 8080)的路径拆分写法,并预留了 cert-manager 的 TLS 注释模板(默认注释状态)。
与 Manifest 部署方式的对照参考
除了 Helm Chart,本仓库还维护了一套可直接kubectl apply的清单文件,位于 docs/install/k8s/,对应指南为 docs/install/kubernetes.md。两套方案的架构思路高度一致,可互为印证:
| 关注点 | Helm Chart(本文) | Manifest 方式 |
|---|---|---|
| 数据库 | 复用外部 PostgreSQL | 40-sts-postgresql.yaml 自带 Bitnami PostgreSQL StatefulSet(数据卷 2Gi、runAsUser: 1001低权限运行,init 容器以 root 准备目录) |
| 静态/媒体文件 | persistence声明两个 1Gi 卷 | 30-pvc.yaml 声明recipes-media、recipes-static两个 1Gi PVC |
| 初始化流程 | chart 内置逻辑 | 50-deployment.yaml 的init-chmod-datainit 容器执行migrate、collectstatic并修正媒体目录属主,与 boot.sh 的启动流程对应 |
| Secret | extraResources注入 | 15-secrets.yaml 预置明文(必须替换),或用kubectl create secret generic recipes --from-file=...生成 |
| 流量入口 | HTTPRoute(Gateway API) | 70-ingress.yaml(recipes.local占位域名,需修改) |
Manifest 方式还给出了一些 Helm 指南未展开的运维细节,可作为补充参考:应用主容器recipes以runAsUser: 65534(nobody)低权限运行,gunicorn 绑定:8080,配置了 liveness/readiness 探针;nginx 容器通过 ConfigMap 10-configmap.yaml 提供/static/、/media/的静态文件服务。如果你需要按需微调探针、资源配额或安全上下文,直接阅读并修改这些清单会比改写 chart 更直观。
安装后的检查要点
- 数据库连通性:
boot.sh会在启动时轮询pg_isready,失败 20 次后容器会打印Database not reachable. Maximum attempts exceeded.并退出,此时优先核对POSTGRES_HOST/POSTGRES_PORT/POSTGRES_USER是否正确。 - 静态文件:容器启动时执行
collectstatic --noinput --clear,首次启动耗时较长属正常现象;若通过 nginx 独立服务静态文件,需确认挂载的staticfiles卷内容完整。 - Secret 一致性:
env段与extraResources中的 Secret 键名必须一一对应(secret-key、username、password),拼写不一致会导致应用启动时读取不到凭据。 - 版本锁定:建议像 docs/install/k8s/50-deployment.yaml 强调的那样显式固定镜像 tag,避免
latest在升级时触发不必要的数据库迁移。
完成以上步骤后,你的 Tandoor Recipes 就已通过 Helm Chart 运行在 Kubernetes 集群中,外部流量经由HTTPRoute到达recipesService。Happy cooking!
【免费下载链接】recipesApplication for managing recipes, planning meals, building shopping lists and much much more!项目地址: https://gitcode.com/GitHub_Trending/re/recipes
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考