Skip to content

Kubernetes Deployment

NAAS provides a Helm chart for production Kubernetes deployments, with raw YAML manifests available as an alternative.

The Helm chart in charts/naas/ is the recommended way to deploy NAAS on Kubernetes. It handles namespaces, secrets, config, scaling, and ingress out of the box.

Prerequisites

  • Kubernetes 1.27+
  • Helm 3.x
  • A container image of NAAS accessible to your cluster

Quick Start

helm install naas charts/naas \
  --set secrets.redisPassword=changeme \
  --set secrets.encryptionKey=$(openssl rand -base64 32)

Verify:

kubectl -n naas get pods

All pods should reach Running. The API readiness probe hits /healthcheck — pods will not become ready until Redis is up.

Common Configurations

External Redis

Disable the bundled Redis and point to a managed instance:

helm install naas charts/naas \
  --set redis.enabled=false \
  --set redis.external.host=redis.prod.internal \
  --set redis.external.port=6379 \
  --set secrets.redisPassword=changeme

Ingress

helm install naas charts/naas \
  --set ingress.enabled=true \
  --set ingress.className=nginx \
  --set "ingress.hosts[0].host=naas.example.com" \
  --set "ingress.hosts[0].paths[0].path=/" \
  --set "ingress.hosts[0].paths[0].pathType=Prefix"

TLS with Custom Certificates

helm install naas charts/naas \
  --set secrets.tlsCert="$(cat fullchain.pem)" \
  --set secrets.tlsKey="$(cat privkey.pem)" \
  --set secrets.tlsCaBundle="$(cat chain.pem)"

Without certificates, NAAS generates a self-signed cert at startup.

cert-manager: Create a Certificate resource targeting the naas-api Service and reference the resulting secret via secrets.existingSecret.

Context Routing

Deploy workers for specific network contexts:

# values-contexts.yaml
worker:
  replicas: 0  # Disable default workers

# Use multiple helm releases or subcharts for context-specific workers.
# Alternatively, deploy additional worker Deployments:

For context-based worker isolation, override config per worker pool:

# Corp workers
helm install naas-worker-corp charts/naas \
  --set api.replicas=0 \
  --set redis.enabled=false \
  --set redis.external.host=redis.naas.svc \
  --set config.WORKER_CONTEXTS=corp \
  --set config.NAAS_CONTEXTS=corp

# OOB workers
helm install naas-worker-oob charts/naas \
  --set api.replicas=0 \
  --set redis.enabled=false \
  --set redis.external.host=redis.naas.svc \
  --set config.WORKER_CONTEXTS=oob-dc1,oob-dc2 \
  --set config.NAAS_CONTEXTS=oob-dc1,oob-dc2

See Context Routing for full details.

Scaling

# Scale workers
helm upgrade naas charts/naas --set worker.replicas=5

# Scale API
helm upgrade naas charts/naas --set api.replicas=4

Each worker pod runs worker.processes RQ processes (default: 10). Total job concurrency = worker.replicas × worker.processes.

OpenTelemetry

helm install naas charts/naas \
  --set config.OTEL_ENABLED=true \
  --set config.OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector.monitoring:4317

Upgrade and Rollback

# Upgrade to new values or chart version
helm upgrade naas charts/naas -f values-prod.yaml

# Rollback to previous release
helm rollback naas

# Uninstall
helm uninstall naas

Values Reference

Value Default Description
image.repository ghcr.io/lykinsbd/naas Container image
image.tag Chart appVersion Image tag
namespace naas Target namespace
api.replicas 2 API pod replicas
api.port 443 API listen port
api.resources.limits.memory 768Mi API memory limit
api.resources.limits.cpu 500m API CPU limit
worker.replicas 2 Worker pod replicas
worker.processes 10 RQ processes per worker pod
worker.metricsPort 9090 Worker metrics port
worker.resources.limits.memory 512Mi Worker memory limit
worker.resources.limits.cpu 500m Worker CPU limit
config.* (see below) Application env vars (injected as ConfigMap)
secrets.existingSecret "" Use an existing K8s Secret
secrets.redisPassword "" Redis password
secrets.encryptionKey "" Credential encryption key
secrets.tlsCert "" TLS certificate (PEM)
secrets.tlsKey "" TLS private key (PEM)
secrets.tlsCaBundle "" TLS CA bundle (PEM)
redis.enabled true Deploy bundled Redis
redis.external.host "" External Redis host
redis.external.port 6379 External Redis port
ingress.enabled false Create Ingress resource
ingress.className "" Ingress class
service.type ClusterIP Service type

All config.* values map to environment variables. See Environment Variables for the full list.

Production Redis

The bundled Redis is a single-replica deployment with no persistence — suitable for dev/test. For production, use a managed Redis (AWS ElastiCache, Redis Cloud, etc.) with redis.enabled=false.

Raw Manifests (Alternative)

If you cannot use Helm, plain YAML manifests are available in k8s/.

Applying Manifests

# Create the secret from the example
cp k8s/secret.yaml.example k8s/secret.yaml
# Edit k8s/secret.yaml with base64-encoded values

# Apply in order
kubectl apply -f k8s/namespace.yaml
kubectl apply -f k8s/secret.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/redis/
kubectl apply -f k8s/api/
kubectl apply -f k8s/worker/

Never commit k8s/secret.yaml — it is in .gitignore.

Scaling Workers (Manifests)

Edit spec.replicas in k8s/worker/deployment.yaml, or:

kubectl -n naas scale deploy/naas-worker --replicas=5

Local Development with k3d

k3d runs a lightweight k3s cluster inside Docker — no cloud account needed.

# Install k3d
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash

# Create a cluster
k3d cluster create naas-dev --port "8443:443@loadbalancer"

# Deploy with Helm
helm install naas charts/naas \
  --set secrets.redisPassword=devpassword \
  --set secrets.encryptionKey=dev-encryption-key-32bytes!!

# Verify
kubectl -n naas get pods
curl -k https://localhost:8443/healthcheck

Security Context

Both API and worker pods run as UID 1000 (naas user, non-root) with all Linux capabilities dropped. The API retains NET_BIND_SERVICE to bind port 443 without root.

Monitoring

The /metrics endpoint on API pods exposes Prometheus metrics. Configure scraping via a ServiceMonitor (Prometheus Operator) or static config:

scrape_configs:
  - job_name: naas
    static_configs:
      - targets: ['naas-api.naas.svc:443']
    scheme: https
    tls_config:
      insecure_skip_verify: true
Metric Type Description
naas_http_requests_total Counter HTTP requests by endpoint, method, status
naas_http_request_duration_seconds Histogram Request latency by endpoint
naas_queue_depth Gauge Jobs waiting in queue
naas_workers_active Gauge Active RQ worker processes

Connection Pooling

Workers reuse SSH connections across sequential jobs to the same device. Configure via config.* values:

Value Default Description
config.CONNECTION_POOL_ENABLED true Enable pooling
config.CONNECTION_POOL_MAX_SIZE 10 Max connections per worker process
config.CONNECTION_POOL_IDLE_TIMEOUT 300 Evict idle connections (seconds)
config.CONNECTION_POOL_MAX_AGE 3600 Evict old connections (seconds)
config.CONNECTION_POOL_KEEPALIVE 60 SSH keepalive interval (seconds)