Skip to main content

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:

FilePurpose
global.yamlShared settings (image registry, project ID)
base.yamlCommon defaults for all services
backend.yamlFastAPI backend configuration
frontend.yamlNext.js frontend configuration
tools.yamlTools app configuration
docs.yamlDocumentation site configuration
langfuse.yamlLangfuse observability platform
ingress.yamlGCE Ingress and routing rules
security.yamlService accounts, secrets configuration

Environment Overrides (values/environments/)

Environment-specific settings that override component values:

EnvironmentOverrides
devDevelopment URLs, debug settings, minimal replicas
testTesting URLs, integration settings
prodProduction URLs, high availability, production secrets

Deployed Services

The chart deploys the following Kubernetes resources:

Application Services

ServiceTypePortDescription
backend-serviceClusterIP8000FastAPI backend API
frontend-serviceClusterIP80Next.js web application
tools-serviceClusterIP80Internal tools app
docs-serviceClusterIP80Documentation site

Supporting Services

ServiceTypePortDescription
langfuse-serviceClusterIP3000LLM observability platform
clickhouse-serviceClusterIP8123Analytics database for Langfuse

Ingress Routing

Traffic is routed via GCE Ingress with the following host-based rules:

Host PatternBackendPath
app.{env}.serko-northsky.comfrontend-service/*
app.{env}.serko-northsky.combackend-service/api/*
tools.{env}.serko-northsky.comtools-service/*
docs.{env}.serko-northsky.comdocs-service/*
langfuse.{env}.serko-northsky.comlangfuse-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:

  1. Loads all component values files
  2. Applies environment-specific overrides
  3. 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:

  1. Create component values (values/components/myservice.yaml):

    myservice:
    enabled: true
    name: myservice
    replicaCount: 1
    image:
    tag: latest
    service:
    type: ClusterIP
    port: 3000
  2. Create deployment template (templates/myservice-deployment.yaml)

  3. Create service template (templates/myservice-service.yaml)

  4. Add helper functions to _helpers.tpl if needed

  5. Add ingress route in values/components/ingress.yaml if external access is required

  6. 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

IssueSolution
Image pull errorsVerify Workload Identity is configured correctly
Secret not foundCheck External Secrets Operator and SecretStore
Ingress not workingVerify GCE Ingress controller and SSL certificates
Pod crash loopCheck resource limits and liveness probe settings