Deploy OpenObserve Standalone on Bare-Metal Kubernetes with Traefik + Ceph RBD (PVC)

This post deploys OpenObserve in standalone (single-node / local mode) on a bare-metal Kubernetes cluster using the official openobserve-standalone Helm chart, exposes the UI via Traefik Ingress, and stores all data on a Ceph RBD PVC (dynamic provisioning).

In standalone mode, OpenObserve runs with ZO_LOCAL_MODE=true and writes data to local disk. In Kubernetes, that “disk” should be backed by a PersistentVolumeClaim. This means you do not need Ceph RGW / S3, do not need CloudNativePG, and do not need the HA chart.


This post is based on


Lab context

Kubernetes (bare metal)

  • Nodes:
    • k8s-1.maksonlee.com192.168.0.99
    • k8s-2.maksonlee.com192.168.0.100
    • k8s-3.maksonlee.com192.168.0.101
  • Ingress controller: Traefik (exposed via MetalLB)
  • MetalLB IP (Ingress LB): 192.168.0.98
  • DNS name for OpenObserve:
    • openobserve.maksonlee.com192.168.0.98

Ceph RBD (dynamic PVC provisioning)

  • StorageClass: csi-rbd-sc
  • Recommended: set csi-rbd-sc as the default StorageClass

What you’ll do

  • Add DNS record for openobserve.maksonlee.com
  • Confirm Kubernetes has a working default StorageClass (csi-rbd-sc)
  • Install OpenObserve standalone Helm chart
  • Create a persistent PVC for local-mode storage (Ceph RBD)
  • Expose OpenObserve UI via Traefik Ingress
  • Verify the UI is reachable
  • Ingest a test log with curl
  • Import a dashboard (Linux hostmetrics) to demo charts

Prerequisites

  • DNS

Add one record (LAN DNS or /etc/hosts on clients):

192.168.0.98 openobserve.maksonlee.com
  • Confirm your default StorageClass (Ceph RBD CSI)

OpenObserve standalone uses a PVC for durable local storage. Make sure your cluster can dynamically provision PVCs.

Check StorageClasses:

kubectl get storageclass
kubectl get storageclass -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.annotations.storageclass\.kubernetes\.io/is-default-class}{"\n"}{end}'

  1. Install OpenObserve Standalone (Helm)
  • Add the Helm repo
helm repo add openobserve https://charts.openobserve.ai
helm repo update
helm search repo openobserve

You should see openobserve/openobserve-standalone.

  • Create namespace
kubectl create ns openobserve

  1. Create the values file

We’ll keep credentials and settings in a local values file. Don’t commit this file to Git.

Create values-o2-standalone.yaml:

auth:
  ZO_ROOT_USER_EMAIL: "root@maksonlee.com"
  ZO_ROOT_USER_PASSWORD: "CHANGE_ME_STRONG"
  ZO_ROOT_USER_TOKEN: ""

config:
  # Standalone / local mode
  ZO_LOCAL_MODE: "true"
  # Store data on local disk (backed by a PVC below)
  ZO_LOCAL_MODE_STORAGE: "disk"

# Persist local-mode data to Ceph RBD
persistence:
  enabled: true
  storageClass: "csi-rbd-sc"
  size: 50Gi

service:
  type: ClusterIP

ingress:
  enabled: true
  className: "traefik"
  annotations: {}
  hosts:
    - host: openobserve.maksonlee.com
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls: []

TLS note

  • If Traefik already serves a wildcard certificate for *.maksonlee.com as its default TLS cert, leaving tls: [] is fine.
  • If you require per-Ingress TLS configuration, add a secretName and configure Traefik accordingly.

  1. Install
helm -n openobserve install o2 openobserve/openobserve-standalone \
  -f values-o2-standalone.yaml

  1. Verify

Pods

kubectl -n openobserve get pods -o wide

You want the OpenObserve pod in Running.

PVC

kubectl -n openobserve get pvc
kubectl -n openobserve describe pvc

You want PVC status Bound.

Ingress

kubectl -n openobserve get ingress
kubectl -n openobserve describe ingress

You should see the host openobserve.maksonlee.com.

UI

Open https://openobserve.maksonlee.com/web/,

Log in with:

  • Email: root@maksonlee.com
  • Password: CHANGE_ME_STRONG

It’s normal to see “No Data Ingested” until you send logs/metrics.

Did this guide save you time?

Support this site

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top