From 9222c8e973da4df17e83f4569d3f57a59b0ef34ffae6cf70b641ea7e155aa767 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 26 Apr 2026 22:52:53 -0400 Subject: [PATCH] feat(helm): chart skeleton (Chart.yaml, values, helpers) Initial scaffold for the ezscale-website chart. Defaults assume self-contained local dev (in-cluster MariaDB + Valkey). Production overrides will live in values-us-prod.yaml. Co-Authored-By: Claude Opus 4.7 (1M context) --- helm/ezscale-website/.helmignore | 9 ++ helm/ezscale-website/Chart.yaml | 9 ++ helm/ezscale-website/templates/_helpers.tpl | 63 ++++++++ helm/ezscale-website/values.yaml | 160 ++++++++++++++++++++ 4 files changed, 241 insertions(+) create mode 100644 helm/ezscale-website/.helmignore create mode 100644 helm/ezscale-website/Chart.yaml create mode 100644 helm/ezscale-website/templates/_helpers.tpl create mode 100644 helm/ezscale-website/values.yaml diff --git a/helm/ezscale-website/.helmignore b/helm/ezscale-website/.helmignore new file mode 100644 index 0000000..5c15002 --- /dev/null +++ b/helm/ezscale-website/.helmignore @@ -0,0 +1,9 @@ +.DS_Store +.git/ +.gitignore +*.tmproj +.vscode/ +*.swp +*.tmp +*.bak +README.md.bak diff --git a/helm/ezscale-website/Chart.yaml b/helm/ezscale-website/Chart.yaml new file mode 100644 index 0000000..37eb26a --- /dev/null +++ b/helm/ezscale-website/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +name: ezscale-website +description: EZSCALE billing platform — Laravel app (web + horizon + scheduler) +type: application +version: 0.1.0 +appVersion: "0.1.0" +maintainers: + - name: EZSCALE + email: dev@ezscale.cloud diff --git a/helm/ezscale-website/templates/_helpers.tpl b/helm/ezscale-website/templates/_helpers.tpl new file mode 100644 index 0000000..d0f3a30 --- /dev/null +++ b/helm/ezscale-website/templates/_helpers.tpl @@ -0,0 +1,63 @@ +{{/* Common name helpers */}} +{{- define "ezscale-website.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define "ezscale-website.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{- define "ezscale-website.labels" -}} +app.kubernetes.io/name: {{ include "ezscale-website.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" }} +{{- end -}} + +{{- define "ezscale-website.selectorLabels" -}} +app.kubernetes.io/name: {{ include "ezscale-website.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{/* +Image reference for a given role (app/horizon/scheduler). +Usage: {{ include "ezscale-website.image" (dict "ctx" . "role" "app") }} +*/}} +{{- define "ezscale-website.image" -}} +{{- $ctx := .ctx -}} +{{- printf "%s/%s:%s-%s" $ctx.Values.image.registry $ctx.Values.image.repository .role $ctx.Values.image.tag -}} +{{- end -}} + +{{/* Secret name (existing or generated) */}} +{{- define "ezscale-website.secretName" -}} +{{- if .Values.secret.create -}} +{{- include "ezscale-website.fullname" . -}}-secrets +{{- else -}} +{{- .Values.secret.existingSecretName -}} +{{- end -}} +{{- end -}} + +{{/* DB host — points at in-cluster MariaDB or external one */}} +{{- define "ezscale-website.dbHost" -}} +{{- if .Values.mariadb.enabled -}} +{{ include "ezscale-website.fullname" . }}-mariadb +{{- else -}} +{{- $ref := .Values.mariadb.externalRef -}} +{{- printf "%s.%s.svc.cluster.local" $ref.name $ref.namespace -}} +{{- end -}} +{{- end -}} + +{{/* Redis host */}} +{{- define "ezscale-website.redisHost" -}} +{{ include "ezscale-website.fullname" . }}-valkey +{{- end -}} diff --git a/helm/ezscale-website/values.yaml b/helm/ezscale-website/values.yaml new file mode 100644 index 0000000..06f1f36 --- /dev/null +++ b/helm/ezscale-website/values.yaml @@ -0,0 +1,160 @@ +# Default values: lean toward "self-contained dev cluster" so `helm install` +# with no flags produces a working stack on a local k3d. Production values +# live in values-us-prod.yaml and disable the in-cluster MariaDB/Valkey when +# pointing at the existing ezscale-namespace MariaDB. + +replicaCount: 1 + +image: + registry: git.ezscale.cloud + repository: ezscale/website + # The chart appends `-{role}-{tag}` to derive each role's image. + # Override `tag` per-release via --set image.tag=v0.1.0 + tag: latest + pullPolicy: IfNotPresent + +imagePullSecrets: + - name: gitea-registry + +nameOverride: "" +fullnameOverride: "" + +# --- App (php-fpm + nginx sidecar) --- +app: + replicaCount: 1 + autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 8 + targetCPU: 70 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 1000m + memory: 1Gi + +# --- Horizon --- +horizon: + replicaCount: 1 + resources: + requests: + cpu: 100m + memory: 256Mi + +# --- Scheduler --- +scheduler: + replicaCount: 1 + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 200m + memory: 256Mi + +# --- In-cluster MariaDB (mariadb-operator CRD) --- +mariadb: + enabled: true + # When enabled, deploys a MariaDB CR named `{release}-mariadb` in this + # release's namespace. When disabled, the chart still creates Database/User/ + # Grant CRDs but they reference an externally-managed MariaDB CR via + # `mariadb.externalRef`. + externalRef: + name: "" # e.g. "mariadb" + namespace: "" # e.g. "ezscale" + image: mariadb:11.4 + replicas: 1 + storage: + size: 5Gi + storageClassName: local-path + rootPasswordSecret: "" # if empty, chart generates a random secret + database: ezscale_billing + username: ezscale_billing_app + +# --- In-cluster Valkey (StatefulSet) --- +valkey: + enabled: true + image: valkey/valkey:9-alpine + password: "" # if empty, chart generates a random secret + maxmemory: "1gb" + storage: + size: 5Gi + storageClassName: local-path + +# --- Migration Job (Helm hook) --- +migrate: + enabled: true + seed: false + seedClass: ProductionSeeder + +# --- Ingress (Traefik IngressRoute) --- +ingressRoute: + enabled: false + hosts: + - ezscale.cloud + - account.ezscale.cloud + - admin.ezscale.cloud + tls: + secretName: ezscale-website-tls + issuerName: letsencrypt + middlewares: + cloudflarewarp: + enabled: false + namespace: kube-system + name: cloudflarewarp + httpToHttps: + enabled: false + namespace: kube-system + name: http-to-https + +# --- Service --- +service: + type: ClusterIP + port: 80 + +# --- Non-secret env vars (rendered into ConfigMap) --- +env: + APP_NAME: "EZSCALE Billing" + APP_ENV: production + APP_DEBUG: "false" + APP_URL: https://ezscale.cloud + APP_MAINTENANCE_DRIVER: file + LOG_CHANNEL: stack + LOG_STACK: single + LOG_LEVEL: info + DB_CONNECTION: mysql + DB_PORT: "3306" + DB_DATABASE: ezscale_billing + DB_USERNAME: ezscale_billing_app + REDIS_CLIENT: phpredis + REDIS_PORT: "6379" + SESSION_DRIVER: redis + SESSION_LIFETIME: "120" + SESSION_DOMAIN: .ezscale.cloud + CACHE_STORE: redis + QUEUE_CONNECTION: redis + BROADCAST_CONNECTION: log + FILESYSTEM_DISK: s3 + MAIL_MAILER: smtp + AWS_DEFAULT_REGION: us-east-1 + AWS_USE_PATH_STYLE_ENDPOINT: "true" + +# --- Secret references (chart does NOT generate APP_KEY or Passport keys) --- +secret: + # When false, chart assumes a Secret named `secret.existingSecretName` is + # already present. This is the production path. + create: false + existingSecretName: ezscale-website-secrets + # Used only when create=true (local dev convenience). + values: {} + +# --- Probes --- +healthCheck: + livenessPath: /up + readinessPath: /up + initialDelaySeconds: 15 + periodSeconds: 15 + timeoutSeconds: 5 + failureThreshold: 3