Kubernetes (Helm) Deployment

For a long-running Luna DevOps installation on Kubernetes or K3s, use Helm. The chart deploys API, Worker, PostgreSQL, and Redis together, and it can also connect to existing external database services.

Before You Start

You need:

  • A Kubernetes or K3s cluster.
  • kubectl and helm configured locally.
  • Network access from the cluster to pull DockerHub images.
  • A default StorageClass for PostgreSQL and Redis data.

Install

Run this from the repository root:

helm install luna-devops ./charts/luna-devops \
  --namespace luna-devops \
  --create-namespace

This starts:

liteyukistudio/luna-devops:nightly
liteyukistudio/luna-worker:nightly
postgres:17-alpine
redis:8-alpine

The AI assistant is disabled by default. The release workflow also publishes liteyukistudio/luna-agent, but the chart deploys it only when ai.enabled=true and ai.existingSecret is provided. That Secret needs only one stable ai-internal-secret key by default; generate it with openssl rand -hex 32, and API plus Agent derive purpose-separated internal keys automatically.

Open The Console

Forward the API Service:

kubectl -n luna-devops port-forward svc/luna-devops-api 8088:80

Then visit:

http://localhost:8088

Use A Fixed Version

helm upgrade --install luna-devops ./charts/luna-devops \
  --namespace luna-devops \
  --create-namespace \
  --set api.image.tag=v0.1.0-rc.1 \
  --set worker.image.tag=v0.1.0-rc.1 \
  --set ai.agent.image.tag=v0.1.0-rc.1

Access the Console Through a Public Domain

When exposing the console with Ingress, set app.publicBaseUrl to the real browser-facing URL:

helm upgrade --install luna-devops ./charts/luna-devops \
  --namespace luna-devops \
  --create-namespace \
  --set app.publicBaseUrl=https://devops.example.com \
  --set ingress.enabled=true \
  --set ingress.className=nginx \
  --set ingress.hosts[0].host=devops.example.com

app.publicBaseUrl affects OIDC callbacks, webhook callbacks, and browser origin checks. Do not set it to an internal Service address.

Use External PostgreSQL Or Redis

The built-in services are convenient for getting started. If production already has managed PostgreSQL or Redis, disable the matching built-in component:

postgresql:
  enabled: false
externalDatabase:
  url: postgres://devops:password@postgres.example.com:5432/devops?sslmode=disable

redis:
  enabled: false
externalRedis:
  url: redis://default:replace-with-a-strong-password@redis.example.com:6379/0

The chart generates the built-in Redis password on first install and stores redis-password separately from the redis-url consumed by API and Worker; upgrades reuse the existing Secret. A redis.auth.existingSecret for the built-in service must contain both keys. For external Redis, set externalRedis.url directly or use an externalRedis.existingSecret containing only redis-url. External URIs use redis://username:password@host:port/database; use rediss:// for TLS.

Then install:

helm upgrade --install luna-devops ./charts/luna-devops \
  --namespace luna-devops \
  --create-namespace \
  -f values-prod.yaml

Common Values

ValueDefaultNotes
app.publicBaseUrlhttp://localhost:8088Public console URL. Required when Ingress is enabled.
app.secretEncryptionKeyGenerated on first installEncrypts Git, registry, and OIDC secrets. Keep it stable in production.
api.image.tag / worker.image.tagnightlyAPI and worker image tag.
ai.enabledfalseDeploy the independent AI Agent. ai.existingSecret must contain ai-internal-secret.
ai.internalSecretKeyai-internal-secretKey name holding the AI internal root in ai.existingSecret.
ai.agent.image.tagChart appVersionAgent image tag. Releases use the same tag as API and Worker.
postgresql.enabledtrueInstall built-in PostgreSQL.
redis.enabledtrueInstall built-in Redis.
externalRedis.urlEmptyComplete external Redis URI, used when built-in Redis is disabled.
worker.buildEgressModerestrictedBuild Job egress mode. Cluster-internal access is restricted by default; use permissive only when you explicitly accept the risk.

Uninstall

helm uninstall luna-devops -n luna-devops

PVCs are retained by default to prevent accidental data loss. Remove them manually only after confirming the data is no longer needed:

kubectl -n luna-devops delete pvc -l app.kubernetes.io/instance=luna-devops