Next.js 應用程式的 Helm Chart
用於 charts/<app>/ 以及 Argo CD 如何使用它。Chart 所運行的映像來自 docker-nextjs;同時發佈這兩者的管道是 github-actions。
模板中的 charts/__APP__/ 是源頭。所有含註解的 values 請見:references/values.md。Argo CD 的接線方式請見:references/argocd.md。
規則
-
每個應用程式一個 Chart,位於應用程式儲存庫根目錄的
charts/<app>/。 為何放在那裡:Argo CD 可以直接從 git 同步(path: charts/<app>)用於開發環境,並從 OCI 註冊表用於生產環境,使用相同的檔案;它位於apps/之外,因此既不在 Docker 建置環境中,也不在 pnpm 工作區套件內;而且 Chart 的變更與需要它的程式碼在同一個 PR 中。Chart 是專為單一應用程式設計的:沒有總 chart,沒有子 chart。僅在單一應用程式需要切換時,才使用通用、由 values 驅動的模板(如後端總 chart):ingress、HPA、PDB、拓撲分佈。 -
切勿手動編輯
version或appVersion。 兩者在 git 中都保持0.0.0。release.yaml從標籤vX.Y.Z執行helm package --version X.Y.Z --app-version vX.Y.Z,因此發佈的 Chart 和映像標籤始終匹配。 -
image.tag預設為appVersion;僅在 git 同步的環境中設定它。 從 OCI 同步時,appVersion就是發佈標籤,映像為ghcr.io/nuvraxis/<app>:vX.Y.Z。從 git 同步時,appVersion為0.0.0,因此 Argo CD Application 會設定image.tag: sha-<short-sha>(或main)。image.repository始終為小寫。 -
探針:startup、liveness 和 readiness,全部指向
/api/health。 startup 探針(2 秒 × 30 次)涵蓋啟動過程;liveness 和 readiness 僅在它之後才開始。該路由永不觸及任何依賴項,因此資料庫中斷不會重新啟動 Pod。不要將探針指向/:它會渲染一個頁面。 -
安全上下文與映像匹配:uid/gid 1001、
runAsNonRoot、readOnlyRootFilesystem、無權限提升、捨棄所有能力、RuntimeDefaultseccomp。automountServiceAccountToken: false同時設定在 ServiceAccount 和 Pod 上:應用程式不會呼叫 Kubernetes API。 -
.next/cache是一個帶有sizeLimit的emptyDir。 它是唯一可寫入的路徑(/app/apps/<app>/.next/cache)。限制可以防止失控的映像快取填滿節點。 -
透過
envFrom進行配置:一個來自values.config的 ConfigMap,以及一個已存在的 Secret。config: API_BASE_URL: https://api.nuvraxis.com existingSecret: portal-secretsChart 永遠不會模板化 Secret 值:沒有包含從 values 取得
data的kind: Secret,沒有--set secret=…。Secret 是由 External Secrets、Sealed Secrets 或運算子建立的,只有其名稱存在於 values 中。ConfigMap 的變更會透過checksum/config註解滾動 Pod。 -
Chart 中沒有
NEXT_PUBLIC_*。 它們在建置映像時就已嵌入(請參閱docker-nextjs);在執行時期設定它們不會有任何作用。 -
資源:請求 CPU 和記憶體、記憶體限制、無 CPU 限制。 CPU 限制會在流量高峰時限制 Node 伺服器並增加尾端延遲;記憶體限制則保留,因為 Node 的堆積會增長到分配的大小為止。
-
預設高可用性:2 個副本、PDB
maxUnavailable: 1、滾動更新策略maxUnavailable: 0、跨可用區和節點的拓撲分佈(ScheduleAnyway)。 啟用autoscaling.enabled時,Deployment 會省略replicas,這樣 Argo CD 和 HPA 就不會爭奪它。 -
Ingress 為選擇性啟用,TLS 透過 cert-manager 註解處理。
ingress.enabled、className、hosts、帶有secretName的tls,以及註解中的cert-manager.io/cluster-issuer。對於 ingress-nginx 上的串流回應,請加上nginx.ingress.kubernetes.io/proxy-buffering: "off";對於速率限制,請加上limit-rps(請參閱nextjs-security)。 -
沒有 Helm hooks、沒有
lookup、沒有隨機值。 Argo CD 使用helm template渲染 Chart 並套用結果:hooks 會變成語義不同的 Argo hooks,lookup會回傳空值,而randAlphaNum會在每次同步時變化,導致應用程式永遠顯示為不同步。所有渲染的內容必須是 values 的純函數。 -
私有 GHCR 套件需要拉取憑證。 GHCR 套件在首次發佈時是私有的。對於映像:一個帶有
read:packages權杖的docker-registrySecret,在imagePullSecrets中引用(生產環境 values 會引用ghcr-pull)。對於 Argo CD 中的 Chart:一個帶有enableOCI: "true"的儲存庫 Secret(請參閱references/argocd.md)。或者,如果程式碼是公開的,也可以在 GitHub 中將套件設為公開。 -
values-production.yaml僅包含生產環境中不同的部分。 疊加使用:-f values.yaml -f values-production.yaml。不要將預設值複製到其中。 -
使用
helm lint --strict和helm template | kubeconform -strict進行驗證。 為什麼選擇 kubeconform 而非 helm-unittest:單一應用程式 Chart 實際會遇到的錯誤是渲染輸出中的錯誤欄位名稱、類型或 API 版本,kubeconform 可以針對真實的 Kubernetes 架構在零測試程式碼的情況下捕捉到這些錯誤。helm-unittest 斷言的是模板邏輯,而這個 Chart 幾乎沒有。如同pr.yaml所做的那樣,對兩個 values 檔案都進行 lint 和驗證。
新增項目
| 需求 | 變更方式 |
|---|---|
| 一個執行時期環境變數 | values 中的 config:(非機密)或現有 Secret 中的一個金鑰 |
| 一個 Secret | 將其新增到外部的 Secret;Chart 中不需任何變更 |
| 另一個埠或 sidecar | 先證明其必要性;一個 Next 應用程式只需要一個埠 |
| 一個 CronJob | 一個單獨的 Chart 或應用程式,不是這個 Deployment |
| NetworkPolicy | 新增 templates/networkpolicy.yaml,由 networkPolicy.enabled 切換 |
驗證
helm lint --strict charts/<app>
helm lint --strict charts/<app> -f charts/<app>/values-production.yaml
helm template <app> charts/<app> -f charts/<app>/values-production.yaml \
| docker run --rm -i ghcr.io/yannh/kubeconform:v0.8.0 -strict -summary -kubernetes-version 1.34.0 -
參考來源
- https://helm.sh/docs/topics/charts/
- https://helm.sh/docs/chart_best_practices/
- https://helm.sh/docs/topics/registries/
- https://helm.sh/docs/overview/
- https://github.com/yannh/kubeconform
- https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
- https://kubernetes.io/docs/concepts/security/pod-security-standards/
- https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/
- https://kubernetes.io/docs/concepts/workloads/pods/disruptions/
- https://argo-cd.readthedocs.io/en/stable/user-guide/helm/
- https://cert-manager.io/docs/usage/ingress/
- https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry