Kubernetes
HeliosLogs runs well on Kubernetes as a single-node StatefulSet. A single node owns its data and control plane on a persistent volume, so this is a replicas: 1 workload — see Scaling & HA before you try to scale it.
The manifest below is self-contained: a namespace, an admin-bootstrap Secret, a Service, and a StatefulSet with two PVCs (data + secrets). It works on any conformant cluster using the default StorageClass.
The manifest
Save as helioslogs.yaml and kubectl apply -f helioslogs.yaml.
apiVersion: v1
kind: Namespace
metadata:
name: helioslogs
---
apiVersion: v1
kind: Secret
metadata:
name: helioslogs-admin
namespace: helioslogs
type: Opaque
---
apiVersion: v1
kind: Service
metadata:
name: helioslogs
namespace: helioslogs
labels:
app: helioslogs
spec:
selector:
app: helioslogs
ports:
- name: http
port: 7300
targetPort: http
- name: syslog-udp
port: 5514
targetPort: syslog-udp
protocol: UDP
- name: syslog-tcp
port: 5514
targetPort: syslog-tcp
protocol: TCP
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: helioslogs
namespace: helioslogs
labels:
app: helioslogs
spec:
serviceName: helioslogs
replicas: 1 # single-node control plane — see Scaling & HA
selector:
matchLabels:
app: helioslogs
template:
metadata:
labels:
app: helioslogs
spec:
securityContext:
# The image runs as the nonroot user 65532. fsGroup makes the mounted PVCs
# group-owned and group-writable so that user can write to them.
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
fsGroup: 65532
seccompProfile:
type: RuntimeDefault
containers:
- name: helioslogs
image: helioslogs/helioslogs:0.2.2 # pin a version (':latest' also exists)
args: ["serve", "--host", "0.0.0.0", "--port", "7300", "--data-dir", "/app/data"]
ports:
- name: http
containerPort: 7300
- name: syslog-udp
containerPort: 5514
protocol: UDP
- name: syslog-tcp
containerPort: 5514
protocol: TCP
envFrom:
- secretRef:
name: helioslogs-admin
volumeMounts:
- name: data
mountPath: /app/data
- name: secret
mountPath: /app/secret
readinessProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 15
periodSeconds: 20
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: "2"
memory: 2Gi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 20Gi # size for your retention — tune this
# storageClassName: fast # omit to use the cluster default
- metadata:
name: secret
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 64Mi # just the encryption + JWT keysApply and access
kubectl apply -f helioslogs.yaml
kubectl -n helioslogs rollout status statefulset/helioslogs
# Reach the UI without an Ingress:
kubectl -n helioslogs port-forward svc/helioslogs 7300:7300Open http://localhost:7300 and log in with the credentials from the Secret (or complete the setup wizard if you removed it). Next: First steps.
Change the admin password
The Secret above ships a placeholder password. Set a real one before exposing the instance, and consider managing the Secret with a sealed-secrets / external-secrets operator rather than committing it to git.
Expose with an Ingress
Point an Ingress at the helioslogs Service on port 7300. Adjust ingressClassName, the host, and TLS to match your cluster:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: helioslogs
namespace: helioslogs
# annotations:
# cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts: ["logs.example.com"]
secretName: helioslogs-tls
rules:
- host: logs.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: helioslogs
port:
number: 7300Terminate TLS at the Ingress and read Security hardening before exposing HeliosLogs publicly.
Receiving syslog
HeliosLogs also listens for raw syslog (UDP + TCP, RFC 5424 / 3164) on port 5514. The manifest publishes that port on the container and Service, but the listener is off by default — enable it under Admin → Data Ingestion → Syslog (or set HELIOS_SYSLOG_PORT). It has no token auth, so restrict it to trusted senders. See Syslog.
In-cluster senders can target helioslogs.helioslogs.svc:5514. Devices outside the cluster need a LoadBalancer or NodePort Service — an Ingress can't carry raw syslog, only HTTP:
apiVersion: v1
kind: Service
metadata:
name: helioslogs-syslog
namespace: helioslogs
spec:
type: LoadBalancer
selector:
app: helioslogs
ports:
- name: syslog-udp
port: 514 # standard syslog port → container's 5514
targetPort: syslog-udp
protocol: UDP
- name: syslog-tcp
port: 514
targetPort: syslog-tcp
protocol: TCPMixed UDP + TCP on a LoadBalancer
Exposing UDP and TCP on a single LoadBalancer needs Kubernetes ≥ 1.26 (or the MixedProtocolLBService feature gate). If your platform's load balancer can't mix protocols, split them into two Services.
Hardening (optional)
For a read-only root filesystem, mount an emptyDir at /tmp and set the flag — all durable writes already go to the two PVCs:
volumeMounts:
- name: tmp
mountPath: /tmp
# ... data and secret mounts ...
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumes:
- name: tmp
emptyDir: {}Scaling & HA
replicas: 1 is deliberate. A single node keeps its control plane and a block cache on its own ReadWriteOnce volume; bumping replicas would give each pod a separate PVC and a separate control plane — not a cluster.
For high availability across nodes, HeliosLogs uses a shared S3-compatible object store (--shared-store) instead of per-pod local state, with the same secret keys mounted on every pod (use a Kubernetes Secret for /app/secret, not a per-pod PVC). See Multi-node & shared store and Secrets & encryption.
Upgrade
Bump the image tag and let the StatefulSet roll the pod (it terminates the old pod before starting the new one, so the ReadWriteOnce volumes hand off cleanly):
kubectl -n helioslogs set image statefulset/helioslogs \
helioslogs=helioslogs/helioslogs:0.2.3
kubectl -n helioslogs rollout status statefulset/helioslogsSee Upgrades & backups for version policy and backing up the data + secret volumes.