17 KiB
Databasus Helm Chart
Installation
Install directly from the OCI registry (no need to clone the repository):
helm install databasus oci://ghcr.io/databasus/charts/databasus \
-n databasus --create-namespace
The -n databasus --create-namespace flags control which namespace the chart is installed into. You can use any namespace name you prefer.
Accessing Databasus
By default, the chart creates a ClusterIP service. Use port-forward to access:
kubectl port-forward svc/databasus-service 4005:4005 -n databasus
Then open http://localhost:4005 in your browser.
Configuration
Main Parameters
| Parameter | Description | Default Value |
|---|---|---|
image.repository |
Docker image | databasus/databasus |
image.tag |
Image tag | latest |
image.pullPolicy |
Image pull policy | Always |
imagePullSecrets |
Image pull secrets | [] |
replicaCount |
Number of replicas | 1 |
Custom Root CA
| Parameter | Description | Default Value |
|---|---|---|
customRootCA |
Name of Secret containing CA certificate | "" |
To trust a custom CA certificate (e.g., for internal services with self-signed certificates):
- Create a Secret with your CA certificate:
kubectl create secret generic my-root-ca \
--from-file=ca.crt=./path/to/ca-certificate.crt
- Reference it in values:
customRootCA: my-root-ca
The certificate will be mounted to /etc/ssl/certs/custom-root-ca.crt and the SSL_CERT_FILE environment variable will be set automatically.
Extra Environment Variables
| Parameter | Description | Default Value |
|---|---|---|
extraEnv |
Extra env vars on the container; standard Kubernetes EnvVar shape. | [] |
extraEnvFrom |
Extra envFrom sources; standard Kubernetes EnvFromSource (secretRef/configMapRef). | [] |
Use extraEnv for arbitrary container env injection — for example, disabling anonymous telemetry in air-gapped or compliance-restricted clusters:
extraEnv:
- name: IS_DISABLE_ANONYMOUS_TELEMETRY
value: "true"
Or pull a secret value into the container:
extraEnv:
- name: SOME_TOKEN
valueFrom:
secretKeyRef:
name: databasus-extras
key: token
Use extraEnvFrom to mount entire Secrets/ConfigMaps as env (handy with External Secrets Operator or the secrets-store-csi-driver):
extraEnvFrom:
- secretRef:
name: databasus-extras
- configMapRef:
name: databasus-extras-cm
Notes:
- Env values must be strings. Use quoted
"true"/"false"rather than bare booleans, and pass--set-stringon the CLI (e.g.--set-string 'extraEnv[0].value=true') to avoid Kubernetes rejecting non-string values. extraEnvis appended afterSSL_CERT_FILE(whencustomRootCAis set), so an entry with the same name will overrideSSL_CERT_FILE. Avoid duplicatenameentries unless that override is intentional.
Logging and Observability
Databasus logs to stdout and can additionally export to any OpenTelemetry backend. There is no dedicated chart value for this — configure it through extraEnv like any other application setting.
| Variable | Description | Default |
|---|---|---|
LOG_LEVEL |
debug, info, warn or error |
info |
OPEN_TELEMETRY_URL |
Full OTLP endpoint URL; empty disables export | empty |
OPEN_TELEMETRY_HEADERS |
k=v pairs, comma separated, values percent-encoded |
empty |
The scheme selects the transport: http:// and https:// use the URL verbatim, path included, while grpc:// and grpcs:// take only the host and port. Pointing at a backend directly and pointing at an OTel Collector are the same setting — a Collector is itself an OTLP receiver:
extraEnv:
- name: LOG_LEVEL
value: "info"
# OTLP/gRPC — Graylog 6.2+, SigNoz, a Collector on :4317
- name: OPEN_TELEMETRY_URL
value: "grpc://otel-collector.observability:4317"
# OTLP/HTTP — VictoriaLogs, Loki, a Collector on :4318/v1/logs
# value: "http://victoria-logs.observability:9428/insert/opentelemetry/v1/logs"
Headers are how a backend is authenticated and tuned: signoz-ingestion-key for SigNoz Cloud, Authorization=Basic%20<base64> for Grafana Cloud, dd-api-key for Datadog, x-honeycomb-team for Honeycomb, VL-Stream-Fields and VL-Extra-Fields for VictoriaLogs. The format matches the standard OTEL_EXPORTER_OTLP_HEADERS, so values are percent-decoded and a value may itself contain a comma (%2C), an equals sign (%3D) or a space (%20). A query string in the URL is rejected rather than silently dropped, since the exporter cannot send one.
Use a Collector when you need to fan out to several backends or to survive a long backend outage — it has a disk-backed queue, whereas the in-process exporter drops records once its buffer fills.
Audit entries (user actions) are exported alongside application logs and carry log_type=audit. They ignore LOG_LEVEL, so raising the level never silently drops the audit trail.
Credentials. A token in OPEN_TELEMETRY_HEADERS, or a password embedded as userinfo in OPEN_TELEMETRY_URL, belongs in a Secret — never as a literal extraEnv[].value, which ends up in values.yaml, in git and in helm get values:
extraEnv:
- name: OPEN_TELEMETRY_HEADERS
valueFrom:
secretKeyRef:
name: databasus-observability
key: otlp-headers
Over http:// and grpc:// those credentials travel in clear — use https:// or grpcs:// outside a trusted network.
File logging. logFileIsEnabled is the one logging setting with its own chart value, and it is false here even though the application defaults it to on: stdout is already collected by the cluster's node agent, and that is the platform's logging model. The file sink exists for Docker and bare-metal installs. Set it to true and the pod writes /databasus-data/databasus.log, capped at 4 files of 5 MB, which needs persistence enabled or the logs vanish with the pod. The location and the limits are not configurable.
Service
| Parameter | Description | Default Value |
|---|---|---|
service.type |
Service type | ClusterIP |
service.port |
Service port | 4005 |
service.targetPort |
Container port | 4005 |
service.headless.enabled |
Enable headless service | true |
Storage
| Parameter | Description | Default Value |
|---|---|---|
persistence.enabled |
Enable persistent storage | true |
persistence.storageClassName |
Storage class | "" (cluster default) |
persistence.accessMode |
Access mode | ReadWriteOnce |
persistence.size |
Storage size | 10Gi |
persistence.mountPath |
Mount path | /databasus-data |
persistence.annotations |
Annotations for the PVC | {} |
Resources
| Parameter | Description | Default Value |
|---|---|---|
resources.requests.memory |
Memory request | 1Gi |
resources.requests.cpu |
CPU request | 500m |
resources.limits.memory |
Memory limit | 1Gi |
resources.limits.cpu |
CPU limit | 500m |
External Access Options
Option 1: Port Forward (Default)
Best for development or quick access:
kubectl port-forward svc/databasus-service 4005:4005 -n databasus
Access at http://localhost:4005
Option 2: NodePort
For direct access via node IP:
# nodeport-values.yaml
service:
type: NodePort
port: 4005
targetPort: 4005
nodePort: 30080
helm install databasus oci://ghcr.io/databasus/charts/databasus \
-n databasus --create-namespace \
-f nodeport-values.yaml
Access at http://<NODE-IP>:30080
Option 3: LoadBalancer
For cloud environments with load balancer support:
# loadbalancer-values.yaml
service:
type: LoadBalancer
port: 80
targetPort: 4005
helm install databasus oci://ghcr.io/databasus/charts/databasus \
-n databasus --create-namespace \
-f loadbalancer-values.yaml
Get the external IP:
kubectl get svc -n databasus
Access at http://<EXTERNAL-IP>
Option 4: Ingress
For domain-based access with TLS:
# ingress-values.yaml
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
hosts:
- host: backup.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: backup-example-com-tls
hosts:
- backup.example.com
helm install databasus oci://ghcr.io/databasus/charts/databasus \
-n databasus --create-namespace \
-f ingress-values.yaml
Option 5: HTTPRoute (Gateway API)
For clusters using Istio, Envoy Gateway, Cilium, or other Gateway API implementations:
# httproute-values.yaml
route:
enabled: true
hostnames:
- backup.example.com
parentRefs:
- name: my-gateway
namespace: istio-system
helm install databasus oci://ghcr.io/databasus/charts/databasus \
-n databasus --create-namespace \
-f httproute-values.yaml
Ingress Configuration
| Parameter | Description | Default Value |
|---|---|---|
ingress.enabled |
Enable Ingress | false |
ingress.className |
Ingress class | nginx |
ingress.hosts[0].host |
Hostname | databasus.example.com |
ingress.tls |
TLS configuration | [] |
HTTPRoute Configuration
| Parameter | Description | Default Value |
|---|---|---|
route.enabled |
Enable HTTPRoute | false |
route.apiVersion |
Gateway API version | gateway.networking.k8s.io/v1 |
route.hostnames |
Hostnames for the route | ["databasus.example.com"] |
route.parentRefs |
Gateway references | [] |
Health Checks
Both probes target /api/v1/system/version — a dependency-free endpoint — rather than the deep
/api/v1/system/health monitoring endpoint, so an instance that is degraded but still serving
traffic is never restarted or pulled out of the Service.
| Parameter | Description | Default Value |
|---|---|---|
livenessProbe.enabled |
Enable liveness probe | true |
livenessProbe.httpGet.path |
Liveness request path | /api/v1/system/version |
livenessProbe.httpGet.port |
Liveness target port (named or numeric) | http |
livenessProbe.initialDelaySeconds |
Delay before the first liveness probe | 30 |
livenessProbe.periodSeconds |
Liveness probe interval | 10 |
livenessProbe.timeoutSeconds |
Liveness probe timeout | 5 |
livenessProbe.failureThreshold |
Failures before the container restarts | 3 |
readinessProbe.enabled |
Enable readiness probe | true |
readinessProbe.httpGet.path |
Readiness request path | /api/v1/system/version |
readinessProbe.httpGet.port |
Readiness target port (named or numeric) | http |
readinessProbe.initialDelaySeconds |
Delay before the first readiness probe | 10 |
readinessProbe.periodSeconds |
Readiness probe interval | 5 |
readinessProbe.timeoutSeconds |
Readiness probe timeout | 3 |
readinessProbe.failureThreshold |
Failures before the pod leaves endpoints | 3 |
Apart from enabled, every key is rendered into the Kubernetes probe verbatim, so fields not
listed above (successThreshold, terminationGracePeriodSeconds, tcpSocket, …) work too.
To swap the handler, null out the default one — Helm merges maps, and a probe carrying two handlers is rejected by the API server:
livenessProbe:
httpGet: null
exec:
command: ["databasus", "healthcheck"]
Custom Storage Size
# storage-values.yaml
persistence:
size: 50Gi
storageClassName: "fast-ssd"
annotations:
k8up.io/backup: "false"
helm install databasus oci://ghcr.io/databasus/charts/databasus \
-n databasus --create-namespace \
-f storage-values.yaml
Pod Security / Hardening
On a cluster that enforces the restricted Pod Security Standard (or runs scanners like Kyverno, Kubescape or Polaris), tune the following values.
| Parameter | Description | Default Value |
|---|---|---|
serviceAccount.create |
Provision a dedicated ServiceAccount | false |
serviceAccount.name |
Override the ServiceAccount name (else default/fullname) | "" |
serviceAccount.annotations |
Annotations for the created ServiceAccount | {} |
serviceAccount.automountServiceAccountToken |
Mount the SA token into the pod | false |
podSecurityContext |
Pod-level security context | {} |
securityContext |
Container-level security context | {} |
podAnnotations |
Pod annotations (e.g. AppArmor profile) | {} |
extraVolumes / extraVolumeMounts |
Extra volumes/mounts (e.g. emptyDir for read-only rootfs) | [] |
The app does not automount the ServiceAccount token by default
(automountServiceAccountToken: false), which clears the common
AutomountServiceAccountTokenTrueAndDefaultSA finding even on the namespace
default ServiceAccount.
A restricted-PSS values example wiring seccomp, no privilege escalation, AppArmor, a dedicated ServiceAccount and a read-only root filesystem:
# hardened-values.yaml
serviceAccount:
create: true
podAnnotations:
container.apparmor.security.beta.kubernetes.io/databasus: runtime/default
podSecurityContext:
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
seccompProfile:
type: RuntimeDefault
capabilities:
drop:
- ALL
# gosu drops privileges from the root entrypoint; these are required.
add:
- SETUID
- SETGID
# Writable paths required while the root filesystem is read-only.
extraVolumes:
- name: tmp
emptyDir: {}
- name: var-run
emptyDir: {}
extraVolumeMounts:
- name: tmp
mountPath: /tmp
- name: var-run
mountPath: /var/run
Not supported by design:
runAsNonRoot: trueand dropping all capabilities. The entrypoint must start as root to handle PUID/PGID remapping, volumechownand PostgreSQLinitdb, then drops to a non-root user withgosu(which requiresSETUID/SETGID). See the note invalues.yamlnext topodSecurityContext.
Upgrade
helm upgrade databasus oci://ghcr.io/databasus/charts/databasus -n databasus
Uninstall
helm uninstall databasus -n databasus