Kubernetes
Deploy NexusCommerce to a Kubernetes cluster with Helm, HPA autoscaling, and Ingress TLS.
Overview
The NexusCommerce Helm chart deploys the full platform to any Kubernetes cluster. It includes deployments with health probes, horizontal pod autoscalers for the API and workers, StatefulSets for Redis and ClickHouse, and an Ingress resource with cert-manager TLS.
The chart lives at infrastructure/k8s/nexuscommerce/.
Key Concepts
Helm Chart — A templated Kubernetes manifest collection with configurable values. NexusCommerce ships a single chart that deploys all services.
HPA (Horizontal Pod Autoscaler) — Automatically scales API pods (2-10 replicas) and worker pods (1-8 replicas) based on CPU utilization.
StatefulSets — Redis and ClickHouse use StatefulSets with persistent volume claims for data durability across pod restarts.
Ingress — A single Ingress resource routes traffic to the API and frontend based on path, with a separate host rule for Grafana on a subdomain.
Getting Started
Prerequisites
- A Kubernetes cluster (1.28+)
- Helm 3.15+
- kubectl configured for your cluster
- nginx-ingress controller installed
- cert-manager installed (for automatic TLS)
Step 1: Create namespace and secret
kubectl create namespace nexuscommerce
kubectl create secret generic nexuscommerce-secret \
--namespace nexuscommerce \
--from-literal=NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co \
--from-literal=NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ... \
--from-literal=SUPABASE_SERVICE_ROLE_KEY=eyJ... \
--from-literal=SUPABASE_DB_URL=postgresql://... \
--from-literal=CLICKHOUSE_PASSWORD=your-password \
--from-literal=GRAFANA_ADMIN_PASSWORD=your-passwordStep 2: Configure values
Review and customize values.yaml:
cp infrastructure/k8s/nexuscommerce/values.yaml my-values.yamlAt minimum, set global.domain to your production domain.
Step 3: Install
helm install nexuscommerce infrastructure/k8s/nexuscommerce \
--namespace nexuscommerce \
--values my-values.yaml \
--set existingSecret=nexuscommerce-secretStep 4: Verify
kubectl get pods -n nexuscommerce
kubectl get ingress -n nexuscommerceAll pods should reach Running status within 2 minutes. The Ingress should show your domain with the TLS certificate.
Features
Resources Deployed
| Resource | Kind | Replicas | Notes |
|---|---|---|---|
| Web | Deployment | 2 | Next.js standalone |
| API | Deployment | 2 | NestJS, HPA 2-10 |
| Workers | Deployment | 2 | Python FastAPI, HPA 1-8 |
| Redis | StatefulSet | 1 | 5 Gi PVC |
| ClickHouse | StatefulSet | 1 | 50 Gi PVC |
| Grafana | Deployment | 1 | Optional |
Autoscaling
The API and workers have horizontal pod autoscalers:
| Service | Min | Max | Target CPU |
|---|---|---|---|
| API | 2 | 10 | 70% |
| Workers | 1 | 8 | 80% |
Disable HPA for staging by setting api.hpa.enabled: false and workers.hpa.enabled: false in your values file.
Health Probes
All deployments include liveness and readiness probes:
| Service | Probe Path | Initial Delay | Period |
|---|---|---|---|
| Web | GET / | 15s (live), 5s (ready) | 30s / 10s |
| API | GET /api/v1/health | 15s / 5s | 30s / 10s |
| Workers | GET /health | 20s / 10s | 30s / 10s |
| Grafana | GET /api/health | 30s / 10s | 30s / 10s |
Ingress Routing
| Host | Path | Backend |
|---|---|---|
app.nexuscommerce.io | /api/v1 | API service (3001) |
app.nexuscommerce.io | /docs | API service (3001) |
app.nexuscommerce.io | / | Web service (3000) |
grafana.nexuscommerce.io | / | Grafana service (3000) |
TLS is handled by cert-manager with a letsencrypt-prod ClusterIssuer.
Values Files
| File | Purpose |
|---|---|
values.yaml | Production defaults |
values-staging.yaml | Staging overrides (1 replica, smaller resources, no HPA) |
values-production.yaml | Production overrides (domain only) |
Configuration
Upgrading
helm upgrade nexuscommerce infrastructure/k8s/nexuscommerce \
--namespace nexuscommerce \
--values my-values.yaml \
--set global.imageTag=sha-abc1234Using an External Secret Manager
Set existingSecret to the name of a Kubernetes Secret created by your secret manager (e.g., External Secrets Operator, Vault):
existingSecret: my-external-secretWhen set, the chart skips creating its own Secret and references yours instead.
Disabling Optional Services
redis:
enabled: false # Use managed Redis (e.g., ElastiCache)
clickhouse:
enabled: false # Use managed ClickHouse
grafana:
enabled: false # Use external GrafanaWhen disabled, set the connection URLs directly in the ConfigMap or Secret.
Resource Defaults
| Service | CPU Request | Memory Request | CPU Limit | Memory Limit |
|---|---|---|---|---|
| Web | 100m | 256 Mi | 500m | 512 Mi |
| API | 200m | 384 Mi | 1000m | 768 Mi |
| Workers | 200m | 512 Mi | 1000m | 1 Gi |
| Redis | 50m | 128 Mi | 250m | 320 Mi |
| ClickHouse | 250m | 1 Gi | 2000m | 4 Gi |
| Grafana | 50m | 128 Mi | 500m | 512 Mi |