Kubernetes

Run the chmonitor dashboard on Kubernetes with either the in-repo Helm chart or the raw kustomize manifests. Both ship the same container image (ghcr.io/duyet/chmonitor), expose port 3000, run as the non-root app user (uid/gid 1001), and wire the same health probes and CLICKHOUSE_* environment.

  • Helm — templating, an optional HorizontalPodAutoscaler, and an Ingress.
  • kustomize — plain YAML you can read, diff, and patch with overlays.

Install with Helm

The chart is vendored in the repo at deploy/helm/chmonitor so it tracks the app it ships.

helm install my-chm ./deploy/helm/chmonitor \
  --set clickhouse.host="https://clickhouse.example.com:8443" \
  --set clickhouse.user="default" \
  --set clickhouse.password="<password>"

Or with a values file:

cat <<EOF > values.yaml
clickhouse:
  host: "https://clickhouse.example.com:8443"
  user: "default"
  password: "<password>"
  maxExecutionTime: "60"
extraEnv:
  - name: CLICKHOUSE_TZ
    value: "UTC"
EOF

helm install my-chm ./deploy/helm/chmonitor -f values.yaml

Upgrade and uninstall:

helm upgrade my-chm ./deploy/helm/chmonitor -f values.yaml
helm uninstall my-chm

Install with kustomize (no Helm)

The raw manifests live at deploy/kubernetes/base. Edit base/configmap.yaml (host/user) and set the password, then:

# Review the rendered output first
kubectl kustomize deploy/kubernetes/base

# Apply
kubectl apply -k deploy/kubernetes/base

Reach the dashboard locally:

kubectl port-forward svc/chmonitor 3000:3000
# open http://localhost:3000

Overlays

Keep environment differences (namespace, replicas, image tag) in an overlay that references the base:

# deploy/kubernetes/overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: monitoring
resources:
  - ../../base
images:
  - name: ghcr.io/duyet/chmonitor
    newTag: v1.2.3
replicas:
  - name: chmonitor
    count: 2
kubectl apply -k deploy/kubernetes/overlays/prod

Health probes

Both install paths configure the same probes:

  • LivenessGET /healthz (static, always 200 while the process runs).
  • ReadinessGET /api/healthz (returns 503 when no configured ClickHouse host is reachable, so traffic is only routed once a host is up).

Secrets

The ClickHouse password is stored in a Kubernetes Secret, never in a ConfigMap. The chart renders one for you (or reuses an existing one via clickhouse.existingSecret); the kustomize secret.yaml ships an empty placeholder you must override. Never commit a real password to Git — create the Secret out of band or use a secrets operator:

kubectl create secret generic chmonitor \
  --from-literal=CLICKHOUSE_PASSWORD='change-me'

For GitOps, prefer External Secrets, SOPS, or Sealed Secrets.

Autoscaling (HPA)

The Helm chart can manage a HorizontalPodAutoscaler. Enable it and the chart drops the static replicaCount in favor of the HPA:

autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

With kustomize, add the HPA as an extra resource in your overlay. The dashboard is stateless, so scaling out is safe; the readiness probe keeps traffic off pods until ClickHouse is reachable.

Validation

Manifests and the chart are linted in CI by .github/workflows/k8s-lint.yml using helm lint and kubeconform. Validate locally:

helm lint ./deploy/helm/chmonitor
helm template release ./deploy/helm/chmonitor | kubeconform -strict -summary
kubectl kustomize deploy/kubernetes/base | kubeconform -strict -summary