Helm Charts
Serko Northsky uses Helm to package and deploy applications to Google Kubernetes Engine (GKE). The chart follows a modular values structure that separates component configurations from environment-specific overrides.
Directory Structure
infra/k8s/
├── helm/
│ ├── deploy-helm.sh # Main deployment script
│ ├── rollout-pods.sh # Pod restart utility
│ └── serko-northsky/ # Main Helm chart
│ ├── Chart.yaml # Chart metadata
│ ├── Chart.lock # Dependency lock file
│ ├── values.yaml # Values documentation
│ ├── templates/ # Kubernetes manifests
│ │ ├── _helpers.tpl # Template helpers
│ │ ├── namespace.yaml
│ │ ├── serviceaccount.yaml
│ │ ├── ingress.yaml
│ │ ├── backend-*.yaml # Backend resources
│ │ ├── frontend-*.yaml # Frontend resources
│ │ ├── tools-*.yaml # Tools resources
│ │ ├── docs-*.yaml # Docs resources
│ │ ├── langfuse-*.yaml # Langfuse resources
│ │ ├── clickhouse-*.yaml # ClickHouse resources
│ │ ├── external-secret.yaml
│ │ └── secretstore.yaml
│ └── values/
│ ├── components/ # Base component configs
│ │ ├── global.yaml
│ │ ├── base.yaml
│ │ ├── backend.yaml
│ │ ├── frontend.yaml
│ │ ├── tools.yaml
│ │ ├── docs.yaml
│ │ ├── langfuse.yaml
│ │ ├── ingress.yaml
│ │ └── security.yaml
│ └── environments/ # Environment overrides
│ ├── dev/
│ │ ├── overrides.yaml
│ │ └── langfuse-overrides.yaml
│ ├── test/
│ │ └── overrides.yaml
│ └── prod/
│ ├── overrides.yaml
│ └── langfuse-overrides.yaml
├── check-https.sh # HTTPS verification utility
└── status-k8s.sh # Cluster status utility
Values Organization
The Helm chart uses a layered values structure for maintainability:
Component Values (values/components/)
Base configurations for each application component:
| File | Purpose |
|---|---|
global.yaml | Shared settings (image registry, project ID) |
base.yaml | Common defaults for all services |
backend.yaml | FastAPI backend configuration |
frontend.yaml | Next.js frontend configuration |
tools.yaml | Tools app configuration |
docs.yaml | Documentation site configuration |
langfuse.yaml | Langfuse observability platform |
ingress.yaml | GCE Ingress and routing rules |
security.yaml | Service accounts, secrets configuration |
Environment Overrides (values/environments/)
Environment-specific settings that override component values:
| Environment | Overrides |
|---|---|
dev | Development URLs, debug settings, minimal replicas |
test | Testing URLs, integration settings |
prod | Production URLs, high availability, production secrets |
Deployed Services
The chart deploys the following Kubernetes resources:
Application Services
| Service | Type | Port | Description |
|---|---|---|---|
backend-service | ClusterIP | 8000 | FastAPI backend API |
frontend-service | ClusterIP | 80 | Next.js web application |
tools-service | ClusterIP | 80 | Internal tools app |
docs-service | ClusterIP | 80 | Documentation site |
Supporting Services
| Service | Type | Port | Description |
|---|---|---|---|
langfuse-service | ClusterIP | 3000 | LLM observability platform |
clickhouse-service | ClusterIP | 8123 | Analytics database for Langfuse |
Ingress Routing
Traffic is routed via GCE Ingress with the following host-based rules:
| Host Pattern | Backend | Path |
|---|---|---|
app.{env}.serko-northsky.com | frontend-service | /* |
app.{env}.serko-northsky.com | backend-service | /api/* |
tools.{env}.serko-northsky.com | tools-service | /* |
docs.{env}.serko-northsky.com | docs-service | /* |
langfuse.{env}.serko-northsky.com | langfuse-service | /* |
Template Helpers
The _helpers.tpl file provides reusable template functions:
# Common naming conventions
{{ include "serko-northsky.fullname" . }}
{{ include "serko-northsky.name" . }}
# Selector labels for each service
{{ include "serko-northsky.backend.selectorLabels" . }}
{{ include "serko-northsky.frontend.selectorLabels" . }}
# Image references (supports custom registry or default)
{{ include "serko-northsky.backend.image" . }}
{{ include "serko-northsky.frontend.image" . }}
# Service account name
{{ include "serko-northsky.serviceAccountName" . }}
Deployment
Using the Deployment Script
# Deploy to an environment
cd infra/k8s/helm
./deploy-helm.sh dev # Development
./deploy-helm.sh test # Testing
./deploy-helm.sh prod # Production
The script automatically:
- Loads all component values files
- Applies environment-specific overrides
- Runs
helm upgrade --install
Manual Deployment
cd infra/k8s/helm/serko-northsky
# Preview the rendered templates
helm template serko-northsky . \
-f values/components/global.yaml \
-f values/components/backend.yaml \
-f values/components/frontend.yaml \
-f values/components/ingress.yaml \
-f values/components/security.yaml \
-f values/environments/dev/overrides.yaml
# Deploy
helm upgrade --install serko-northsky . \
--namespace serko-northsky-dev \
-f values/components/global.yaml \
-f values/components/backend.yaml \
-f values/components/frontend.yaml \
-f values/components/ingress.yaml \
-f values/components/security.yaml \
-f values/environments/dev/overrides.yaml
Rollout Pods
To restart pods after a configuration change:
./rollout-pods.sh dev backend # Restart backend pods
./rollout-pods.sh dev frontend # Restart frontend pods
./rollout-pods.sh dev all # Restart all pods
Configuration Reference
Backend Configuration
backend:
enabled: true
name: backend
replicaCount: 1
image:
tag: latest
pullPolicy: Always
service:
type: ClusterIP
port: 8000
resources:
requests:
memory: "1024Mi"
cpu: "250m"
limits:
memory: "1024Mi"
cpu: "500m"
probes:
liveness:
path: /api/health
initialDelaySeconds: 90
readiness:
path: /api/health
initialDelaySeconds: 60
Secrets Management
The chart integrates with External Secrets Operator to sync secrets from Google Secret Manager:
externalSecrets:
enabled: true
secretStore:
name: app-secretstore
gcpProjectId: serko-northsky-dev
secrets:
# Backend configuration secret
- name: backend-config
keys:
- DATABASE_URL
- OPENAI_API_KEY
- FIREBASE_SERVICE_ACCOUNT_CONTENT
- LANGFUSE_ENABLED
- LANGFUSE_SECRET_KEY
- LANGFUSE_PUBLIC_KEY
# Frontend configuration secret
- name: frontend-config
keys:
- NEXT_PUBLIC_API_URL
- NEXT_PUBLIC_FIREBASE_CONFIG
- NEXT_PUBLIC_LOGO_DEV_KEY
Service Account
GKE Workload Identity is used for secure GCP access:
serviceAccount:
create: true
name: app-service-account
annotations:
iam.gke.io/gcp-service-account: serko-northsky-dev-app@serko-northsky-dev.iam.gserviceaccount.com
Adding a New Service
To add a new service to the chart:
-
Create component values (
values/components/myservice.yaml):myservice:
enabled: true
name: myservice
replicaCount: 1
image:
tag: latest
service:
type: ClusterIP
port: 3000 -
Create deployment template (
templates/myservice-deployment.yaml) -
Create service template (
templates/myservice-service.yaml) -
Add helper functions to
_helpers.tplif needed -
Add ingress route in
values/components/ingress.yamlif external access is required -
Update environment overrides with environment-specific settings
Troubleshooting
Check Deployment Status
# View all resources in namespace
kubectl get all -n serko-northsky-dev
# Check pod logs
kubectl logs -n serko-northsky-dev -l app=backend
# Describe a failing pod
kubectl describe pod -n serko-northsky-dev <pod-name>
Validate Chart
cd infra/k8s/helm/serko-northsky
# Lint the chart
helm lint .
# Dry-run installation
helm install --dry-run --debug serko-northsky .
Common Issues
| Issue | Solution |
|---|---|
| Image pull errors | Verify Workload Identity is configured correctly |
| Secret not found | Check External Secrets Operator and SecretStore |
| Ingress not working | Verify GCE Ingress controller and SSL certificates |
| Pod crash loop | Check resource limits and liveness probe settings |