DEV Community

Cover image for Deploying Metabase on Kubernetes
Sanskriti Harmukh for Vultr

Posted on with Aashish Chaurasiya • Originally published at docs.vultr.com

Deploying Metabase on Kubernetes

Metabase is an open-source BI tool for building charts and dashboards over MySQL, PostgreSQL, MongoDB, Redshift, and more. This guide deploys Metabase on Kubernetes, loads the Sakila sample dataset into MySQL, builds a dashboard, and secures it behind Nginx Ingress with cert-manager TLS.

Prerequisites: a Kubernetes cluster with kubectl/helm configured, a Linux workstation, a reachable MySQL server, and a domain name.


Load the Sakila Sample Database

Sakila models a DVD rental store — films, actors, inventory, rentals.

$ sudo apt install zip -y
$ wget https://downloads.mysql.com/docs/sakila-db.zip
$ unzip sakila-db.zip
Enter fullscreen mode Exit fullscreen mode

Connect to your MySQL server (replace host/port/user):

$ mysql -h <HOST_ENDPOINT> -P <DATABASE_PORT> -u <ADMIN_USER> -p
Enter fullscreen mode Exit fullscreen mode
mysql> CREATE DATABASE sakila;
mysql> SOURCE sakila-db/sakila-schema.sql;
mysql> SOURCE sakila-db/sakila-data.sql;
Enter fullscreen mode Exit fullscreen mode

Deploy Metabase

$ nano metabase.yaml
Enter fullscreen mode Exit fullscreen mode
apiVersion: apps/v1
kind: Deployment
metadata:
  name: metabase
spec:
  selector:
    matchLabels:
      app: metabase
  replicas: 1
  template:
    metadata:
      labels:
        app: metabase
    spec:
      containers:
        - name: metabase
          image: metabase/metabase:latest
          ports:
            - containerPort: 3000
              protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: metabase-svc
spec:
  type: LoadBalancer
  selector:
    app: metabase
  ports:
    - name: http
      port: 8080
      targetPort: 3000
Enter fullscreen mode Exit fullscreen mode

Your cloud provider may need a provider-specific LoadBalancer annotation here (e.g. to set the listener protocol) — check its Kubernetes docs if the default doesn't work.

$ kubectl apply -f metabase.yaml
$ kubectl get deployments
$ kubectl get services
Enter fullscreen mode Exit fullscreen mode

Wait for metabase-svc to get an EXTERNAL-IP (can take a few minutes), then visit http://<external-ip>:8080 to confirm the Metabase welcome page loads.


Connect Metabase to the Database

  1. Let's get started → pick language.
  2. Enter your name, email, company, and a password.
  3. Select your use case.
  4. Database engine: MySQL. Set a display name, then host/port/database/user/password.
  5. Connect Database → set data-sharing preference → FinishTake me to Metabase.

Build a Dashboard

  1. + New → Dashboard, name it, Create.
  2. Add a chart → New SQL query, pick your database.
  3. Run:
SELECT CAST(payment_date AS DATE) AS payment_date, SUM(amount) AS total_revenue
FROM payment
GROUP BY CAST(payment_date AS DATE)
ORDER BY payment_date;
Enter fullscreen mode Exit fullscreen mode
  1. Run Query to preview results as a table.
  2. Visualization → Line → Done to switch to a line chart.
  3. Save, name the chart — it now appears in your dashboard.

Secure with Ingress + TLS

1. Switch the service off a public LoadBalancer:

$ kubectl patch svc metabase-svc -p '{"spec": {"type": "ClusterIP"}}'
$ kubectl get services
Enter fullscreen mode Exit fullscreen mode

2. Install Nginx Ingress:

$ helm install my-ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace
$ kubectl get services -n ingress-nginx
Enter fullscreen mode Exit fullscreen mode

Point your domain's A record at the Ingress controller's external IP.

3. Install cert-manager — check the releases page for the current version:

$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.0/cert-manager.yaml
Enter fullscreen mode Exit fullscreen mode

4. Create an Issuer:

$ nano cert-issuer.yaml
Enter fullscreen mode Exit fullscreen mode
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: tls-certificate-issuer
  namespace: default
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: abc@example.com
    privateKeySecretRef:
      name: letsencrypt-private-key
    solvers:
      - http01:
          ingress:
            class: nginx
Enter fullscreen mode Exit fullscreen mode
$ kubectl apply -f cert-issuer.yaml
Enter fullscreen mode Exit fullscreen mode

5. Create the Ingress. Replace example.com:

$ nano ingress.yaml
Enter fullscreen mode Exit fullscreen mode
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-metabase
  annotations:
    cert-manager.io/issuer: tls-certificate-issuer
spec:
  ingressClassName: nginx
  rules:
  - host: example.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: metabase-svc
            port:
              number: 8080
  tls:
  - hosts:
      - example.com
    secretName: my-webapp-tls
Enter fullscreen mode Exit fullscreen mode
$ kubectl apply -f ingress.yaml
$ kubectl get ingress
Enter fullscreen mode Exit fullscreen mode

You'll briefly see a cm-acme-http-solver-* ingress handling the ACME challenge alongside ingress-metabase — once resolved, both show your controller's public IP.

6. Confirm the certificate is issued:

$ kubectl get certificate
Enter fullscreen mode Exit fullscreen mode

READY: True means you're set — visit https://example.com to reach Metabase over TLS.


Next Steps

Metabase is running on Kubernetes with a live dataset, a saved chart, and TLS via Ingress. From here:

  • Connect additional databases and build cross-source dashboards
  • Set up scheduled email/Slack reports from saved questions
  • Add a HorizontalPodAutoscaler if query load grows beyond a single replica

For the full guide, visit the original article on Vultr Docs.

Top comments (0)