Metabase

Query builder and dashboards over the cluster databases, no SQL knowledge required

Metabase provides SQL-first exploration and dashboards over the cluster databases. Where Grafana answers how the system is behaving, Metabase answers what is in the data.

ArgoCD configuration

Excerpt from argocd-apps/values.yaml in the argocd-apps chart, with annotations added for this site:

metabase:
  application: true
  project: cluster-services
  # false
  autoSync: false

Chart values

The full metabase/values.yaml from the service's own chart:

# General
database:
  type: postgres
  name: metabase

### External Secret Configuration ###
refreshInterval: 30s
creationPolicy: Owner

volume:
  accessModes: ReadWriteOnce
  size: 10Gi
  folder: /data/
  storageClass: longhorn-ssd-small

### Metabase Related
image: registry.opi5cluster.co.uk/metabase:v0.60.2
metabasePort: 3000

Manifests & templates

templates/http-route.yaml

Gateway API HTTPRoute exposing the service through the Istio gateway under opi5cluster.co.uk.

Show manifest
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: {{ .Release.Namespace }}-httproute
  namespace: {{ .Release.Namespace }}
  annotations:
    link.argocd.argoproj.io/external-link: "https://{{ .Release.Namespace }}.opi5cluster.co.uk"
spec:
  parentRefs:
    - name: istio-gateway
      namespace: istio
      sectionName: websecure
  hostnames:
    - {{ .Release.Namespace }}.opi5cluster.co.uk
  rules:
    - backendRefs:
        - name: {{ .Release.Namespace }}-service
          port: {{ .Values.metabasePort }}

templates/pvc.yaml

Longhorn-backed PersistentVolumeClaim for persistent data.

Show manifest
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: {{ .Release.Namespace }}-data-pvc
  namespace: {{ .Release.Namespace }}
spec:
  accessModes:
  - {{ .Values.volume.accessModes }}
  resources:
    requests:
      storage: {{ .Values.volume.size }}
  storageClassName: {{ .Values.volume.storageClass }}

templates/rollout.yaml

Argo Rollout workload: container spec, probes, resources and rollout strategy.

Show manifest
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: {{ .Release.Namespace }}-rollout
  namespace: {{ .Release.Namespace }}
spec:
  replicas: 1
  strategy:
    canary:
      steps:
      - setWeight: 25
      - pause: {duration: 30s}
      - setWeight: 50
      - pause: {duration: 45s}
      - setWeight: 100
  selector:
    matchLabels:
      app: {{ .Release.Namespace }}
  template:
    metadata:
      labels:
        app: {{ .Release.Namespace }}
    spec:
      serviceAccountName:  {{ .Release.Namespace }}-service-account
      automountServiceAccountToken: true
      #imagePullSecrets:
      #  - name: {{ .Values.imageSecret }}
      containers:
      - name:  {{ .Release.Namespace }}
        image: {{ .Values.image }}
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: {{ .Values.metabasePort }}
          protocol: TCP
        env:
        - name: MB_DB_TYPE
          value: {{ .Values.database.type }}
        - name: MB_PLUGINS_DIR
          value: './plugins'
        - name: MB_DB_CONNECTION_URI
          valueFrom:
            secretKeyRef:
              name: postgres-url-secret
              key: database_url
        - name: AWS_ACCESS_KEY_ID
          valueFrom:
            secretKeyRef:
              name: {{ .Release.Namespace }}-secret
              key: admin_access_key
        - name: AWS_SECRET_ACCESS_KEY
          valueFrom:
            secretKeyRef:
              name: {{ .Release.Namespace }}-secret
              key: admin_secret_key
        - name: AWS_REGION
          value: eu-west-2
        - name: S3_URL_STYLE
          value: "path"
        - name: S3_ENDPOINT
          valueFrom:
            secretKeyRef:
              name: {{ .Release.Namespace }}-secret
              key: S3_ENDPOINT
        volumeMounts:
        - name: {{ .Release.Namespace }}-data
          mountPath: {{ .Values.volume.folder }}
        resources: {}
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      volumes:
      - name: {{ .Release.Namespace }}-data
        persistentVolumeClaim:
          claimName: {{ .Release.Namespace }}-data-pvc

templates/service-account.yaml

ServiceAccount the workload runs as.

Show manifest
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ .Release.Namespace}}-service-account
  namespace: {{ .Release.Namespace }}

templates/service.yaml

ClusterIP Service fronting the workload.

Show manifest
apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Namespace }}-service
  namespace: {{ .Release.Namespace }}
spec:
  type: ClusterIP
  selector:
    app: {{ .Release.Namespace }}
  ipFamilyPolicy: SingleStack
  ports:
    - name: {{ .Release.Namespace | substr 0 9 }}-http
      protocol: TCP
      port: {{ .Values.metabasePort }}
      targetPort: http

Trade-offs

Decision. A BI tool next to Grafana

Alternative. Trying to do analytics in Grafana

Why. Grafana is a metrics tool; structured data exploration deserves SQL-first UI rather than a metrics query language.

← Back to Data & Streaming · All service groups